Is it time to modify boundaries of your bounded contexts?
Your bounded contexts aren't set in stone. As your system evolves, their boundaries may stop serving you well. Discover six symptoms that indicate it's time to revisit them - and learn why not every symptom means you should make a change.
Many people think that good design decisions make software architecture last for years. In reality, quite the opposite is true - when you continue working on a system and adding new features, its architecture should evolve as well. New challenges emerge that weren't present when the original design was created. Some assumptions turn out to be incorrect, and you learn more about the domain and your users' needs. Sometimes, one of these discoveries (or a combination of several) should lead to an architectural change.
And this is where good design decisions really shine - they make it easier to evolve the architecture. Their purpose is not to keep the system within the same boundaries it had years or decades ago, when the context and reality were different.
Today I'll share a few ideas on how to recognize situations in which the boundaries of your bounded contexts should be revisited.
Why should bounded contexts evolve?
A system is a solution to a set of problems, and its initial implementation establishes a particular set of bounded contexts. But what happens when a new problem emerges? Its solution doesn't always fit within the existing bounded contexts.
What if a problem becomes more complicated? The initial boundaries may become too narrow to accommodate the growing complexity.
And what if a solution becomes simpler, perhaps thanks to a newly discovered third-party service or a new technology? It may turn out that an existing bounded context is no longer needed.
Only when you stop adding new functionality might it be safe to assume that your bounded contexts will remain in their current state. Until then, it's worth observing the system, the work already completed, and the work planned for the future. These observations can help you identify the right moment to revisit the boundaries and decide whether a change is necessary.
How do you recognize that a discussion is needed?
Below, you'll find a list of observations that should trigger a discussion about changing the system's architecture. In this context, we're specifically talking about changing boundaries. That might mean merging bounded contexts, splitting them, or establishing entirely new boundaries.
Before we start, keep a few things in mind:
- These observations are triggers for discussion, not rules of thumb that dictate when you must change your bounded contexts.
- The more symptoms you observe, the stronger the case for reconsidering the current boundaries.
- A single observation doesn't mean you should wait for more evidence. Even one symptom can be a good starting point for a discussion.
One disclaimer before we begin: I'll describe these symptoms using examples involving two bounded contexts, but the same advice applies to any subset of bounded contexts you're considering.
Chatty bounded contexts
What's the symptom?
Two bounded contexts frequently exchange information. For example, 80% of the problems solved in BC1 lead to communication with BC2.

Why does it matter?
This may indicate that domain knowledge is leaking across boundaries and that the separation exists only on paper. Perhaps, in our pursuit of finer-grained contexts, we split something that should have remained together. Now we're paying the price through an oversized API and additional maintenance overhead.
Why might it be OK?
Imagine a sales context in which most operations should end with sending an email through a notification context. There will be many integrations between the two, but that doesn't necessarily mean the boundaries are wrong:
- Sending a notification isn't a crucial part of any sales process. A failure in the notification context doesn't cause a sales operation to be canceled.
- The notification context may expose a well-designed API that isn't coupled to the sales context.

Scattered responsibility
What's the symptom?
There are multiple integration points between two bounded contexts, and communication occurs throughout a complex, automated business scenario. The process consists of multiple steps, with interactions between the contexts taking place along the way.

Why does it matter?
If we have a single business scenario, there's a chance that we're solving a single business problem. If implementing that solution requires jumping between multiple contexts, it may indicate that responsibility for the overall consistency of the process is scattered across boundaries.
Why might it be OK?
Some business scenarios require information to be propagated between contexts as the process progresses.
Let's use the sales context as an example again. Consider this simplified process:
- We initiate the sale of a place on a training course in BC1.
- We reserve that place in BC2.
- We finalize the sale in BC1, but the operation fails. We have a built-in mechanism that retries the operation twice, after one minute and then after five minutes.
- Meanwhile, BC1 tracks sales that are still in progress. If an offer isn't closed within two minutes, BC1 triggers the release of the reserved place in BC2.
- To prevent the reservation from being released while retries are still in progress, we renew the booking in BC2 whenever the finalization operation fails.
- Once the retries are exhausted or the finalization succeeds, we either release the place or confirm the booking in BC2.
In this scenario, we can still decide to keep the sales context (which handles offers, orders, price calculations, and related responsibilities) separate from the reservation and booking context.

The important question isn't simply how many interactions occur between contexts. It's whether the distribution of responsibilities and the resulting complexity justify keeping them separate.
Bounded contexts often change together
What's the symptom?
A new feature or modification to existing functionality requires changes in several bounded contexts. After several such changes, we notice that two contexts are almost always modified together.

Why does it matter?
This may be evidence of coupling. If almost every change spans multiple bounded contexts, their responsibilities may be too finely divided. The current boundaries may add unnecessary complexity without providing enough value in return.
Why might it be OK?
Imagine two contexts: one in which the sales team manages scheduled training sessions, and another in which potential clients discover available sessions. The first is the scheduled trainings context; the second is the training catalogue. This is an example of a CQRS implementation.
When a new training session is scheduled, the operation happens in the scheduled trainings context, and the session must subsequently become visible in the training catalogue. The same applies to rescheduling, canceling, moving sessions, and similar operations. When data is added, removed, or renamed, the changes may need to be reflected in both contexts.
Even so, keeping them separate may be justified by scalability, performance, and throughput requirements.

