Once we understand Bounded Context, we let go of the desire to merge models into one. We accept that the same word can have different meanings depending on context, and that several consistent models can be better than one giant model.
But design does not end just because we split Bounded Contexts. In a real system, contexts do not exist alone. A subscription context must connect to a payment context, connect to an entitlement context, and tell a notification context what happened.
The problem is connection. If we do not split boundaries, models mix together. If we only split boundaries and do not design relationships, the system becomes disconnected.
A Context Map is a tool for balancing these two concerns.
A system is made of relationships between models
Consider a subscription service. At first, it may seem enough to model Subscription well. But as the real service grows, several contexts appear.
Member Context
Subscription Context
Payment Context
Entitlement Context
Notification Context
Settlement Context
Each context has its own language.
In the member context, what matters may be the user’s registration status, authentication information, consent to terms, and whether the account is locked. In the subscription context, what matters is the plan, renewal date, expiration date, and whether cancellation is allowed. The payment context handles approvals, cancellations, failures, refunds, and transaction identifiers. The entitlement context determines which features a user can access.
They solve different problems. Therefore their models must also differ. But they cannot be completely independent.
When payment succeeds, the subscription must be renewed. When a subscription expires, entitlements must be revoked. When a subscription is canceled, a notification must be sent. The settlement context must calculate revenue based on payment and refund information.
In other words, Bounded Contexts are not independent islands. They must keep their own boundaries while still forming relationships with each other.
Context Map reveals relationships
A Context Map is a way to explicitly express relationships between contexts. The goal is not simply to draw boxes and arrows. What matters is understanding the nature of each relationship.
Suppose there is a subscription context and a payment context. The subscription context needs to know the payment result. But if the subscription context directly adopts the internal model of the payment system, problems appear.
The payment context may use language like this:
Transaction
Approval
Cancel
PartialCancel
MerchantUid
PgResponseCode
The subscription context may use language like this:
SubscriptionRenewed
RenewalFailed
GracePeriodStarted
SubscriptionExpired
Even when two contexts look at the same event, they express it in different languages. Context Map does not ignore this difference. Instead, it asks, “How should these two be connected?”
Customer/Supplier: When one side depends on the other
One common relationship is Customer/Supplier. This is when one context needs the result of another context.
The subscription context needs the result of the payment context. In this case, the subscription context can be seen as the customer, and the payment context as the supplier. Subscription policy changes depending on payment results.
What matters in this relationship is negotiating requirements. Depending on which events the payment context provides, which APIs it exposes, and how it expresses failure codes, the model of the subscription context is affected.
In a good Customer/Supplier relationship, the supplier context understands the needs of the customer context to some degree. In a poor relationship, the supplier context only pushes its own internal structure, and the customer context is forced to fit that model.
Conformist: When we have no choice but to follow
Sometimes we cannot change the other model. There are systems we do not control, such as an external payment gateway, a legacy ERP, or another organization’s common platform. In this case, we may have to follow the other model as it is. This is a Conformist relationship.
Conformist is not always a bad choice. It can be a practical way to reduce cost. If the external system is stable enough and does not greatly damage our domain complexity, following it may be better.
But we must be careful in the Core Domain. If the core domain is bent to fit an external model, long-term cost grows. It is especially dangerous when the terminology of the external system starts replacing the language of our domain.
subscription.approveTransaction(pgResponse);
If this code starts appearing inside the subscription domain, the subscription model may be getting pulled by the language of the payment model.
Shared Kernel: When part of the model is shared
Sometimes two contexts share part of a model. This is called a Shared Kernel.
For example, there may be Value Objects such as Money, Currency, and EmailAddress that several contexts use in common. Or the member and authentication contexts may share some rules about account identifiers.
Shared Kernel can reduce duplication and increase consistency. But sharing always creates cost. When a shared model changes, several contexts are affected together. Therefore Shared Kernel should be limited to small and stable areas.
When we want to turn everything into a common module, we should be suspicious. Commonization can simplify design, but it can also force different models together.
Separate Ways: Not connecting is also design
Not every context needs to be connected. Sometimes going separately is the best choice. This can be seen as Separate Ways.
For example, if an internal operational statistics system does not need to be deeply connected to the subscription context, it can copy data in batches and analyze it independently. If real-time consistency is not needed, there is no reason to create a complex API dependency.
Connection is always a cost. Data synchronization, failure propagation, version management, and contract management follow. So instead of only asking, “How should we connect?” we should also ask, “Do we really need to connect?”
The point that leads to Anti-Corruption Layer
When drawing a Context Map, particularly dangerous relationships become visible. This happens when an external system or legacy system strongly affects our Core Domain. What we need here is an Anti-Corruption Layer.
Suppose we use the response model of a payment gateway directly in the subscription domain.
if (pgResponse.getResultCode().equals("0000")) {
subscription.setStatus(ACTIVE);
}
This code can work technically. But the subscription domain now directly depends on the payment gateway’s code system. Over time, the gateway’s language corrodes the language of the subscription domain.
Context Map helps us discover this risk. With some contexts, we can cooperate. With some, we must conform. From some contexts, we must protect our model.
Context Map is a tool for conversation, not a document
Context Map is not for making a beautiful diagram. It is a conversation tool that helps the team clearly understand relationships.
It is used to ask questions such as:
What data do these contexts exchange?
Who depends on whose model?
Which models are safe to share?
Which relationships should be protected by an ACL?
Which connections can be removed?
How do changes in external systems affect our Core Domain?
If we do not answer these questions, relationships between contexts implicitly hide inside code. API DTOs become domain objects, external system status codes become internal policies, and common modules become giant dependencies that every team fears.
Closing
Bounded Context creates boundaries for models. Context Map shows what relationships those boundaries have.
Splitting boundaries is not enough. Different models inevitably meet. What matters is designing that meeting consciously.
Some contexts must cooperate. Some contexts must be followed. Some contexts can share parts of a model. From some contexts, we must protect our model. And with some contexts, choosing not to connect may be better.
Context Map lets us see the system not as code structure, but as relationships between models. With that perspective, DDD goes beyond making one model well and becomes a way for many models to live together inside a large system.