Introduction
When modeling complex systems using Domain-Driven Design (DDD), one of the most common dilemmas architects and engineers face is:
“If two bounded contexts use the same concept — like a
Customer
— should they share a common model or have separate ones?”
Take, for example, Sales and Support systems within an organization. Both deal with a Customer
, but they use that concept differently. So what’s the right way to model this scenario in line with DDD principles?
original context map image courtesy: https://martinfowler.com/bliki/BoundedContext.html
Let’s explore.
Understanding the Problem: Shared Concepts, Divergent Needs
In many organizations:
- The Sales team cares about a customer's lead score, purchase intent, and assigned sales rep.
- The Support team, on the other hand, is focused on support ticket history, SLA agreements, and incident timelines.
Clearly, while the term "Customer" is shared, its meaning and usage diverge across these contexts. This is a textbook case of polysemy in DDD — the same term having multiple meanings in different bounded contexts.
What Does DDD Recommend?
✅ Model Each Bounded Context Independently
Rather than forcing a single Customer
entity to serve multiple masters, DDD encourages modeling the concept according to the specific domain's needs.
This means creating:
-
SalesCustomer
in the Sales context. -
SupportCustomer
in the Support context.
Each entity will only contain the attributes and behavior relevant to its respective domain. They can be kept in sync using integration events or APIs.
Why Not Share a Single Customer Entity?
Sharing a single customer model across contexts may seem DRY and clean at first, but it introduces tight coupling, cross-team dependencies, and often leads to bloated models full of irrelevant attributes.
Problems with a Shared Model:
- Code becomes harder to maintain.
- Changes in one context impact others.
- The model becomes a compromise that satisfies no one well.
Integration Through Events: The DDD Way
In a properly decoupled system, Sales might publish domain events such as CustomerCreated
, CustomerUpdated
, or LeadConverted
.
Support consumes these events and updates its own SupportCustomer
read model.
This keeps the systems loosely coupled and allows each to evolve independently.
Diagram: Visualizing the Pattern
- Each bounded context maintains its own
Customer
model. - Integration events (via Kafka, EventBridge, etc.) keep the models in sync.
- The system respects context boundaries and encourages autonomy.
Other Modeling Strategies
In DDD, this scenario can also be approached through different integration patterns depending on organizational and technical constraints:
Pattern | Description |
---|---|
Shared Kernel (discouraged but still valid in rare scenarios) | Shared subset of the model agreed upon and versioned by both teams |
Customer-as-a-Service | One context exposes an API or event feed; others consume with translation |
Anti-Corruption Layer | Context-specific adapter to isolate internal models from external contracts |
Practical Guidelines
- Avoid modeling based on database schemas. Model based on domain semantics.
- Treat duplication as an acceptable trade-off for autonomy and clarity.
- Use ubiquitous language in each context; don’t force uniform terminology.
- Synchronize data through events, not shared objects.
Final Thoughts
In Domain-Driven Design, context is king. Just because different domains refer to a Customer
doesn’t mean they are talking about the same concept. Forcing a unified model creates fragility and limits agility.
Instead, embrace duplication, model explicitly, and integrate intentionally. That’s how you build robust, evolvable systems.