Here’s a myth that won’t die: your Bounded Contexts should map 1 on 1 to your business domains. It sounds clean and logical, but it’s wrong.
The myth persists because:
- Sometimes it’s true,
- it could be true in ideal but imaginary circumstances,
- it absolves you from doing deep modelling and critical thinking about your organisation and software systems.
Be careful with software design rules that promise a simple one-size-fits all solution to a complex problem. I’ll demonstrate that there are many valid reasons not to map your domains 1 on 1 to your Bounded Contexts. It’s unrealistic in non-trivial systems. And it ignores the benefits of Bounded Contexts as a software design tool for gaining control and understanding of our domains and systems.
Quick Recap
In Domain-Driven Design (DDD), a domain is an area of activity, knowledge, and expertise, that your organisation is active in. For example, you could be in finance, with lots of possible subdomains like trading, consumer banking, loans, sales, customer retention, down to accounting and HR.
A Bounded Context (BC) is a linguistic and model boundary. Inside this boundary, we use a single unambiguous language, and a single consistent model to talk and reason about the problem.
In the code, you should be able to look at all the terms and relationships and behaviours, and be able to understand it as a whole. Every term is clearly defined and understood, and adding or removing terms and concepts is very deliberate. (Ideally but not always, the code for a single BC is contained in a single deployable unit, but that is out of scope here).
The domains are how the business “see itself”. The org chart will often reflect this, and structure the company to reflect it. The Accounting department manages all the people and resources to deal with the Accounting domain.
Software disrupted that. Suddenly you have people who are skilled in software engineering disciplines as opposed to the company’s domains. They are organised in a separate engineering department, but they build for the other departments. In other words, the company’s org chart is designed for people, not for software engineering. (See literally everything ever written about Conway’s Law, and my own Conway’s Law Doesn’t Apply to Rigid Designs).
In DDD, we reason like this: The engineers need to build, maintain, and evolve secure and performant systems that serve the company. To do that, the engineers need an understanding of the domains and of the software systems. To achieve that, we leave the domains as the organisation sees them, and we draw our own Bounded Contexts to serve our need for understanding. The Bounded Contexts exist primarily for the engineers, and for the engineers’ communication with domain experts and other business functions.
Ideally, we look at the organisations’ carving up of domains, and mimic it in our own drawing of Bounded Contexts. In fact, many DDD advocates have been claiming that this is the only way. There are so many counterexamples that I don’t understand why people advocate it. The organisation’s perception of domains is never a design choice, so having our design mimic that structure can be harmful.
A Single Domain Across Multiple BCs
Here’s a nice example. A online retailer considers Pricing to be one of their Core Domains. They have two software systems. One does webscraping to find competitor’s prices for the same products, and does machine learning to react to inputs such as supply and demand. The second system allows employees to price items manually, set up discounts and campaigns, do strategic pricing (for example to position a product line as higher quality against another one), and psychological pricing (like automatically reducing €10 to €9.99). The second system also has rules to pick the final price between the two systems, and takes into account minimum margins.
Why two systems? The programming language, tech stack, and engineering skills used for the second system, are very typical of business applications: databases, user interfaces, a domain model… The first system requires machine learning skills, which is a different specialisation. On top of that, one system was built first, and the need for the second emerged later. So the need for different skills and technology, as well as historic reasons, are the causes of this split. I think these three are valid reasons for choosing Bounded Contexts on their own. The engineers choose their BCs to fit their needs.
I feel there could be at least four Bounded Contexts.
I’d separate the webscraping and machine learning into two BCs. They are very different technical concerns. More importantly, from the DDD perspective, they have very different domain languages and modelling needs, and mixing them causes more confusion than benefits. From the architectural perspective, we’d see that the machine learning system has at least three inputs: the webscraper, the company’s own sales data, and the supply data. It’s not very flexible in the current system that one of these inputs is part of its own consumer. Separating them would make it easier to add more inputs in the future.
The Manual Pricing context stays, but I’d extract the rule based part. The reasoning is similar: The Pricing Rules context takes the Manual Pricing, the Machine Learning, and the supply data as inputs.
So, one domain (Pricing) from the organisation’s perspective, four languages and models and therefore four Bounded Contexts to fit the engineers’ need.
Are these actually four domains? Arguably, but the organisation doesn’t see it that way. And in any case, the current system has 2 BCs for four areas, and changing it to my proposed design with 4 BCs might not be worth the effort. In that case we’d have 2 Bounded Contexts for 4 domains, which again could be a valid choice.
There’s a more radical example of a company where 1 domain is not just split, but repeated across 20(!) Bounded Contexts. You can find it in the book Design and Reality by Rebecca Wirfs-Brock and me, or read it here for free (but we appreciate your support for our writing!)
Here are some more examples that show valid reasons for avoiding a 1 on 1 mapping.
Startups
A startup with no pre-existing software would theoretically be the easiest place to do a 1 on 1 mapping. You look at the domains the startup needs, draw the Bounded Contexts accordingly, and start building.
Startups don’t have the luxury of clean boundaries. You’re figuring out what business you’re in while building the software. So you’ll jam User Management into your Payment System because that’s where the engineers had time. You’ll choose BCs prematurely because you didn’t understand them yet. You’ll split order processing across three services because each was built during a different pivot. Everything is hacks and duct tape. This isn’t about software design, it’s survival. You’re usually starved for people, skills, time, and money.
You want to find the right balance between making good software design choices, and doing literally anything that gets the company to a point where it gets funding or revenue. Over time, needs change, resources become available, and insights grow. You can now rethink the design and draw new boundaries — presuming you can keep the code flexible enough to change it.
Experiments
There is a use of Bounded Contexts that Eric Evans (who coined the concept of Bounded Contexts) talks about a lot. If you isolate a small area into a BC, you can use it to experiment. You can try business ideas or technical ideas, learn from them without affecting the existing systems, and throw them out.
Say, within our Pricing domain, we have an isolated BC for rule-based pricing, that only has a small well-defined interface with other parts. We can leave it as is, and make a new ruled-based pricing context. It could be designed differently, more efficiently, use different technology like a rules engine, or have a different model and language. We could A/B test it on a small part of our business, using a simple switch or a feature flag to send requests to the existing BC or the experimental one.
Then, if it works, migrate. If not, delete it. No risk to your existing systems.
Older Companies
Older companies have software systems dating back years and decades. A legacy system survives because it brings more value than it costs to replace it. There’s no way you can redesign the whole thing to fit our ideal 1 on 1 mapping.
- The redesign is hard because a lot of the knowledge about the system has disappeared. You can’t redesign without that knowledge. (DDD and general software design recognise this. We have patterns to deal with isolating the systems that are ill-understood, from the newer ones.)
- “Any component that is easy to replace will eventually be replaced by a component that’s hard to replace.” (I couldn’t find a source for this, please message me if you have it.) In other words, a system that’s old enough will be highly coupled, making it harder to isolate BCs.
Deciding what to improve, replace, or keep, is a design choice that you analyse for costs & benefits.
Mergers and Acquisitions
Here’s where the 1 on 1 myth completely breaks down: mergers and acquisitions. Say our retailer from the earlier example buys a nearly identical competitor. All of a sudden, we have at least two Bounded Contexts for Pricing, two Product Catalogs, two Accounting systems, two everything. The business sees one domain each; engineering sees a mess of overlapping contexts that somehow need to work together.
This situation might be cheaper and more effective than trying to unify everything! More realistically, we will want to merge some and leave others.
Accounting is a very mature domain, and I imagine that merging two companies is bread and butter for them. But maybe the competitor has a single Bounded Context that handles the Product Catalog as well as the Pricing. Perhaps one company is better at webscraping, and the other is better at machine learning. Deciding what to keep or migrate away from, what to combine, what to split, what the new boundaries should be: all of these are a mix of business and software design choices. You’ll end up with a fascinating Context Map, showing a patchwork of Bounded Contexts that overlap with multiple domains, and domains that overlap with multiple Bounded Contexts. And the best design is the one that serves business needs and engineering needs.
Conclusions
Stop trying to make your software mirror your org chart. Bounded Contexts are design tools, not bureaucracy.
Bounded Contexts boundaries should be deliberate design choices. The engineers need to make it easy to their job, so they can serve the business needs in the short and long term. As a linguistic and model boundary, Bounded Contexts are a great tool to achieve that. If we let ourselves be constrained by the organisation’s perception of its domains, we are not making design decisions. Mimicking reality (or some perception of it) is not our goal (see Design and Reality). It merely satisfies a need for simple design rules, or for pretty system diagrams. (“If drawing of your system looks pretty, the drawing is a lie”.)
Isolating a language and a model is incredibly productive. A right-sized Bounded Context allows us to isolate domain knowledge and reason about it with a model and language. They make it easier to understand a system and therefore to evolve it. We can isolate chunks of a domain for all kinds of reasons:
- access to domain experts,
- technical expertise,
- security or performance,
- avoiding leaky abstractions or pollution from legacy components,
- business value,
- fast experimentation,
- architectural needs,
- …
In short, draw your Bounded Contexts pragmatically to get the advantage.