2.5 Context mapping
Context mapping is all about avoiding entanglement: Creating greater efficiency with smaller, more capable components, better APIs, purpose-built data sets, and easily reasoned about services.
Our definition of ready for beginning this activity is:
Before starting
Context mapping builds a visual map of how your bounded contexts depend upon and communicate with each other. Done well, it establishes clear separation of concerns, reduces inter-service chatter, keeps APIs small, and lets you scale components independently. Done poorly, it muddles the architecture and erases many of the benefits of domain driven design.
Guide to context mapping
Context mapping is largely about building a visual map of your bounded contexts. The map will clearly indicate how each context depends upon and communicates with other contexts. While this is principally an engineering activity, you’ll also need to have comprehensive business domain knowledge.
Accordingly, you’ll need access to your business domain experts so you can reason about the flow of business data. While modeling your contexts, you may need clarification on data residency, purpose, or business process details. You’ll also need technical knowledge, to help make decisions about how data will be expressed between contexts. You’ll make decisions about data ownership, sources of truth, and methods of communication.
The outcome of context mapping leads us toward an efficient design. Done well, it will greatly simplify implementation downstream. For this activity, our goals and their respective impact are:
Inputs
- Access to contextually relevant business information and business domain experts.
- Event maps expressing the business processes in the current increment.
- Domains and their definitions for each business domain in the current increment.
- At least a partial list of your bounded contexts, along with their entities and aggregate roots.
Process
Your context map will evolve over time. It’s perfectly natural to create new bounded contexts as new capabilities are added to your system. Likewise, existing bounded contexts might break into smaller ones as good reasons to separate concerns materialize. Start with your current increment, the scope of functionality you are currently working on delivering. Think in terms of “good enough” to get the job done — sometimes, perfection can be the enemy of progress.
Prepare
Keep in mind this is principally an engineering activity. While in most of our activities leading up to this point, the whole team has been present, that might not be entirely necessary this time. Even so, be sure that you have access to your whole team. Questions will arise, and you want to be able to answer them.
If you’ve already started to split your project across teams, you’ll want to have involvement from each team. You’ll be talking about who owns specific data, how the components developed by each team communicate, and what is being communicated.
At a minimum you should have your technical team lead, architect, and some of your senior engineering team members participate in the activity. Having business experts or product owners present is never a bad thing.
Execute
You’ll want to start from your domain definitions and list of bounded contexts. Most often using a diagramming tool like Miro works quite well, as it enables everyone to collaboratively develop the context map.
Step 1: Identify interactions between contexts
The first step is to identify which bounded contexts need to integrate with other bounded contexts. This could be as simple as sending a small bit of information on-demand from one component to another; or, it could be much more elaborate.
Integrations are modeled by drawing a connecting line between two separate bounded contexts. In domain driven design, that integration between the two different bounded contexts is called context mapping. It represents any kind of interaction between the contexts — sharing of information, functionality, or data. The line indicates that the two contexts are mapped in some way. It also means there will be some inter-team dynamic between the two, as well as some integration.
Step 2: Explore context overlap
We want to identify whether there is significant overlap between two different contexts. In domain driven design terms, this is considered “partnership.” Visually, it represents such a tight integration that it’s actually a functional overlap.
In this situation, a partnership exists between two contexts (and potentially two different teams) — however, this is largely considered an anti-pattern. It indicates significant entanglement between two different business contexts. Because of this entanglement, the combined solution becomes more elaborate; both contexts (and, if large enough, then both teams) will succeed or fail together.
Maintaining a partnership can be difficult over time. Because of this, it’s best to limit partnerships as much as possible. Ideally, this is done by subdividing contexts into smaller components, but you may choose to do it by creating a limited partnership. You’ll need to decide which way to go:
- Decompose. Would it be better to break the overlapping area of responsibility into a new context? If so, creating three (or more) bounded contexts would likely be a cleaner, more maintainable solution in the long run.
- Limited partnership. Is there significant value realized by maintaining the partnership? If so, it’s critical to be certain the cost of the partnership is outweighed by other benefits. Create a limited partnership, keeping the scope of overlap as small as possible. Consider specifying that the partnership is limited in time as well as scope.
Model the partnership accordingly. If you choose to proceed with a partnership contract between the two contexts, model it with a thick line. The thick line is intended to indicate an extremely tight linkage between the contexts. On the other hand, if your approach will be further decomposition, then simply proceed by introducing new bounded contexts and model them as usual.
There is also the concept of a “shared kernel” in domain driven design, where two (or more) teams share a small but common model. This is visually represented by showing two overlapping bounded contexts. This approach is very strongly discouraged, and considered a potentially worse anti-pattern. It creates deep entanglement and, in general, throws away all the benefits we are seeking to create.
Step 3: Refine context mapping
Continue exploring how your different bounded contexts will integrate, adding fidelity to your context map as you go. Specifically, you’ll want to add annotations that provide greater detail about the nature of each integration. The annotations define the following attributes of each integration:
- Customer-supplier. Describes a relationship between two bounded contexts where the supplier is an upstream context and the customer is a downstream context. The supplier, denoted with a “U” in the diagram, holds sway in the relationship; it provides information to the customer context, which is denoted with a “D.” The supplier is effectively a provider of information, determining how and when information is provided.
- Anticorruption layer. An anticorruption layer (or “ACL”) is a defensive strategy. The goal of the ACL is to introduce a layer that translates external data into the context’s internal ubiquitous language. We use an ACL when a downstream consumer creates a translation layer between its internal ubiquitous language and the outside world (the upstream context). Effectively, this maps external communications to the context’s own APIs. This is a very common pattern you’ll use often — you want to avoid introducing external language into your context. Instead, keep contexts completely isolated from external concepts.
- Open host service. An open host service (or “OHS”) defines an interface that exposes access to your context’s services. The interface is “open” so that anyone that needs to integrate with the bounded context can do so easily. Services are well documented and easily accessed.
Work through each of your event maps and the underlying use cases to discover where required interfaces exist. Keep in mind your goals to create purpose-built components that specialize in doing one thing well. Also remember that there can only be one source of truth for data, so that means one bounded context will become the owner of specific business data. Other contexts will use interfaces, anticorruption layers, and other context mapping techniques to get at that information.
There are other kinds of interfaces you can add to your design. In practice, what’s covered here is more than adequate. For a full exploration of other types and techniques (such as the published language interface), Domain-Driven Design Distilled by Vaughn Vernon is a concise reference.1
Step 4: Buy and leverage decisions
At some point, you will want to think hard about what you want to build, what you want to buy, and what you want to leverage. Building something is your most expensive option, so building everything tends to be undesirable — at least, if you can use something that already exists or just buy it off the shelf.
Your bounded contexts should have clearly defined responsibilities. That presents an ideal opportunity to consider buy and leverage decisions. Doing so now, relatively early in the delivery lifecycle, has the greatest long-term impact.
Take some time now to investigate buy and leverage options. Find out if there are commercial, off-the-shelf software that you can buy, or existing components across the organization that you could reuse.
What to avoid
Context mapping can get tricky. You’ll be dealing with a lot of tough questions about where data should live, who owns it, what it means — not to mention, how different contexts will talk about that data. A few tips to help get through the harder conversations:
- Don’t over design. One of the great things about domain driven design is that it decomposes your problem into smaller problems. That lets you reason about a specific solution independent of solving every problem up front. Your context map (and your bounded contexts) are going to change and evolve over time. This is natural. It’s perfectly OK to come back later and make improvements as new discoveries create more clarity.
- Don’t limit yourself with synchronous thinking. The world is asynchronous, and having that understanding makes it easier to think about business problems. Decomposition is often hard to grasp if you think about problems synchronously. But that’s a path toward monolithic thinking — instead, decouple components and realize it’s routine for processes to continue without having all the information.
- Not being strict about contextual boundaries. Watch carefully for changes in language, usage and meaning. Remember the definition of a context: “The setting in which a word or a statement appears that determines its meaning.” It’s an excellent definition and one that scales very well. Use it as your litmus test to determine whether you’ve crossed a boundary into another context.
Alberto Brandolini’s Strategic Domain Driven Design with Context Mapping is an excellent companion article, especially because he uses banking (our model use case, more or less) as the problem space.2
Outputs
- Context map. A visual map of your bounded contexts that clearly indicates how each context depends upon and communicates with other contexts.
- Buy and leverage decisions. Where appropriate, decisions to buy or leverage components (rather than build them from scratch).
In chapter 2.4 Domain modeling we created our detailed domain descriptions, and documented the results using a domain detail template. You can now add context map references directly to your domain detail wiki page.
At the same time, take a few minutes to go back over your domain detail page. Make sure everything is up-to-date. Quite often during context mapping, we move a few boundaries around. That may have implications with our domain definitions, such as changing their responsibilities. This is also a good time to refresh your event maps.
In the upcoming chapters we’ll start to go deep on shaping future state architecture. If you haven’t defined your target state architecture and architecture foundation, you’ll probably want to continue with chapter 2.6 Target state architecture. You can also begin work on chapter 2.9 Functional architecture, as well as 3.1 Value mapping.
Templates
Next activity
Footnotes
-
Vaughn Vernon, Domain-Driven Design Distilled, Addison-Wesley Professional, 2016. ISBN-13 978-0134434421. ↩
-
Alberto Brandolini, Strategic Domain Driven Design with Context Mapping, InfoQ, Nov. 25 2009. ↩