Domain-Driven Design (DDD)
An approach to software design that centres the code around the real-world concepts it models, using the same language that domain experts use — so the code reads like a description of the problem, not like an abstract technical exercise.
What is Domain-Driven Design?
Domain-Driven Design is the idea that your software should mirror the world it represents. If you’re building software for a hospital, the code should talk about patients, diagnoses, and treatments — not “entities,” “resources,” and “items.” If you’re building software for an e-commerce platform, the code should talk about orders, products, and customers.
Eric Evans introduced DDD in his 2003 book. The central insight was simple but powerful: the biggest source of bugs and confusion in software isn’t bad algorithms — it’s the gap between how domain experts talk about the problem and how developers model it in code. Close that gap, and most complexity disappears.
DDD has two layers. Strategic DDD is about organising a large system into coherent parts (bounded contexts) that each own their own vocabulary. Tactical DDD is about modelling the objects within each part (entities, value objects, aggregates). For most beginners, the strategic concepts — especially ubiquitous language and bounded contexts — are the ones that deliver the most value with the least overhead.
In plain terms
DDD is like labelling every jar in your kitchen with exactly what’s inside. If the jar says “flour,” everyone in the kitchen calls it flour — not “powder,” not “ingredient #3,” not “baking base.” When the recipe says “flour,” the chef grabs the jar labelled “flour.” No translation needed, no confusion, no mistakes.
At a glance
The core DDD concepts (click to expand)
graph TD DDD[Domain-Driven Design] --> SL[Ubiquitous Language] DDD --> BC[Bounded Contexts] DDD --> TM[Tactical Modelling] SL -.- SLN["Same words everywhere:<br/>code, docs, UI, database"] BC -.- BCN["System divided into<br/>areas with own vocabulary"] TM --> E[Entities] TM --> VO[Value Objects] TM --> AG[Aggregates] style DDD fill:#4a9ede,color:#fffKey: DDD has two strategic concepts (ubiquitous language and bounded contexts) that organise the big picture, and tactical patterns (entities, value objects, aggregates) that shape the internal structure. For most projects, the strategic layer is where the real value lives.
How does Domain-Driven Design work?
DDD works through three core ideas, each building on the previous one.
1. Ubiquitous language
Everyone uses the same words for the same things — everywhere. The product manager, the developer, the AI agent, the database schema, the API, and the UI all use identical terminology. There is no “translation layer” between business language and code language.
| Layer | Without ubiquitous language | With ubiquitous language |
|---|---|---|
| PRD | ”democratic tool" | "instrument” |
| Database | entity table | instrument table |
| API | /api/resources | /api/instruments |
| UI | ”Browse tools" | "Browse instruments” |
| Code | class Resource | class Instrument |
When someone says “instrument,” everyone knows exactly what it means. No one has to mentally translate between “resource” in the API and “tool” in the UI and “entity” in the database.
Think of it like...
A multilingual meeting where everyone agrees to speak one language. If the accountant says “revenue” and the engineer hears “revenue” and the report shows “revenue,” there’s zero room for misunderstanding. The moment someone starts using synonyms (“income,” “earnings,” “proceeds”), confusion creeps in.
Concept to explore
See ubiquitous-language for how to establish and maintain a shared vocabulary across a project.
2. Bounded contexts
Different parts of a system may need different vocabularies.
A “customer” in the billing system (credit card, invoices, payment
history) is not the same object as a “customer” in the support
system (tickets, satisfaction score, response time). Trying to
cram both into one Customer class creates a bloated, confusing
model.
Bounded contexts solve this by drawing explicit boundaries. Inside each boundary, the vocabulary is consistent and unambiguous. Between boundaries, a translation layer handles the mapping.
Example: e-commerce platform
An online store has several bounded contexts:
Context ”Order” means… Shopping Items in a cart, not yet purchased Checkout A payment transaction being processed Fulfilment A package to pick, pack, and ship Accounting A revenue entry with tax implications Same word, four different meanings. Each context owns its definition. A single
Orderclass trying to serve all four would be unmaintainable.
Think of it like...
The word “set” in English. In tennis it means one thing, in mathematics another, and in a dining room another. Context determines meaning. Bounded contexts make the “which meaning?” question explicit in code, not implicit.
Concept to explore
See bounded-contexts for how to identify, draw, and maintain context boundaries in a system.
3. Tactical patterns — entities and value objects
Inside each bounded context, DDD provides patterns for modelling the objects.
Entities have a unique identity that persists over time. An entity is “the same thing” even if all its attributes change.
- A user account is an entity — it has an ID. Even if the user changes their name and email, it’s still the same account.
- A book in a library is an entity — it has a catalogue number. Even if you update the description, it’s the same book.
Value objects are defined by their attributes, not by identity. Two value objects with the same attributes are interchangeable.
- A mailing address is a value object — “123 Main St, Zurich” is the same address regardless of where it appears.
- A money amount is a value object — CHF 50 is CHF 50, no matter which transaction it belongs to.
The identity test
Ask: “If I change every attribute, is it still the same thing?” If yes (because it has an ID), it’s an entity. If no (because it’s defined by its values), it’s a value object.
Concept to explore
See entities-and-value-objects for detailed patterns, examples, and common mistakes when modelling each.
Why do we use Domain-Driven Design?
Four problems DDD solves
1. Translation errors. When the PRD says “instrument” but the code says “resource,” every handoff between business and engineering risks a misunderstanding. Ubiquitous language eliminates the translation layer entirely.
2. Bloated models. Without bounded contexts, a single object tries to serve every part of the system and grows into an unmaintainable monster. Bounded contexts keep models focused and independent.
3. AI agent confusion. An AI agent generates better code when the domain vocabulary is consistent. If “instrument” means the same thing in the PRD, the schema, and the prompt, the agent’s output is more accurate and needs fewer corrections.
4. Onboarding friction. A codebase that uses domain language is self-documenting. A new developer (or a new AI session) can read the code and understand the business logic without needing a separate glossary.
When do we use DDD?
- When the business domain is complex enough to justify modelling (more than CRUD)
- When domain experts and developers need to collaborate closely
- When the system has multiple sub-systems that use overlapping terminology
- When working with AI agents that benefit from consistent vocabulary across code, docs, and prompts
- When the codebase needs to be understandable by non-engineers (product managers, stakeholders)
Rule of thumb
If the hardest part of your project is understanding the domain (not the technology), DDD will help. If the hardest part is performance or infrastructure, DDD might be overkill.
How can I think about it?
The hospital ward
DDD is like running a hospital ward.
- Ubiquitous language: Doctors, nurses, and administrators all use the same medical terminology. “Tachycardia” means the same thing on the chart, in the handoff, and in the discharge notes. Nobody calls it “fast heartbeat” in one place and “elevated BPM” in another.
- Bounded contexts: The same patient is modelled differently in different departments. To the ER, they’re a triage case (severity, symptoms). To billing, they’re an insurance claim (coverage, procedures). To the lab, they’re a set of samples (blood type, results). Each department owns its own model.
- Entities: The patient is an entity — they have a medical record number. Even if their address and phone change, they’re the same patient.
- Value objects: A blood pressure reading (120/80) is a value object — it has no identity of its own, just values.
The city map
DDD is like creating a city map for different audiences.
- Ubiquitous language: Every map labels “Rue de Bourg” the same way. The tourist map, the bus map, and the utility map all use the same street names. No map invents its own names for streets.
- Bounded contexts: But each map shows different things. The tourist map shows landmarks and restaurants. The bus map shows routes and stops. The utility map shows pipes and cables. Same city, different models — each optimised for its audience.
- Entities: A building is an entity — it has an address. Even if it’s renovated, it’s the same building.
- Value objects: A GPS coordinate (46.519, 6.632) is a value object — it describes a location, not a named thing.
DDD says: agree on the street names (ubiquitous language), but let each map show what matters to its users (bounded contexts).
Concepts to explore next
| Concept | What it covers | Status |
|---|---|---|
| ubiquitous-language | How to establish and maintain a shared vocabulary across a project | stub |
| bounded-contexts | How to identify and draw boundaries between parts of a system | stub |
| entities-and-value-objects | How to model objects with identity vs. objects defined by their attributes | stub |
| aggregates | How to group entities and value objects into consistency boundaries | stub |
Some of these cards don't exist yet
They’ll be created as the knowledge system grows. A broken link is a placeholder for future learning, not an error.
Check your understanding
Test yourself (click to expand)
- Explain what Domain-Driven Design is to someone who has never written code. Use the kitchen jar or hospital analogy.
- Name the three core DDD concepts covered in this card and describe what problem each one solves.
- Distinguish between an entity and a value object. Give two examples of each from a domain you know (library, restaurant, school).
- Interpret this scenario: a team’s database calls it
resource, the API calls it/tools, and the UI says “instruments.” What DDD principle is being violated, and what problems will this cause?- Connect this concept: how does DDD’s ubiquitous language improve the quality of a technical-specification?
Where this concept fits
Position in the knowledge graph
graph TD SD[Software Development] --> SA[Software Architecture] SA --> DDD[Domain-Driven Design] SA --> SOC[Separation of Concerns] DDD --> UL[Ubiquitous Language] DDD --> BC[Bounded Contexts] DDD --> EVO[Entities & Value Objects] DDD --> AGG[Aggregates] style DDD fill:#4a9ede,color:#fffRelated concepts:
- prd — the PRD establishes the domain vocabulary that DDD carries through to code, database, and UI
- technical-specification — specs written with DDD vocabulary are clearer because terms mean the same thing everywhere
- apis — API endpoints should use domain language (
/instruments) not generic terms (/resources)
Further reading
Resources
- Domain Driven Design (DDD) for Beginners (Mariem Moalla) — Beginner-friendly introduction covering all key concepts with clear examples
- Introduction to Domain-Driven Design (Software System Design) — Comprehensive overview with emphasis on strategic and tactical patterns
- Ubiquitous Language (Software System Design) — Deep dive into the most impactful DDD concept with practical guidance
- Domain-Driven Design Quickly (InfoQ) — Free condensed summary of Eric Evans’ original book
- From Chaos to Clarity: A Beginner-Friendly Introduction to DDD (LinkedIn) — Practical walkthrough with analogies and worked examples
