Redr · Study Guide
Domain-Driven Design
Tackling Complexity in the Heart of Software
Eric Evans
Unofficial AI-assisted study guide. Not affiliated with or endorsed by the author or publisher. For educational use — supplements, not replaces, the original work.
Contents
- 01Crunching Knowledge
- 02Communication and the Use of Language
- 03Binding Model and Implementation
- 04Isolating the Domain
- 05A Model Expressed in Software
- 06The Life Cycle of a Domain Object
- 07Using the Language: An Extended Example
- 08Breakthrough
- 09Making Implicit Concepts Explicit
- 10Supple Design
- 11Applying Analysis Patterns
- 12Relating Design Patterns to the Model
- 13Refactoring Toward Deeper Insight
- 14Maintaining Model Integrity
- 15Distillation
- 16Large-Scale Structure
- 17Bringing It All Together
- Part 01 · Putting the Domain Model to Work01Crunching Knowledge02Communication and the Use of Language03Binding Model and Implementation
- Part 02 · The Building Blocks of a Model-Driven Design04Isolating the Domain05A Model Expressed in Software06The Life Cycle of a Domain Object07Using the Language: An Extended Example
- Part 03 · Refactoring Toward Deeper Insight08Breakthrough09Making Implicit Concepts Explicit10Supple Design11Applying Analysis Patterns12Relating Design Patterns to the Model13Refactoring Toward Deeper Insight
- Part 04 · Strategic Design14Maintaining Model Integrity15Distillation16Large-Scale Structure17Bringing It All Together
Part 01
Putting the Domain Model to Work
Ch. 1–3
Crunching Knowledge
Effective software for complex domains depends on a deep, evolving model — not on technical prowess alone. Knowledge crunching is the ongoing, collaborative process by which developers and domain experts distill messy domain information into a shared, expressive model that drives the software.
Ingredients of Effective Modeling
Modeling works when the model is bound to implementation, a language is cultivated around it, the model is knowledge-rich, it is distilled over time, and the team brainstorms and experiments. Skip any ingredient and the model becomes academic.
Knowledge Crunching as Collaboration
Modeling is not a solo analyst's job. Developers, domain experts, and users together explore scenarios, surface contradictions, and discover useful abstractions through dialogue.
Iterative Refinement
The first model is never the right one. Evans's PCB-routing example shows how early models (just nets and components) evolve to include richer concepts (probe simulation, reference designators) as the team crunches more knowledge.
Domain Experts Learn Too
Forcing experts to articulate tacit knowledge in precise terms exposes inconsistencies in their own thinking. Knowledge crunching sharpens the business's understanding of itself, not only the developers'.
Continuous Learning
Knowledge leaks when people leave or projects fragment. Explicit modeling preserves and amplifies team learning, making it part of the codebase rather than tribal lore.
Knowledge-Rich Design
A good model captures rules, policies, and constraints — not just entities and data. The juicy parts of the domain usually live unwritten in the experts' heads; surfacing them is the modeler's job.
Deep Models
Beyond surface jargon, seek the underlying concepts that genuinely explain the domain. A shallow model reflects vocabulary; a deep model reflects insight.
- Domain
- The sphere of knowledge or activity to which the program is applied.
- Model
- A system of abstractions that describes selected aspects of a domain.
- Knowledge Crunching
- Collaborative distillation of domain information into a rigorous, useful model.
- Domain Expert
- A team member whose primary expertise is the business, not software.
- Analysis Model
- A traditional pre-design model produced separately from implementation; Evans criticizes the separation.
- Brainstorming
- Free-flowing exploration combined with concrete experiments that stress the model.
- Deep Model
- A model that captures essential abstractions allowing important business problems to be expressed cleanly.
Multiple choice
According to Evans, what most reliably separates a deep model from a shallow one?
Spot the issue
A team hires a business analyst to interview domain experts for six weeks and produce a "complete" analysis model document. They hand the document to developers, who proceed to design and code the system independently. What's wrong with this approach?
Multiple choice
Evans's PCB-routing example illustrates which principle?
True / False
Knowledge crunching only sharpens developers' understanding — domain experts learn nothing new from the process.
Communication and the Use of Language
Translation between domain experts' language and developers' language is a major source of bugs and lost insight. Evans proposes a single shared Ubiquitous Language — built on the domain model and used in speech, writing, diagrams, and code alike. When the language strains, the model itself must change.
The Cost of Translation
When developers speak "tech" and experts speak "business," every conversation requires translation, which loses information and hides assumptions. Neither side can think clearly with the other's vocabulary.
Ubiquitous Language
The shared language is grounded in the domain model. Class names, method names, and module names in code are the same terms used in conversation, requirements, and diagrams.
Modeling Out Loud
Teams play with the language verbally — speaking scenarios aloud, rephrasing requirements using model terms. Awkward sentences signal a model flaw, not a phrasing problem.
One Team, One Language
Developers and experts do not need separate dialects. Some technical jargon stays internal to developers, but domain concepts must be expressed identically across the team.
Documents Support, Not Replace
Specs and diagrams are scaffolding and reference. They cannot substitute for the living, code-bound language; documents that drift from the code are worse than no documents.
The Role of Diagrams
Comprehensive UML rarely works. Small, focused diagrams that highlight a specific concept, paired with explanatory text and code, communicate far better.
Language Evolves with the Model
Vocabulary changes trigger code changes; refactored code feeds back into the language. The two rise and fall together — neither leads permanently.
- Ubiquitous Language
- A language structured around the domain model and used by every team member within a Bounded Context.
- Translation
- The lossy conversion between dialects that the Ubiquitous Language exists to eliminate.
- Modeling Out Loud
- Speaking scenarios aloud in the model's vocabulary to stress-test it.
- Explanatory Model
- A separate model used purely for communication, distinct from the implementation model.
- UML
- The standard graphical notation — useful in fragments, weak for whole-system capture.
- Code as Model Expression
- The principle that source code itself is a primary medium of the model.
Multiple choice
What grounds the Ubiquitous Language for a team?
Spot the issue
During a planning meeting, a developer says, "When the user POSTs to the orders endpoint, we'll persist the row and fire a webhook." The product expert nods politely but later admits she didn't understand most of it, so she described the same flow as "when a customer places an order, notify the warehouse." What's the underlying problem?
Multiple choice
A team member rephrases a requirement using model terms and the sentence comes out clumsy and twisted. What does Evans recommend?
Multiple choice
What does Evans say about comprehensive UML diagrams covering an entire system?
Binding Model and Implementation
Evans contrasts the traditional split — analysts hand a model to programmers who build a separate design — with model-driven design, where one model serves both understanding and implementation. This binding requires hands-on modelers: developers who model and modelers who code.
Pitfalls of Pure Analysis Models
A model produced solely for understanding, with no concern for implementation, forces programmers to invent a parallel structure. The two drift apart, and the model loses authority over the code.
Model-Driven Design
Software design reflects the domain model so closely that the mapping between the two is obvious. The model is not a separate document — it is the skeleton of the code itself.
One Model for Analysis and Design
A single model serves understanding, communication, and implementation. Compromises flow in both directions: the analyst accepts implementation constraints; the programmer accepts conceptual ones.
The Hands-On Modeler
Anyone contributing to the model spends time with code; anyone changing code understands the model. Separating "thinkers" from "coders" breaks the binding.
Implementation Pushes Back
When a model concept cannot be cleanly implemented, that is feedback about the model, not an indictment of the code. Listen to it.
Modeling Paradigms Must Fit the Tools
Object-oriented languages naturally support object models. Forcing an object model onto a procedural or purely relational platform breaks the binding between code and model.
Software Reveals the Model
Well-bound code makes the model visible. A reader should be able to recover the model's concepts directly from class structures, method names, and interactions.
- Model-Driven Design
- An approach in which code structure is tightly bound to and shaped by the domain model.
- Hands-On Modeler
- A developer who participates in modeling and a modeler who works in the code.
- Implementation
- The running code; in MDD, shaped by the model rather than translated from it.
- Modeling Paradigm
- The framework (OO, procedural, relational) in which the model is expressed.
- Skeleton
- Evans's metaphor for the model serving as the underlying structure of the software.
- Round-Trip
- Movement between conceptual modeling and implementation, with each shaping the other.
Multiple choice
In Model-Driven Design, what is the relationship between the domain model and the code?
Spot the issue
A senior architect produces detailed UML class diagrams and hands them to a separate implementation team. He never reads the resulting code; the implementers never join modeling sessions. After six months the diagrams and the code describe noticeably different systems. What broke?
Multiple choice
A modeler proposes a concept that the implementation team finds impossible to express cleanly in code. What should the team conclude?
True / False
Forcing a richly object-oriented model onto a purely procedural or strictly relational platform preserves the binding between code and model.
Part 02
The Building Blocks of a Model-Driven Design
Ch. 4–7
Isolating the Domain
Domain logic must be separated from UI, persistence, and infrastructure concerns; otherwise it disperses and the model has nowhere to live. Layered Architecture is the standard solution, while the Smart UI is acceptable only for trivial applications that will never need a rich model.
Layered Architecture
Partition the program into User Interface, Application, Domain, and Infrastructure layers, with each depending only on layers below. The Domain Layer is where business concepts, rules, and state live.
The Four Standard Layers
UI presents and interprets; Application coordinates tasks (no business rules, no state); Domain expresses the business; Infrastructure supplies generic capabilities like persistence and messaging.
Domain Layer Isolation
The principal goal of layering: give the domain model a pure place to exist. Without isolation, business logic leaks into UI controllers and database code and the model dies.
Relating the Layers
Upper layers call lower layers directly through public interfaces. Lower layers communicate upward through callbacks and Observers, never by direct reference.
The Smart UI Anti-Pattern
Put all business logic in the UI, chop into small functions, use the database directly. Productive for trivial apps with junior developers and short lifecycles — but locks you out of model-driven design forever.
Smart UI Trade-offs
Smart UI offers simplicity and speed but forbids reuse, abstraction, and rich behavior. Choosing it is a strategic commitment that forecloses DDD.
Frameworks Must Not Intrude
A framework that forces the domain layer to implement framework interfaces couples the model to infrastructure. Pick frameworks that support layering without invading the domain.
- Layered Architecture
- A design in which the program is divided into layers, each depending only on those below.
- User Interface Layer
- Shows information and interprets commands.
- Application Layer
- A thin coordinator with no business rules and no domain state.
- Domain Layer
- Represents business concepts, information, and rules — the heart of the software.
- Infrastructure Layer
- Generic technical capabilities supporting higher layers.
- Smart UI Anti-Pattern
- All business logic placed in the UI; suitable only for simple, short-lived applications.
- Separation of Concerns
- The general principle motivating layering.
Multiple choice
Which responsibility belongs to the Application Layer in Evans's layering?
Spot the issue
A team builds a customer-loyalty system as a single Rails app: button click handlers in controllers call ActiveRecord models that contain a sprinkling of validation but most rules live in controller methods alongside flash messages and redirect logic. The product owner expects this code to power three new channels next year. What's the strategic problem?
Multiple choice
How do lower layers communicate with upper layers in a Layered Architecture?
Multiple choice
What is the principal goal of Layered Architecture according to Evans?
A Model Expressed in Software
Three tactical patterns let an object-oriented model be expressed in code: Entities (identity matters), Value Objects (attributes only), and Services (verbs with no natural home). Modules organize the model; carefully designed Associations minimize coupling.
Associations
Every traversable association in the model becomes a reference in code. Tame them by imposing direction, adding qualifiers to reduce multiplicity, and eliminating non-essential associations.
Entities
An object defined by a thread of continuity and identity that persists through state changes. Equality is identity-based; identity may be natural or assigned.
Value Objects
An object that describes a characteristic with no conceptual identity. Equality is by attributes; instances should be immutable, freely shared, and discarded when no longer useful.
Designing Value Objects
Default to immutability. If a Value Object must be shared, never mutate it. If mutability is unavoidable, never share the instance. They may reference Entities but their own identity does not matter.
Services
Some operations are verbs with no natural object home (e.g., funds transfer). Model them as Services: a stateless interface expressing a domain concept, named in the Ubiquitous Language.
Services Across Layers
Services occur in Application, Domain, and Infrastructure layers. The discipline is keeping Domain Services from being colonized by Application coordination or Infrastructure plumbing.
Modules
Modules group conceptually related elements with low coupling and high cohesion. Module names enter the Ubiquitous Language; choose names that reveal domain meaning, not technical categories.
- Entity
- An object defined by identity that persists through state changes.
- Value Object
- An object defined by its attributes, with no conceptual identity.
- Service
- A standalone operation modeled as an interface, not part of any Entity or Value Object.
- Module (Package)
- A named container grouping related model elements; part of the model itself.
- Identity
- The distinguishing thread that defines an Entity.
- Immutability
- A property where state cannot change after creation; default for Value Objects.
- Association
- A modeled relationship that becomes a traversable reference in code.
- Stateless Service
- A Service whose instances carry no client-specific state between calls.
Multiple choice
Which is the defining characteristic of a Value Object?
Spot the issue
A developer models "transfer funds between two accounts" by adding a `transfer(toAccount, amount)` method to the `Account` Entity. Reviewers note it feels awkward — neither source nor destination account "owns" the operation. What's the cleaner design?
Multiple choice
What is the default rule for mutability in Value Objects?
Multiple choice
Evans says module names should be chosen to:
The Life Cycle of a Domain Object
Persistent objects are created, used, archived, deleted — and managing this lifecycle raises issues of integrity, reference complexity, and the gap between memory and storage. Three patterns address these: Aggregates (consistency boundaries), Factories (encapsulated creation), and Repositories (collection-like retrieval).
Aggregates
Cluster Entities and Value Objects into Aggregates with explicit boundaries. Each Aggregate has a single root Entity, the only member outside objects may reference, which enforces the Aggregate's invariants as a unit.
Aggregate Rules
The root has global identity; interior entities have local identity only. External references point only to the root; transient interior references are allowed only within one operation. Everything stored must be reachable from a root.
Aggregates and Transactions
Deletes remove the whole Aggregate at once. When an Aggregate changes, all invariants must be satisfied before commit. Aggregates are the natural unit of transactional consistency.
Factories
Shift creation of complex objects and Aggregates to a separate Factory, which is part of the domain design but not the model. Factories encapsulate construction knowledge and atomically produce instances in a valid state.
Forms of Factories
Useful patterns include Factory Method, Abstract Factory, and Builder. The Factory must guarantee all invariants of the Aggregate it produces.
When a Constructor Is Enough
Skip the Factory when the class is not part of a hierarchy, the client cares which concrete class, all attributes are available, construction is simple, and no invariants span multiple objects.
Repositories
A Repository provides the illusion of an in-memory collection of all Aggregates of one type. Clients query through domain-meaningful methods; the Repository encapsulates the storage technology.
Repository Design
One Repository per Aggregate root, exposing domain-meaningful queries, delegating to a persistence framework. Repositories free the model from infrastructure concerns and let storage be swapped for testing.
- Aggregate
- A cluster of associated objects treated as a unit for data changes.
- Aggregate Root
- The single Entity that external objects may reference; enforces invariants.
- Invariant
- A consistency rule that must hold whenever data changes.
- Factory
- A program element responsible for creating other objects in a valid state.
- Repository
- A mechanism that mediates between the domain and the persistence store.
- Local Identity
- Identity unique only within an enclosing Aggregate.
- Global Identity
- Identity unique across the entire system.
- Persistent Object
- A domain object whose state outlives a single process.
Multiple choice
What is the rule for external references into an Aggregate?
Spot the issue
A team needs to create a new `Order` with a generated order number, an initial `Cart` snapshot, a discount calculation, and a default shipping address. They put all of this into a 60-line `Order` constructor. What pattern would clean this up?
Multiple choice
A Repository provides clients with which illusion?
Spot the issue
What's the Aggregate-design problem?
public class Order {
public List<LineItem> items;
public Customer customer;
}
// In another module, far away:
order.items.add(new LineItem(...)); // bypasses any invariants
order.items.get(0).setPrice(BigDecimal.ZERO);True / False
A Repository should be created for every Entity in the model, including interior entities of an Aggregate.
Using the Language: An Extended Example
Evans walks through a cargo-shipping application to show how Part II's patterns combine in practice. Starting from domain conversation, the design progressively isolates the domain, distinguishes Entities from Value Objects, draws Aggregate boundaries, introduces Repositories, Factories, and finally a Service for a new allocation policy.
Introducing the Shipping Application
The domain features Cargo, Customers, Carrier Movements, Handling Events, and routing. Iterative dialogue with experts produces an initial class diagram and seeds the Ubiquitous Language.
Two Applications, One Domain
The design supports a Tracking Query application and a Booking application, both depending on the same domain layer — demonstrating how isolation lets multiple Application Layers reuse one model.
Distinguishing Entities and Value Objects
Customer, Cargo, Handling Event, and Carrier Movement become Entities. Tracking IDs, voyage numbers, and addresses become Value Objects. Each choice is justified by whether identity matters.
Designing Associations
Bidirectional associations are pruned and given direction (e.g., Cargo → Customer, not both ways). Constraining or removing associations dramatically simplifies implementation.
Aggregate Boundaries in the Shipping Domain
Customer, Cargo, Handling Event, Carrier Movement, and Location are each Aggregate roots. Delivery History sits inside the Cargo Aggregate, protected from outside reference.
Selecting Repositories
Only Aggregate roots get Repositories: Customer, Cargo, Handling Event, Carrier Movement, Location. Each offers domain-meaningful queries (e.g., find cargo by tracking ID).
Factories and Refactoring
A Cargo Factory ensures new Cargos are born with tracking IDs and Delivery Histories satisfying invariants. Later, Evans reconsiders the Aggregate — does Delivery History belong inside Cargo or follow from Handling Events? — showing that initial designs are tentative.
Introducing a Service for a New Feature
A new allocation-checking requirement arrives. Rather than forcing it into an existing Entity, Evans models it as an Allocation Checking Service — a verb-oriented Domain Service.
- Cargo
- The central Entity, representing a shipment with tracking ID, route, and history.
- Handling Event
- An Entity for a discrete action on a cargo (loaded, unloaded, claimed).
- Carrier Movement
- An Entity representing one leg of transport by a carrier.
- Delivery History
- Part of the Cargo Aggregate; records the cargo's Handling Events.
- Tracking ID
- A Value Object uniquely identifying a Cargo.
- Allocation Checking Service
- A Domain Service expressing the booking allocation policy.
- Route Specification
- Describes the intended route of a Cargo — origin, destination, deadline.
Multiple choice
In the cargo example, which of these is correctly classified as a Value Object?
Spot the issue
A new allocation-checking requirement arrives. A developer proposes shoving the logic into the `Cargo` Entity because "it deals with cargo." The team objects. What is the cleaner design?
Multiple choice
Why does Delivery History sit inside the Cargo Aggregate rather than being its own Aggregate root?
Multiple choice
Two applications — Tracking Query and Booking — share the same domain layer. What does this illustrate?
Part 03
Refactoring Toward Deeper Insight
Ch. 8–13
Breakthrough
Successive refactorings of a domain model occasionally produce a breakthrough — a discontinuous leap where the team suddenly sees the domain in a fundamentally new way. Breakthroughs require prior incremental refactoring and the courage to undertake risky, large-scale change at the right moment.
Breakthrough as Payoff
Continuous modest refactoring accumulates until a sudden conceptual shift reframes the whole model. Progress is not linear — it comes in phase transitions.
The Syndicated Loan Example
A loan-syndication system tracked "shares" of a loan facility, but shares were not conserved across drawdowns and fees. The contradiction exposed a hidden domain concept and forced a fundamental redesign.
Recognizing the Opportunity
Breakthroughs appear as awkwardness, contradictions, or repeated workarounds. The team must read these as invitations to a deeper concept, not as mere bugs.
Cost and Risk
A real breakthrough demands rework, schedule pressure, and team buy-in. Not every project can afford it, and timing matters — undertaking one late in a release cycle is dangerous.
Preparation Through Prior Refactoring
Breakthroughs are only possible because earlier rounds of modest refactoring kept the model supple and the team's understanding sharp. A neglected model cannot transform.
Concentration on the Core
Breakthroughs matter most where complexity and business value concentrate — foreshadowing the Core Domain idea of Part IV.
Going Back to Basics
Real breakthroughs challenge fundamental assumptions ("a Loan is divided into Shares"), not surface details. Deep refactoring questions the model's vocabulary itself.
- Breakthrough
- A discontinuous leap in the model's expressiveness that reorganizes the design around a clearer concept.
- Refactoring Toward Deeper Insight
- Refactoring driven by better alignment with domain reality, not code cleanup.
- Supple Design
- A design flexible enough to absorb a breakthrough; introduced in Chapter 10.
- Syndicated Loan
- A large loan funded by multiple lenders, used as Evans's running example.
- Share Pie
- The first model's metaphor for proportional ownership; eventually replaced.
- Facility
- The overall lender commitment, distinguished in the breakthrough from the outstanding loan.
Multiple choice
According to Evans, what makes a real breakthrough possible?
Spot the issue
In the syndicated-loan example, the team modeled loan ownership as proportional Shares. But over time, drawdowns and fees revealed that shares didn't sum cleanly across operations. The team's first instinct was to add increasingly clever reconciliation code. What's the real diagnosis?
Multiple choice
When is it especially dangerous to undertake a breakthrough?
True / False
Breakthroughs typically come from polishing surface details of the model.
Making Implicit Concepts Explicit
Modelers must listen for concepts that are implicit in the domain's language but absent from the model, and promote them to first-class objects. Evans surveys techniques for digging concepts out and gives the Specification pattern as the chapter's flagship example.
Digging Out Concepts
Awkward phrasings, repeated qualifications, and clumsy code signal a missing concept. A word the experts use that has no counterpart in the code is a candidate for promotion.
How to Dig
Listen to experts, scrutinize model inadequacies, contemplate contradictions, and read domain literature (textbooks, regulations, journals) to find vocabulary practitioners already use.
Modeling Constraints Explicitly
Business rules buried inside method bodies should often become named objects or predicates. Hiding constraints in procedural code obscures the rule and prevents reuse.
Modeling Processes as Domain Objects
Some processes are essential domain operations (e.g., "route a cargo") and deserve to be modeled — typically as Services. Purely technical procedures should remain hidden.
The Specification Pattern
A Specification is a predicate-like object that answers "does this candidate satisfy a criterion?" It separates the rule from the object being tested and supports composition.
Three Uses of Specifications
Validation (does this object satisfy?), Selection (find matching objects), and Building-to-Order (create an object that will satisfy the spec). One concept, three applications.
Composite Specifications
Specifications combine via AND, OR, NOT to produce new Specifications. Complex rules become declarative and recombinable.
Translating for Performance
When a Specification crosses persistence boundaries, it can produce a SQL fragment for efficient evaluation — keeping the conceptual model clean while enabling fast queries.
- Implicit Concept
- A domain idea present in expert language but absent from the model.
- Specification
- A predicate object that determines whether another object satisfies a criterion.
- Constraint
- A rule limiting valid states; when complex, lifted into a named domain element.
- Process (as Domain Concept)
- A multi-step domain operation modeled explicitly, typically as a Service.
- Composite Specification
- A Specification built from others via AND/OR/NOT.
- Predicate
- A function returning true/false; the conceptual root of Specification.
Multiple choice
A Specification answers which kind of question?
Multiple choice
The three uses of Specifications Evans names are validation, selection, and:
Spot the issue
A senior developer notices that the experts repeatedly say "preferred customer" — meaning customers with three or more orders and no overdue invoices — but no such concept exists in the code; the rule is duplicated as an `if` statement in five places. What's the recommended fix?
Multiple choice
What does Evans recommend when a Specification must cross persistence boundaries for performance?
Supple Design
Supple Design is Evans's name for a model and code so clear and well-factored that clients can combine its elements with confidence and developers can refactor safely as understanding deepens. The chapter catalogs mutually reinforcing patterns that together make the model ready for the next breakthrough.
Intention-Revealing Interfaces
Name classes, methods, and parameters after what they accomplish in the domain, not how. A client should be able to use an operation without reading the implementation.
Side-Effect-Free Functions
Separate queries from commands: push as much logic as possible into functions that return results without changing state, ideally on Value Objects. Results compose and can be reasoned about safely.
Assertions
State postconditions, invariants, and preconditions explicitly — as runtime checks, unit tests, or documented contracts. When side effects are unavoidable, assertions describe them.
Conceptual Contours
Decompose the design along the natural fault lines of the domain. Repeated refactoring exposes these contours; ad-hoc decomposition obscures them.
Standalone Classes
Reduce a class's dependencies. A class understandable and testable in isolation lowers cognitive load and frees the modeler to reason about it without dragging in the rest of the model.
Closure of Operations
Define operations whose argument and result types match the receiver's type — adding two Money values yields Money, unioning two Sets yields a Set. Eliminates coupling to other concepts.
Declarative Design
Express what the program should do rather than how, ideally via a domain-specific combination grammar (Specifications, predicates). It is fragile without the supple foundations the other patterns provide.
Drawing on Established Formalisms
Borrow conceptual frameworks — algebras, set theory, accounting equations — when they fit. A well-understood formalism is pre-tested by mathematicians or domain experts.
- Supple Design
- A design easy for clients to use and easy for developers to change.
- Intention-Revealing Interface
- Names express purpose so clearly the implementation needn't be read.
- Side-Effect-Free Function
- An operation that computes and returns a result without mutating state.
- Assertion
- A statement of a postcondition, invariant, or precondition that must hold.
- Conceptual Contour
- A natural seam in the domain along which the model decomposes cleanly.
- Standalone Class
- A class with few or no dependencies on other domain concepts.
- Closure of Operations
- An operation on a type whose inputs and result are all that type.
- Declarative Design
- Specifying rules or properties rather than imperative steps.
Multiple choice
What is the defining property of Closure of Operations?
Spot the issue
What supple-design principle is being violated?
class ShoppingCart {
public BigDecimal total() {
BigDecimal sum = computeSum();
log.info("Total computed: " + sum);
applyLoyaltyPoints(sum); // mutates the customer
return sum;
}
}Multiple choice
Intention-Revealing Interfaces mean naming things after:
Multiple choice
Evans says Declarative Design is powerful but fragile without:
Applying Analysis Patterns
Analysis patterns, as developed by Martin Fowler, are reusable groups of concepts that recur across business domains. They are a source of conceptual leverage and shared vocabulary, but they must be adapted to the project's Ubiquitous Language, not copied unchanged.
What Analysis Patterns Are
Reusable conceptual structures from Fowler's *Analysis Patterns* (1996) that capture recurring business-domain configurations, distinct from design patterns which capture technical structures.
Conceptual Leverage
Even when a pattern is not adopted directly, reading it can crystallize a half-formed insight, supply vocabulary, and warn the modeler about pitfalls others discovered firsthand.
Adapt, Do Not Copy
Patterns must be modified to fit the specific domain. Forcing a pattern past where it fits produces a distorted model; pattern-driven design that ignores domain realities backfires.
Worked Example — Accounts and Transactions
Evans applies Fowler's accounting pattern, retaining concepts like Account and Entry but renaming and reshaping to match the project's Ubiquitous Language.
Patterns as Language Source
The vocabulary in an analysis pattern often joins the team's Ubiquitous Language, accelerating communication with experts who already know the standard terms.
Boundary with Design Patterns
Analysis patterns operate at the level of business concepts; design patterns at the level of software construction. Mixing the two confuses the model.
Continue Refactoring
A pattern is a starting point, not an endpoint. Keep refactoring toward deeper insight after applying one, just as with any model element.
- Analysis Pattern
- A reusable group of domain concepts representing a common business situation.
- Fowler's *Analysis Patterns*
- The 1996 book cataloging such patterns across accounting, trading, healthcare, and more.
- Account / Entry / Transaction
- Core concepts from Fowler's accounting pattern.
- Conceptual Leverage
- The benefit gained when a pattern supplies insight, vocabulary, or warnings.
- Pattern Adaptation
- Deliberate adjustment of a pattern's structure and naming to fit the actual domain.
- Design Pattern (contrasted)
- A reusable solution to a technical construction problem, at a different level than analysis patterns.
Multiple choice
What is the key difference between analysis patterns and design patterns?
Spot the issue
A team reads Fowler's accounting analysis pattern and copies the Account, Entry, and Transaction classes verbatim — including terminology that doesn't match how their billing experts talk. Within months, expert conversations and code drift apart. What was the mistake?
True / False
A team that decides not to adopt an analysis pattern can still gain conceptual leverage from reading it.
Multiple choice
After applying an analysis pattern to your model, what should the team do next?
Relating Design Patterns to the Model
Some Gang-of-Four design patterns can pull double duty: useful technical structures that also represent recurring domain concepts and so belong in the model. Strategy (Policy) and Composite are the clearest examples; Flyweight is the counterexample of a purely technical pattern that should stay invisible.
Two Levels of Pattern Use
A pattern can be used as an implementation device (purely technical) or as a way to express a domain concept. Only the latter belongs in the model.
Strategy as Policy
When a domain has variant rules or algorithms (routing policies, pricing policies), modeling them as Strategy objects names the choice in the Ubiquitous Language. Evans prefers "Policy" to emphasize the domain aspect.
Example of Policy
A Route policy that decides how to traverse a network — the variation is a true domain concern, not a programming convenience, so the pattern earns its place.
Composite as a Domain Pattern
When the domain has whole-part hierarchies in which whole and parts share an interface (shipping containers holding containers, org units), Composite captures a real domain structure.
Example of Composite
A shipping route built from legs that are themselves routes — the model can treat any segment uniformly because the recursion is in the domain itself.
Flyweight Is Not a Domain Pattern
Flyweight optimizes memory by sharing instances; it solves no domain problem and should remain an invisible implementation detail. The boundary: a pattern must be domain-meaningful to enter the model.
Naming in the Ubiquitous Language
When a domain pattern is adopted, its name (Policy, Composite) can enter the team's language — but only if it makes sense to domain experts; otherwise a domain-specific name is better.
- Design Pattern
- A named, reusable solution to a recurring software-design problem (Gamma et al.).
- Strategy / Policy
- A pattern encapsulating an interchangeable rule behind a common interface.
- Composite
- A pattern in which composites and leaves share an interface.
- Flyweight
- A memory-sharing pattern Evans cites as not belonging in the domain model.
- Domain Pattern
- A design pattern adopted because it also expresses a recurring domain concept.
- Gang of Four (GoF)
- Gamma, Helm, Johnson, Vlissides, authors of *Design Patterns* (1995).
Multiple choice
According to Evans, why does Flyweight not belong in the domain model?
Multiple choice
Evans prefers to call the Strategy pattern "Policy" in domain models because:
Spot the issue
A developer applies the Composite pattern to wrap a list of `User` objects so a UI dropdown can show a hierarchical view. There is no real whole-part relationship in the domain; she just wanted recursive iteration in the UI. What is the issue?
Multiple choice
A shipping route can be built from legs that are themselves routes. Which pattern earns its place in the domain model?
Refactoring Toward Deeper Insight
The closing chapter of Part III pulls the preceding ideas into an ongoing discipline: refactoring is not a one-time cleanup but a continuous practice aimed at deepening the team's grasp of the domain. Deep models emerge only in teams that keep refactoring.
From Code-Smells to Model-Smells
Classical refactoring fixes code smells; refactoring toward deeper insight responds to model smells — awkward names, missing concepts, hidden constraints — producing a clearer model, not just cleaner code.
Initiation
A refactoring is triggered by a new understanding from a domain expert, a recurring awkwardness, a contradiction between parts of the model, or dissatisfaction with how a concept is currently expressed.
Exploration Teams
Small focused groups, including a domain expert, explore a candidate concept through whiteboard modeling and quick experiments before committing to a refactoring.
Contact with Domain Experts
Ongoing conversation with experts is the primary fuel for refactoring. The model is judged by how well it serves their reasoning, not by aesthetic criteria alone.
Self-Discipline and Timing
Refactoring requires discipline; not every itch should be scratched. The team judges when an insight is mature enough to justify the cost of change.
Continuous Steps, Occasional Breakthroughs
Regular small refactorings keep the design supple, and supple designs are what allow breakthroughs to happen at all. The two practices reinforce each other.
Pitfalls
Beware refactoring without insight (busywork), pattern-chasing, and losing contact with domain experts during long refactorings.
- Model Smell
- A sign the model is failing to express the domain — awkward names, contortions, expert dissatisfaction.
- Exploration Team
- A small, temporary group that investigates a candidate refactoring before broader adoption.
- Domain Expert
- The primary source of insight for model refactorings.
- Deep Model
- A model that captures essential abstractions so the hardest business problems become tractable.
- Continuous Refactoring
- Disciplined, ongoing, insight-driven model changes.
- Initiation
- The triggering moment — new insight, recurring pain, expert correction — that justifies starting a refactoring.
Multiple choice
What is a model smell as opposed to a code smell?
Multiple choice
Who should typically be part of an exploration team investigating a candidate refactoring?
Spot the issue
A team begins an ambitious six-week refactoring to introduce a new core abstraction. To "move fast," they decide to pause all meetings with domain experts until the refactor lands. What's the pitfall?
True / False
Continuous small refactorings and occasional breakthroughs are independent practices; one does not enable the other.
Part 04
Strategic Design
Ch. 14–17
Maintaining Model Integrity
A single unified model for a large system is rarely feasible — different teams interpret the same concepts differently. Evans introduces Bounded Contexts as the fundamental unit of model integrity and a catalog of relationship patterns (mapped together as a Context Map) describing how distinct models can coexist and interoperate.
Bounded Context
Explicitly define the scope — team, codebase, schema, subsystem — within which a particular model applies. Inside the boundary, terms have unambiguous meaning; outside, the same term may mean something different.
Continuous Integration
Within one Bounded Context, merge and reconcile work frequently at both the model-concept and code level so that fragmentation is detected before splinters set in.
Context Map
A document showing every Bounded Context, its name, and the relationships between them including translation points. Without it, teams collide at unmarked boundaries and silently corrupt each other's models.
Shared Kernel
Two teams agree to share a small, explicitly designated subset of the domain model as common ground. Changes require coordination; the kernel stays small to limit that cost.
Customer / Supplier
A clear upstream/downstream relationship where the supplier accepts the customer's requirements into its backlog and runs joint acceptance tests. Both teams cooperate; the customer's needs shape supplier planning.
Conformist
When the downstream has no leverage over the upstream, it conforms slavishly to the upstream model rather than fighting it. Eliminates translation cost — at the price of accepting whatever quality the upstream offers.
Anticorruption Layer
An isolating translation tier the downstream builds to convert the upstream model into its own terms, defending against foreign concepts. Combines Facades, Adapters, and translators.
Separate Ways, Open Host Service, Published Language
Separate Ways: declare no integration at all. Open Host Service: define a protocol once for many consumers. Published Language: use a well-documented shared interchange language, often paired with Open Host Service.
- Bounded Context
- The delimited applicability of a particular model.
- Context Map
- Representation of all Bounded Contexts and their relationships.
- Continuous Integration
- Frequent merging within a Bounded Context to maintain coherence.
- Shared Kernel
- A small intentionally shared subset of the model used in common by two teams.
- Customer / Supplier
- Upstream/downstream relationship where supplier accommodates customer needs.
- Conformist
- A downstream team that adopts the upstream model wholesale.
- Anticorruption Layer (ACL)
- Isolating translation tier protecting one model from another.
- Open Host Service (OHS)
- A published protocol allowing many downstreams uniform access.
- Published Language
- A documented shared language as the medium of translation between contexts.
Multiple choice
What does a Bounded Context explicitly define?
Spot the issue
Two teams integrate by directly importing each other's domain classes. A "Customer" object from the CRM context is used inside the Billing context, where billing-specific rules creep into the CRM class. Soon billing concepts pollute CRM and vice versa. What pattern would have prevented this?
Multiple choice
In a Customer / Supplier relationship between contexts:
Multiple choice
A downstream team has no leverage over an upstream team's roadmap and decides to mirror the upstream model exactly to eliminate translation cost. Which pattern is that?
True / False
Without a Context Map, teams typically still collaborate effectively because boundaries are implicit and well understood.
Distillation
Not all parts of a model are equally valuable. Distillation is the process of identifying the Core Domain — the differentiator that justifies custom software — and aggressively separating it from supporting concerns so the best people and richest modeling effort can focus there.
Core Domain
The small portion of the model that captures the business's competitive advantage and is the reason custom software is being written. Assign your best designers; refactor it most aggressively; never outsource it.
Generic Subdomains
Cohesive parts of the model that are not specific to the business (time zones, currency, generic accounting). Factor into separate modules, use off-the-shelf solutions when possible, don't waste top talent on them.
Domain Vision Statement
A short (about one page) document describing the Core Domain and the value it brings — what it does, why it matters, the trade-offs it makes. Written early, kept stable, used to guide resource allocation.
Highlighted Core
Make the Core visible to everyone — via a distillation document that names and walks through core elements, or by flagging core elements in the code. Counters the tendency for the Core to be lost in the surrounding mass.
Cohesive Mechanisms
Encapsulate complex algorithmic machinery (graph traversal, math, state engines) behind intention-revealing interfaces so the model expresses *what* without being polluted by *how*. Mechanisms support the Core; they are not the Core.
Segregated Core
Refactor the model so the Core is physically separated into its own modules, pulling out tangled supporting code. The pain is outweighed by the clarity gained in the Core.
Abstract Core
Lift the most essential abstractions (interfaces, abstract classes) into a separate module depending on no concretes. The Abstract Core resembles the distillation document made executable.
Strategic Value of Distillation
Distillation directs effort to vital parts, clarifies the overview, guides refactoring, and informs decisions about outsourcing and off-the-shelf adoption.
- Core Domain
- The distinctive, business-critical part of the model where the system's value concentrates.
- Generic Subdomain
- A cohesive supporting area not specific to the business; separable and often replaceable.
- Domain Vision Statement
- Brief written summary of the Core Domain's nature and value.
- Highlighted Core
- A distillation document and/or in-code flagging that makes the Core visible.
- Cohesive Mechanism
- A self-contained algorithm hidden behind an intention-revealing interface.
- Segregated Core
- A refactoring that physically separates Core elements into dedicated modules.
- Abstract Core
- A module of pure abstractions capturing the Core's essential concepts.
- Distillation Document
- A short narrative summarizing the Core's main objects and interactions.
Multiple choice
What defines the Core Domain?
Spot the issue
A company assigns its strongest engineers to rewrite a generic time-zone conversion module while interns are handed the company's pricing-engine model — the very thing that differentiates the business. What's the distillation error?
Multiple choice
A Domain Vision Statement is best described as:
Multiple choice
What is the role of a Cohesive Mechanism?
Large-Scale Structure
Even with bounded contexts and a distilled core, a very large system can be incomprehensible at the macro level. A Large-Scale Structure is a set of high-level rules or roles that lets a developer understand any part in relation to the whole. Evans is emphatic: it is better to have no large-scale structure than one that doesn't fit.
Large-Scale Structure
A system-wide pattern of rules, roles, or relationships that gives every part a place in the whole, letting developers reason about elements in context. Communicated through the Ubiquitous Language, applied across Bounded Contexts.
Evolving Order
Reject fixed up-front architectures. Let the structure emerge with the application, accepting it may need to change to a different kind of structure entirely. Free-for-alls produce incoherence; rigid up-front structure suffocates.
System Metaphor
When the team naturally adopts a metaphor (firewall, pipes-and-filters), make it explicit and weave it into the Ubiquitous Language. Use carefully — metaphors mislead when pushed too far.
Responsibility Layers
Partition the domain by conceptual dependency and rate of change into stacked layers with broad responsibilities — Evans's examples: *Potential, Operation, Decision Support, Policy, Commitment*. Each layer knows only those below.
Knowledge Level
A two-tier pattern where one group of objects describes and constrains how another behaves. The Knowledge Level holds the rules; the Operational Level applies them. Used when the software must represent multiple variant configurations.
Pluggable Component Framework
When many independently developed components must collaborate, distill an Abstract Core of interfaces and rules all plug-ins conform to. Powerful but demands deep up-front domain understanding — attempt only after a mature model exists.
Minimalism and Fit
Large-scale structure should constrain the design just enough to clarify it. Trying to be comprehensive produces "a dead, suffocating blanket"; structures must be allowed to relax or change when they stop fitting.
- Large-Scale Structure
- A high-level conceptual organization giving a coherent shape to a whole system.
- Evolving Order
- Principle that structure should emerge and change with the system rather than be imposed up front.
- System Metaphor
- An explicit shared analogy adopted into the Ubiquitous Language.
- Responsibility Layers
- A structure dividing the domain into stacked layers, references flowing downward.
- Knowledge Level
- A pattern where one set of objects describes and parameterizes another.
- Pluggable Component Framework
- A structure built on an Abstract Core enabling independent components to interoperate.
Multiple choice
According to Evans, what is preferable to a large-scale structure that doesn't fit the system?
Spot the issue
A new CTO mandates a fixed layered architecture (Potential / Operation / Decision Support / Policy / Commitment) on day one of a greenfield project before any model has emerged. Eighteen months in, the layers fit some subsystems and suffocate others, but no one is allowed to change them. What principle was violated?
Multiple choice
The Knowledge Level pattern is best used when:
Multiple choice
When should a team attempt a Pluggable Component Framework?
Bringing It All Together
The concluding chapter shows how Bounded Context, Distillation, and Large-Scale Structure combine in practice, and how teams can make decisions about them. Evans then offers six essentials for any group responsible for strategic design, emphasizing that strategy must serve — not dominate — the development teams.
Combining Structure and Contexts
A Large-Scale Structure (e.g., Responsibility Layers) may span multiple Bounded Contexts; a Bounded Context may sit inside one layer or span several. Context Map and structure together let teams locate any piece.
Combining Structure and Distillation
The Core Domain may sit in a particular layer; a Pluggable Component Framework may itself be an Abstract Core. The two reinforce each other: structure clarifies where the Core lives; the Core's prominence justifies parts of the structure.
Assessment First
Before applying strategic design, map current Bounded Contexts warts and all, evaluate translations, examine what the Ubiquitous Language is doing. Strategy addresses actual problems, not imagined elegance.
Decisions Reach the Team
Strategic decisions must be communicated and understood throughout development — through formal architecture teams, or by strategy emerging from developers themselves. Either way, the decision must travel.
Feedback and Evolution
The decision process absorbs feedback from those doing the work (rotate architects through dev teams), and the plan allows evolution as understanding deepens. Strategy that cannot bend will be ignored or break.
Architecture Teams Must Not Siphon Talent
Application work also needs deep designers. An isolated architectural elite produces designs detached from reality and starves the place where the model actually lives.
Minimalism, Humility, and Generalist Developers
Strategic design demands minimalism (only essential structure) and humility (your best idea will obstruct someone). Objects are specialists with narrow responsibilities; developers are generalists with breadth across domain, design, and architecture.
- Strategic Design
- The body of practice addressing the system at the largest scale: Contexts, Distillation, Large-Scale Structure.
- Combining Strategies
- Applying Bounded Contexts, Distillation, and Large-Scale Structure together rather than in isolation.
- Six Essentials
- Evans's guidelines for how a team responsible for strategic design should operate.
- Architecture Team
- A group with strategic-design authority; effective only if connected to development.
- Minimalism (Strategic)
- Imposing the least structure that produces clarity.
- Humility (Strategic)
- Recognizing that strategic decisions inevitably constrain working developers.
Multiple choice
Before applying strategic design, what should a team do first?
Spot the issue
A company forms an "Architecture Council" of its most senior designers, who spend their days producing strategic-design diagrams. Meanwhile the application teams — staffed with juniors — struggle to model the Core Domain. After a year, the council's plans don't match anything that ships. What went wrong?
Multiple choice
Evans says objects are specialists with narrow responsibilities. What does he say about developers?
Multiple choice
A Large-Scale Structure and a Bounded Context can relate in which way?
True / False
Strategic decisions can succeed even if they never reach the development teams doing the work.
Key Takeaways
Complex software lives or dies by the depth of its domain model; technical brilliance cannot rescue a project from a shallow understanding of the business.
A Ubiquitous Language shared by developers and domain experts — spoken, written, and embedded in code — is the connective tissue of every successful model-driven design.
Isolate the domain into its own layer and express it with tactical building blocks (Entities, Value Objects, Services, Aggregates, Factories, Repositories) so the model can drive the implementation.
Refactor toward deeper insight: model smells, awkward language, and implicit concepts are invitations to a breakthrough that reshapes the model.
Supple design (intention-revealing interfaces, side-effect-free functions, assertions, closure of operations) keeps the model malleable enough to absorb new understanding.
At scale, integrity demands explicit Bounded Contexts, a Context Map, distillation of the Core Domain, and only as much large-scale structure as truly fits.