Library · Summary & review

DDD Reference

By Eric Evans. All DDD patterns in sixty pages — the vocabulary that reshaped how backend thinks about business logic.

FR EN
DDD Reference cover, Eric Evans

DDD Reference

Domain-Driven Design Reference: Definitions and Pattern Summaries

6.4 /10

« Thirty patterns in sixty pages, freely licensed — the trade's vocabulary for those who already know the terrain. »

  • AuthorEric Evans
  • VODomain Language, Inc., 2015 · 59 pages
  • LanguageEnglish only · free PDF (CC BY 4.0)
  • This page~9 min read
Book rating across 5 dimensionsIdeas10/10Practical5/10Readability5/10Aged well9/10Examples3/10

The official Domain-Driven Design glossary: all of Evans' patterns in sixty pages, freely available online.

Why this document

I came across DDD terms scattered everywhere — "bounded context" in a microservices post, "aggregate root" in a Symfony conference talk, "ubiquitous language" in an architecture book. Everyone used them as if they were obvious. I wanted the source. The Blue Book (560 pages, 2004) is the original, but Evans himself condensed all its patterns into this free 59-page reference. It's the map before the territory.

Fair warning: this is not a book you learn DDD from. It's a reference for people who already know DDD and need a quick reminder, or for people who want to understand the vocabulary before diving into the full book or Vaughn Vernon's Implementing Domain-Driven Design.

The ideas that stick

1The model and the code are one object

The classic architecture trap: a senior architect models in UML during workshops, developers code what they can, and the two quietly diverge. Evans calls this "a deadly divide between analysis and design." Each side works against the other without knowing it.

Model-Driven Design's answer is radical: code must reflect the domain model literally. An Order object in the code corresponds to an order in the business domain — not a table, not a DTO, not a Doctrine entity with its own rules.

The direct consequence: "a change to the code may be a change to the model." Renaming a class might mean changing the project's vocabulary.

Hence Hands-on Modelers: anyone contributing to the model must spend time in the code, and every developer must have access to domain experts. An architect who doesn't code ends up modeling things that can't be implemented. An isolated developer ends up coding something other than what the business wanted.

2Ubiquitous Language — code that speaks the domain

In an ordinary project, three languages coexist without ever touching: the business jargon of domain experts, the technical vocabulary of developers, and the code. Experts talk about "order confirmation," developers write OrderStatusUpdate, and the project manager translates in both directions at every meeting. Every translation loses a little meaning.

DDD imposes one rule: there must be a single vocabulary, shared without translation between experts and developers, in conversations and in code. Evans writes: "Recognize that a change in the language is a change to the model." If your expert says "reservation" and your code says Booking, you already have a model problem.

This isn't about elegance. It's a real-time test: if you can't explain your code to the domain expert using their own words, your code doesn't correctly model their domain.

The Ubiquitous Language is both a design tool and a detection tool.

3Bounded Context — where "customer" stops meaning anything

On a large project, the same word covers different realities depending on who's speaking. In the CRM, a "customer" has a purchase history and preferences. In billing, a "customer" is a legal entity with a tax number. In support, a "customer" is an open ticket with a priority level. Forcing a single "Customer" model for the whole system produces a bloated object that satisfies no one — or silent bugs when the models contaminate each other.

A Bounded Context draws an explicit boundary within which a model applies coherently. Inside, the Ubiquitous Language holds without ambiguity. Between two contexts, an explicit translation is needed — and that translation is itself modeled (see idea 7).

Keeping that coherence over time has a name in DDD: Continuous Integration, not to be confused with automated CI/CD pipelines. Here it is a team practice. When several people code in parallel, their versions of the model drift apart in silence, each refining a term in their own corner. You prevent it by merging often, so gaps surface early and small, and by re-aligning the language continuously, so a word keeps a single meaning in the code as in conversation.

4Entity vs Value Object — the first question for every object

For each domain concept, the first question to ask: does identity matter, or only the attributes?

An Entity is defined by its identity, not its attributes. A user remains the same user even if they change their email, married name, or profile picture. Their ID persists over time. Two entities with identical attributes are still two distinct entities — what matters is WHO, not WHAT.

A Value Object describes a characteristic. The address "12 rue de la Paix, 75001 Paris" has no identity of its own. Two identical addresses are interchangeable. Value Objects are immutable: when something changes, you create a new object instead of modifying the existing one. This immutability makes them safe to share.

