Domain-Driven Design: Bounded Contexts Explained
Understand DDD bounded contexts — how to decompose a complex domain into autonomous modules with clear boundaries, shared kernels, and anti-corruption layers.
Domain-Driven Design: Bounded Contexts Explained
Bounded Contexts are the central pattern in Domain-Driven Design (DDD). They define explicit boundaries within which a domain model is consistent and meaningful.
The Problem: One Model Doesn't Fit All
In a large system, the same word means different things in different parts of the business:
| Term | In Sales | In Warehouse | In Accounting |
|---|---|---|---|
| Order | A customer's purchase intent with pricing and discounts | A pick list with bin locations and weights | An invoice with tax calculations and payment terms |
| Product | SKU with marketing copy, images, and reviews | Physical item with dimensions, weight, and storage class | Revenue line item with cost-of-goods and margin |
| Customer | Lead/prospect with conversion funnel data | Shipping address and delivery preferences | Billing entity with credit terms and payment history |
Forcing one unified model creates a Big Ball of Mud — a model that's too complex, too coupled, and too fragile.
The Solution: Bounded Contexts
Each bounded context:
- Has its own ubiquitous language (terms, rules, invariants).
- Owns its own data store (or at minimum, its own schema/tables).
- Communicates with other contexts via well-defined interfaces (events, APIs, shared kernel).
Context Mapping Patterns
How bounded contexts relate to each other:
Pattern Summary
| Pattern | Description |
|---|---|
| Shared Kernel | Two contexts share a small common model (e.g., Money, Address). Both teams co-own it. |
| Anti-Corruption Layer (ACL) | Downstream context translates upstream models into its own language. Protects from upstream changes. |
| Open Host Service | Upstream exposes a well-defined API/protocol for multiple consumers. |
| Published Language | A shared schema (e.g., JSON Schema, Protobuf) that both sides agree on. |
| Customer–Supplier | Upstream prioritises downstream's needs. |
| Conformist | Downstream adopts upstream's model as-is (no translation). Simplest but most coupled. |
Identifying Bounded Contexts
- Listen for language shifts — When the same word has different meanings, you've crossed a boundary.
- Look for independent lifecycles — If two parts of the system change for different business reasons, they're likely separate contexts.
- Follow the data ownership — Who is the authoritative source for this data?
- Watch for team boundaries — Conway's Law: system structure follows team structure.
Bounded Contexts in Practice
Modular Monolith
Bounded contexts don't require microservices. A modular monolith enforces context boundaries via:
- Separate modules/packages with explicit public APIs.
- Shared database with per-context schemas.
- In-process event bus for async communication.
Microservices
Each microservice is a bounded context (ideally). Inter-service communication happens via:
- Domain events (async, preferred).
- REST/gRPC APIs (sync, for queries).
- Anti-corruption layers at service boundaries.