"What does Order mean?" In your warehouse system, Order = a list of SKUs to pick. In your billing system, Order = an invoice with payment terms. In your shipping system, Order = a box with an address. Same word, three completely different concepts. Build all three under one Order class and you create the worst kind of coupling — every change ripples through systems that share nothing in common.
Domain-Driven Design (DDD) — Eric Evans, 2003 — is the discipline of letting language and concepts mirror the business. The big idea: identify bounded contexts where each domain word has one specific meaning, and let those contexts be the natural boundaries of your services.
02
Bounded contexts — the only DDD idea you need
A bounded context is a place where a particular model + ubiquitous language applies. Outside that boundary, the same word can mean something else.
In Support context: name, contact channels, recent tickets, satisfaction score.
In Recommendations context: user_id, browsing history, embedding vector, segment.
Trying to build one "Customer" object that holds all this is the path to a 200-field nightmare. Three bounded contexts, three different Customer models. They share an ID; they don't share a class.
03
The DDD vocabulary
Term
What it means
Example
Bounded Context
Boundary inside which one model is consistent
"Sales", "Support", "Inventory"
Ubiquitous Language
Vocabulary shared between developers + business inside one context
"Order" in Sales = list of cart items pre-checkout
Aggregate
Cluster of objects that change together; treat as a unit
Order + LineItems together — never modify a LineItem without going through Order
Aggregate Root
The single entry point to an aggregate
Order is the root; access LineItems via Order, not directly
Entity
Object with stable identity beyond its attributes
Customer (you can change their name; they're still the same customer)
Value Object
Defined entirely by attributes; immutable
Money(100, USD), Address — equal if attributes equal
Domain Event
Something the business cares about that happened
OrderPlaced, PaymentReceived, ShipmentDispatched
Anti-Corruption Layer
Translation layer between two contexts so neither leaks into the other
Adapter that maps "Sales Customer" to "Support Customer"
04
Aggregates in practice
The most practically useful DDD idea after bounded contexts. An aggregate is a transactional consistency boundary. Rules:
One aggregate per database transaction. Don't touch two aggregates atomically — if you need to, they should be one aggregate.
External code only references aggregates by ID, never by direct object reference.
Inside an aggregate, you can have rich object graphs. Outside, you can't reach in.
Cross-aggregate consistency is eventual — via domain events.
Example: Order aggregate contains LineItems. Adding a line item: order.addItem(product, qty). The order itself enforces invariants ("max 100 items", "no duplicate SKUs"). You never call lineItem.setQuantity() directly.
Why this matters at scale: aggregates become natural sharding boundaries, natural transaction boundaries, natural cache keys. The boundary you draw in your code is the boundary you exploit in infrastructure.
05
Deep dive — context mapping
Once you have bounded contexts, you have to decide how they relate. Eric Evans defined seven patterns; the practically important ones:
Shared Kernel — two contexts share a small subset of model. Tight coupling. Use sparingly.
Customer/Supplier — context A's needs drive context B's interface. B has to support A's use cases. Negotiated.
Conformist — A uses B's interface as-is, no protection. Cheap; A is at B's mercy when B changes.
Anti-Corruption Layer (ACL) — A wraps B's interface in an adapter that translates to A's preferred terms. Insulates A from B's changes. The professional choice for any cross-team integration.
Open Host Service — B publishes a stable, well-documented API for many consumers. Higher cost for B; many As benefit.
Published Language — common interchange format like JSON Schema, OpenAPI, Avro. Decouples parties via the schema.
Interview answer
"We organize services around bounded contexts derived from business subdomains. Each context owns its data and exposes a context-specific interface. Cross-context integration goes through anti-corruption layers + domain events to prevent model leakage. Aggregates are the unit of transaction inside each context."
06
Real-world
Stripe APIs
Bounded contexts visible in API
Charges, Customers, Subscriptions, Connect — each a context with its own model. Same "Customer" appears differently across them.
Amazon's two-pizza teams
Service per bounded context
Inventory team owns the Inventory context. Recommendations team owns recs context. Each ~5-10 engineers.
Microsoft eShopOnContainers
DDD reference impl
Open-source .NET reference architecture explicitly built around DDD. Catalog, Basket, Ordering, Payment as separate bounded contexts.
E-commerce explicitly applies bounded contexts (Catalog vs Cart vs Order vs Inventory vs Shipping). Payment gateway uses aggregates (Payment, Refund) for atomic state transitions. Uber's domain split (Rides, Eats, Freight) is bounded contexts at the org level.