// Entity — identity is the ID, attributes can evolve
class Order {
    public function __construct(
        private readonly OrderId $id,   // stable identity
        private Status $status           // can evolve
    ) {}
}

// Value Object — immutable, two equal instances = interchangeable
final class Money {
    public function __construct(
        private readonly int $cents,
        private readonly string $currency   // "EUR", "USD"…
    ) {}

    public function add(Money $other): self {
        return new self($this->cents + $other->cents, $this->currency);
    }
}

The distinction is not technical — it's semantic. An invoice number might be an entity or a Value Object depending on whether your domain treats it as a persistent identity or a printable code.

5Aggregate — the guardian of consistency

A system with complex associations faces a consistency problem: if any code can modify any object directly, business rules break silently. An OrderLine modified without going through the Order can produce an incoherent total.

An Aggregate groups entities and Value Objects into a unit treated as a whole. One object is the Aggregate Root: the only access point from the outside. Internal objects cannot be modified directly from outside the boundary.

Evans states the transaction rule: "Use the same aggregate boundaries to govern transactions and distribution." One transaction = one aggregate. If two aggregates must change together, that's asynchronous coordination — not an extended synchronous transaction.

This is what makes distributed systems manageable: each aggregate lives on one node, cross-aggregate updates travel through events.

So how do two aggregates actually talk? Validating an Order and decrementing the Stock never share a transaction. The Order commits alone, then announces what happened by emitting an event; the Stock listens and applies the consequence later, in its own separate transaction, with its own rules:

// 1. Order aggregate — its own transaction, all or nothing
$order->validate();                          // checks ITS rules (coherent total…)
$order->recordEvent(new OrderValidated($order->id(), $order->lines()));

// 2. The event travels alone — no shared transaction, no lock held on Stock

// 3. Stock aggregate reacts later, in ITS OWN transaction
function onOrderValidated(OrderValidated $event) {
    $stock->reserve($event->lines());            // checks ITS rules (never below 0)
}

The Order never reaches into the Stock to change it — it only knows the Stock's identity, not its internals. The price of crossing the boundary: between the two there is a brief window where the order is validated but the stock not yet reserved. Inside an aggregate, consistency is immediate; between aggregates it is eventual — and that delay is exactly what lets each one live on its own machine.

One transaction per aggregate, asynchronous events between them Order Aggregate Order (root) Line Line 1 transaction: all or nothing Stock Aggregate Stock (root) Item 1 transaction: all or nothing async event A transaction never leaves one aggregate · between two, an async event · one node each
The consistency rule, drawn: each aggregate changes in one block (all or nothing) in its own transaction. To sync Order and Stock you don't open a shared transaction, you send an asynchronous event, which lets each live on its own machine.

6Repository — the database disappears from the model

Without the pattern, business logic gets contaminated with SQL. The domain code knows table names, columns, joins. Changing the database engine becomes a rewrite.

A Repository creates the illusion of an in-memory collection of all objects of a type. Business code acts as if the objects are always there, with no knowledge of SQL, Redis, or any infrastructure detail:

// ✗ Without repository: the domain knows the infrastructure
$stmt = $pdo->prepare('SELECT * FROM orders WHERE status = "pending" AND customer_id = ?');
$stmt->execute([$customerId]);

// ✓ With repository: the domain speaks its own language
$orders = $orderRepository->pendingOrdersFor($customerId);

The method pendingOrdersFor is named in the Ubiquitous Language, not in SQL terms. The Doctrine, Redis, or flat-file implementation hides behind the interface. Tests can use an in-memory repository. The domain stays clean. Evans adds: provide repositories only for Aggregate Roots that need direct access — not for every internal entity.

7Context Mapping — the politics between teams, made explicit

When a project touches multiple Bounded Contexts (your system, an external CRM, a legacy ERP), DDD offers a taxonomy of relationships. It's not just a technical question — it's often a political one.

  • Anticorruption Layer (ACL) : when the upstream model is a catastrophe (unmaintained legacy, Big Ball of Mud), you build a defensive translation layer. It speaks two languages: the external system's terms on one side, your clean model on the other. Your domain stays uncontaminated.
  • Conformist : when the upstream team has no incentive to adapt to your needs, you can choose to adopt their model without a fight. It simplifies integration at the cost of a model that's sometimes ill-suited to your real needs.
  • Open-host Service : you expose your subsystem as a set of services with a clear, documented protocol. Each consumer adapts to your public interface. It's the pattern of well-designed REST APIs.
  • Partnership : two teams whose success is linked plan jointly and evolve their interfaces together. Expensive in coordination, but necessary when one side failing brings both down.