Only part of a bounded context changes
What's the symptom?
A new feature or modification to existing functionality affects only part of a bounded context. After several changes, we notice that almost all modifications happen in the same area, while another part of the code remains untouched.

Why does it matter?
This may indicate that one part of the bounded context is becoming more complex than the rest. We're adding new details, rules, and behaviors, and the resulting concentration of responsibility may be significant enough to justify splitting the context.
Why might it be OK?
There may be a situation in which we initially focus on delivering one aggregate and move on to the next only after the first one is well established.
In a sales context, for example, we may have both an offer and an order. We could initially focus on ensuring that orders are handled correctly and all relevant cases are supported. After all, there's no deal without an order.
Once that part is settled, we can turn our attention to offers. We might introduce automatic cancellation or renewal based on specific conditions, then support different ways of creating offers to make them more personalized.

The fact that one area receives more changes than another doesn't automatically mean the bounded context should be split. What matters is whether the growing complexity reveals a meaningful boundary between distinct responsibilities.
Too much information, too many features, or too many problems being solved
What's the symptom?
More and more work takes place within a single bounded context. We can observe this by looking at past work in the version control system or at future demand in the backlog. Additionally, explaining the context's responsibility becomes increasingly difficult. We find ourselves saying "and it also does..." more often than we'd like.
Why does it matter?
Perhaps the context has grown too large and should be split. Over time, features become more complex, and the domain model accumulates more information and behavior. Because this growth happens incrementally, we may be misled into thinking that all the new details still belong in the same context. If we notice the problem too late, we risk ending up with a miniature big ball of mud inside the system.
Why might it be OK?
Sometimes, we deliberately invest heavily in one context because we see an opportunity worth pursuing.
Imagine that our pricing context initially considers only discount codes. We then discover that training prices can depend on much more than that. Discounts might be specific to an individual or a company, apply during a particular period or on a specific day of the year, or be available only for a selected subset of training sessions. The growing number of rules doesn't necessarily mean we need another bounded context. These capabilities may all belong to the pricing domain. The question is whether the new responsibilities still form a coherent whole.
A bounded context is too small
What's the symptom?
It's difficult to explain the context's responsibility, not because it contains too many responsibilities, but because we always treat it as part of something bigger. Explaining what it does requires referring to the larger problem we're trying to solve.
Why does it matter?
Sometimes, we assume complexity will grow over time, but it never does. In other cases, we anticipate needing more functionality to solve a problem, only to discover that our assumptions were incorrect.
In such situations, we should consider whether the bounded context would be better placed inside another one. It's worth remembering that bounded contexts give us boundaries and a consistent language, but they also introduce costs in the form of communication and integration that we need to maintain. Sometimes, that overhead outweighs the benefits of keeping the contexts separate.
Why might it be OK?
Let's return to the discount context. If its only responsibility is to apply discount codes to prices, we might reasonably ask why this functionality isn't part of the sales context.
However, monetary calculations are notoriously tricky. Keeping pricing and discount logic separate may make the associated risks easier to manage, even if we don't expect to add any further capabilities in the foreseeable future.
A small context isn't necessarily a problem. The question is whether its independence provides enough value to justify the additional boundary.
How often should we review bounded context boundaries?
In an ideal world, the answer would be continuously. But let's be pragmatic.
If the system is in maintenance mode, meaning we're fixing bugs and providing required updates, and new functionality is delivered only occasionally, an annual review should be more than enough.
If new features are being added continuously, the frequency of reviews should depend partly on the number of teams working on the system. For a single team, I'd recommend reviewing bounded contexts every six months. If multiple teams are involved, I'd suggest doing so quarterly.
Why the difference?
It comes down to the number of changes that can happen within a given period. The more changes we make, the more we learn about the domain and the more problems we need to solve. This evolving understanding of the domain and its complexity is what we use to establish bounded contexts in the first place. And what we should use to validate them later.
Of course, regardless of how frequently you schedule these reviews, you should always encourage ad hoc discussions whenever you or someone else notices symptoms that, in your opinion, warrant reconsidering the boundaries. Even if the discussion ends with the decision to keep things as they are, you'll have a better understanding of the current structure of the system, its bounded contexts, and the rationale behind their boundaries.
Summary
Bounded contexts are not permanent architectural decisions. They're boundaries based on our current understanding of the domain, its complexity, and the problems we're trying to solve.
As the system evolves, that understanding changes. New features, changing responsibilities, growing complexity, and new technical opportunities can all reveal that the original boundaries no longer serve us as well as they once did.
Chatty communication, scattered responsibilities, contexts that change together, unevenly distributed changes, growing complexity, and contexts that are too small are all signals worth investigating. None of them automatically means that a boundary must change. Each is an opportunity to ask whether the current design still serves the business and the team.
Want to go deeper into Bounded Contexts, their boundaries, and their role in software architecture? Find more articles in my series on Strategic Domain-Driven Design: Bounded Contexts.
Comments ()