Domain-Driven Design
Modelling the business the way the business describes it, and drawing boundaries where the language changes.
The Model Is The Point
The ubiquitous language is where it starts: the same words in conversation, in the model, in the code and in the database. When a domain expert says "a policy lapses", there is a Policy with a lapse() operation — not a StatusUpdateService setting a flag to 3.
Entities, Value Objects & Aggregates
| Concept | Identity | Example |
|---|---|---|
| Entity | Has an id; two with the same fields are still different | Customer, Order |
| Value object | Defined entirely by its values; interchangeable | Money, DateRange, Address |
| Aggregate | A cluster with one root that guards its invariants | Order with its lines |
| Repository | Loads and stores whole aggregates | OrderRepository |
| Domain event | Something the business cares that happened | OrderPlaced |
# a value object: immutable, compared by value, and it protects its own rules
@dataclass(frozen=True)
class Money:
amount: int # minor units — never a float
currency: str
def __add__(self, other: "Money") -> "Money":
if self.currency != other.currency:
raise ValueError("cannot add different currencies")
return Money(self.amount + other.amount, self.currency)
The aggregate is the idea that earns its place fastest. It defines a consistency boundary: everything inside is saved together and its invariants always hold, and anything outside is referenced by id and updated separately. That single rule answers most "should this be one transaction" questions.
Bounded Contexts
The strategic half, and the more valuable one. A bounded context is a boundary within which a model and its language are consistent. "Customer" means something different to billing, to support and to marketing — forcing one shared definition produces a model that serves none of them.
| Context | "Customer" means |
|---|---|
| Sales | A prospect with a pipeline stage |
| Billing | A payment method and a tax jurisdiction |
| Support | A person with a contact history and entitlements |
| Shipping | An address and delivery preferences |
Context mapping then names the relationships: which context is upstream, who conforms to whose model, and where a translation layer sits between them. An anti-corruption layer is the pattern that keeps a legacy or supplier model from leaking into a clean one.
When It Is Worth It
| Suits DDD | Does not |
|---|---|
| Complex, contested business rules | CRUD over forms |
| A long-lived system with real domain experts | A short-lived internal tool |
| Language that differs across departments | One obvious shared model |
| Rules that change more than the technology | Technology that changes more than the rules |
Applied to a simple CRUD application, DDD produces four layers of ceremony around a database table. That is the criticism people make of it, and on those systems they are right.
Interview Questions
What is the ubiquitous language?
One vocabulary shared by domain experts, the model and the code. It removes the translation step where knowledge is lost and the two vocabularies drift apart.
Entity or value object?
An entity has identity that persists through change; a value object is defined entirely by its values and is interchangeable. Money and date ranges are value objects; a customer is an entity.
What does an aggregate define?
A consistency boundary: one root, invariants that always hold, saved as a unit. Anything outside it is referenced by id and updated in a separate transaction.
Why keep aggregates small?
A large aggregate means every change locks and loads all of it, creating contention and slow writes. Small aggregates with id references keep transactions narrow.
What is a bounded context?
A boundary within which one model and one language are consistent. "Customer" legitimately means different things to billing and support, and each context keeps its own definition.
When is DDD the wrong choice?
On CRUD applications and short-lived tools with a simple shared model. The strategic patterns cost real time and only repay where the domain rules are genuinely complex and contested.