The resulting Context Map is often not a formal diagram — it's a whiteboard sketch that makes explicit dependencies that already existed but had never been named.

Context Map: your context and three named relationships with its neighbors Your Context Legacy ERP (Big Ball of Mud) External API (Open-host Service) Partner team ACL Conformist Partnership
A few common relationships: ACL protects your model from a chaotic legacy; Conformist adopts the model of a well-designed API (Open-host Service); Partnership co-evolves with an interdependent team. The choice is partly technical, partly political.

8Core Domain — where to put your best developers

Not everything deserves the same investment. An e-commerce platform has a Core Domain: the recommendation algorithm, the dynamic pricing engine, real-time inventory management. Those parts make the business's competitive value. Email confirmation management or PDF generation are Generic Subdomains: necessary, but standardized.

Evans is direct: "Apply top talent to the core domain, and recruit accordingly." Your most senior developers shouldn't spend their time on generic subdomains you could buy or outsource. For Generic Subdomains, Evans explicitly recommends considering off-the-shelf solutions — why implement your own permission system when you could buy a proven one? Free the energy for the domain that makes your competitive value.

Distillation goes further:

  • Identify: explicitly identify the Core Domain.
  • Document: document it in a one-page Domain Vision Statement.
  • Mark: mark its elements in the code.

This visibility lets the team make the right trade-offs when resources are scarce.

Three things I didn't expect

  • CQRS cited as an evolution, not a contradiction — Evans thanks Greg Young and Udi Dahan in the preface for CQRS and Event Sourcing — he sees them as "the first successful big departure" from the architecture inherited from the turn of the century. DDD didn't get outdated by them: it gained new architectural options.
  • The Big Ball of Mud is a legitimate pattern — Evans doesn't condemn it outright. He cites Foote and Yoder: sometimes a Big Ball of Mud is the practical solution for a given context. The advice: draw a boundary around it so it doesn't contaminate the rest, but don't try to apply DDD inside it.
  • "Separate Ways" as a valid strategy — DDD officially acknowledges that sometimes the best thing two bounded contexts can do is have nothing to do with each other. Integration always has a cost. If the benefit is small, declare independence.

Honestly

The title says "Reference" and it delivers: a glossary, not a novel. Thirty patterns, each a half-page, same format — problem, "Therefore:", solution. You don't learn DDD here. You look things up.

What strikes me is how well it holds up. Evans writes the original in 2004, publishes this Reference in 2015, and in 2026 the patterns still stand. CQRS and Event Sourcing, which he salutes in the preface, strengthened DDD rather than obsoleting it. Bounded Contexts became the natural vocabulary of microservices. The Anticorruption Layer describes exactly what you do when consuming a legacy API.

The problem is what's missing: the stories. The original Blue Book fills 560 pages with concrete cases, failed examples, progressive refactorings. This Reference gives you the vocabulary without the grammar. You'll be able to say "Aggregate Root" without necessarily knowing when to draw an aggregate boundary, or why that boundary makes all the difference. If you're new to DDD, read Vaughn Vernon's Implementing Domain-Driven Design first — more accessible than the Blue Book. Come back to the Reference as a cheat sheet. It's free, short, and exactly what a glossary should be.

And in my PHP/Symfony code, concretely?

DDD influenced Symfony deeply:

  • Doctrine entities: implement the Entity pattern (persistence identity via an ID).
  • Form objects: can be Value Objects.
  • Repositories: are first-class citizens with their own interface.

The Messenger component naturally implements Domain Events. The concepts in this Reference are not theoretical abstractions — they're the vocabulary behind frameworks you already use daily.

Read it if

  • You work on a project with complex business logic and want a shared vocabulary for the team
  • You've already encountered "bounded context" or "aggregate root" in the wild and want the primary source
  • You want a one-hour reference, freely licensed, shareable without restrictions
  • You already know DDD and need a cheat sheet to refresh the taxonomy

Skip it if

  • You're completely new to DDD — the Reference without the book is the index without the chapters
  • You're doing simple CRUD without meaningful business logic — DDD has a real entry cost
  • You want worked examples and concrete case studies — that's the Blue Book or Vernon's IDDD

Go further

Comments (0)