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


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.

LayerWithout ubiquitous languageWith ubiquitous language
PRD”democratic tool""instrument”
Databaseentity tableinstrument table
API/api/resources/api/instruments
UI”Browse tools""Browse instruments”
Codeclass Resourceclass 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.

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

ConceptWhat it coversStatus
ubiquitous-languageHow to establish and maintain a shared vocabulary across a projectstub
bounded-contextsHow to identify and draw boundaries between parts of a systemstub
entities-and-value-objectsHow to model objects with identity vs. objects defined by their attributesstub
aggregatesHow to group entities and value objects into consistency boundariesstub

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


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:#fff

Related 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