Domain-Driven Design
Model code around the business domain. Bounded contexts, ubiquitous language, aggregates, value objects. Eric Evans, 2003. Survives framework churn.
Code that mirrors the business domain. Ubiquitous language. Bounded contexts. The book that taught a generation to model before coding. Status: STUB — promoted to OUTLINE in Y1 Phase 5.
What this pattern is
Domain-Driven Design (DDD), introduced by Eric Evans in 2003, models code around the business domain rather than around the database schema or the UI. Its core moves: build a ubiquitous language shared between engineers and domain experts; carve the domain into bounded contexts so different parts can model the same concept differently without leaking; use aggregates to enforce invariants across related entities; use value objects for concepts defined by their attributes; keep the domain model isolated from infrastructure concerns.
The patterns inside DDD (entities, aggregates, repositories, services, factories) are internal structure decisions. They survive whether you’re using Spring Boot, FastAPI, or Go. What DDD contributes above the individual tactical patterns is a discipline: model the business first, encode it in code, and let the technical patterns (repositories, factories, services) fall out of the model rather than driving it.
DDD’s value is most apparent when domain complexity is real. Insurance policies, healthcare workflows, financial instruments, logistics networks, e-commerce orders — these have hundreds of concepts that interact in ways the domain expert knows and the engineer often doesn’t. Modeling this in code without DDD produces a system that’s technically correct but semantically wrong: the code doesn’t match how the business thinks about the problem, and every conversation between engineers and stakeholders requires translation. For CRUD apps or simple pipelines, DDD can over-engineer. The judgment of when to apply it is a senior-IC distinction.
Concrete instances in the wild
- Amazon’s service architecture. Amazon’s two-pizza teams map to bounded contexts. Each team owns its domain vocabulary; different teams model overlapping concepts (like “order” or “customer”) differently, connected through published contracts, not shared databases.
- Banking core systems. Accounts, transactions, and ledgers as aggregates that enforce invariants (double-entry bookkeeping, no negative balances without overdraft, atomic transfer semantics). The aggregate boundary is where the invariants live.
- Insurance policy modeling. A Policy aggregate references Coverages, Beneficiaries, and Claims — each a distinct concept in the ubiquitous language. The words match what actuaries and adjusters use.
- E-commerce order processing. Order, LineItem, ShippingAddress, PaymentMethod as related entities with clear ownership. Order is the aggregate root; you can’t directly modify a LineItem, you tell the Order to update it.
- Logistics with distinct bounded contexts. Warehouse and Shipping both use the word “Package,” but they mean different things. In Warehouse, a Package is defined by its physical dimensions and location. In Shipping, it’s defined by destination, weight, and carrier. Same word, different bounded contexts, no leakage.
- Healthcare EHR systems. Patient, Encounter, Diagnosis, Medication — modeled as domain concepts, not as database tables. The domain model outlives many database migrations.
- Trading platforms. Instrument, Order, Trade, Position as domain concepts. Value objects for Price and Quantity (they’re immutable, defined by attributes, and equality is structural).
- Content management systems. Article, Author, Revision, Publication as aggregates. The aggregate boundary determines what changes atomically vs eventually.
Why this pattern matters
Without a modeled domain, code drifts toward the shape of the database. Database rows become entity classes; foreign keys become relationships; joins become the primary way to answer business questions. The result is code that’s easy to query and hard to reason about. Business rules end up scattered across SQL queries, view templates, and service methods, and no one knows where the authoritative definition of “customer with an active subscription” lives.
DDD flips this. The domain model is authoritative. Business rules live in domain code, expressed in the ubiquitous language. The database becomes an implementation detail. Two people from different parts of the company (an engineer and a customer support lead) can look at the domain model and agree that yes, this is how the business actually works.
The pattern also matters for team scaling. Bounded contexts let different teams model overlapping concepts differently without stepping on each other. Warehouse team’s Package is different from Shipping team’s Package; both are correct in their context; the contract between them is explicit. Without this discipline, cross-team dependencies produce constant coordination overhead and shared entities that make everyone miserable.
Depth progression
STUB ← you are here.
OUTLINE Promoted when Y1 Phase 5 walks DDD's core moves.
DEEP Promoted when at least one Y2 capstone service explicitly applies DDD
and you've felt the trade-off of carving a bounded context the wrong
way at least once.
Preview: what OUTLINE will answer
When Y1 Phase 5 promotes this entry to OUTLINE, it will name:
- PROBLEM. How do you model complex business domains in code such that the code reflects how the business actually thinks?
- PRINCIPLES. Ubiquitous language shared between engineers and domain experts. Bounded contexts to prevent semantic overload. Aggregates enforce invariants across related entities. Value objects for concepts defined by attributes; entities for concepts defined by identity. Domain isolated from infrastructure.
- TRADE-OFFS. Tactical DDD (patterns like aggregates and repositories) vs strategic DDD (bounded contexts, context mapping, event storming). Small domain with heavy DDD ceremony vs large domain with light DDD ceremony. Domain events vs direct calls between contexts.
- TOOLS (time-stamped as of 2026-06): Evans’s blue book vocabulary, Vernon’s red book patterns, event storming as a modeling workshop, context maps as visual documentation, and language-specific DDD toolkits (Axon in Java, Broadway in PHP, though most implementations are hand-rolled).
The DEEP promotion, after Y2 capstone services and at least one bad-context-carve experience, will add MASTERY (operating a DDD-shaped service through real feature work), COMPARE (DDD vs a lighter approach like Rails-style ActiveRecord), OPERATE (incidents where the model misalignment produced bugs), and CONTRIBUTE (a domain-model refactor documented in ADRs).
Canonical references
- Eric Evans, Domain-Driven Design: Tackling Complexity in the Heart of Software (2003) — the “blue book.” Dense but foundational. Read chapters 1-4 first; the rest is reference.
- Vaughn Vernon, Implementing Domain-Driven Design (2013) — the “red book.” More accessible; walks concrete implementations.
- Alberto Brandolini’s writing on Event Storming — a lightweight modeling workshop that bootstraps a shared ubiquitous language.
- Martin Fowler’s blog posts on aggregates and value objects — free, short, and clarifying.
- Nick Tune’s writing on strategic DDD — modern coverage of bounded contexts and context mapping.
Cross-references
- Y1 Phase 5: Software Architecture Patterns — first introduction
- Y2 overview — where DDD gets applied to real backend services
- Related: clean-architecture, hexagonal-and-ports-and-adapters, repository-pattern
- Canonical text: “Domain-Driven Design” — Eric Evans (2003)