Domain-Driven Design
Model software around the business domain using a shared language, clear boundaries, and rich building blocks that reflect real-world concepts.
Ubiquitous Language
A single, shared vocabulary used by domain experts and developers alike — in code, tests, conversations, and documentation.
Rule: If a developer needs to "translate" when talking to a domain expert, the model is wrong. Rename the code to match the business language.
Entity vs Value Object
Two fundamental domain building blocks with different identity rules and mutability contracts.
Rule: If two instances can exist with the same data but are still different things (a user account), use an Entity. If two instances with the same data are interchangeable (a price), use a Value Object.
Aggregate & Aggregate Root
A cluster of domain objects treated as a single unit. The Aggregate Root is the only entry point — it owns and protects all invariants.
Rule: External objects may only hold a reference to the root. Never reference inner entities or value objects directly — all changes must flow through the root.
Bounded Context
An explicit boundary within which a domain model is defined and applies. The same term can mean different things in different contexts — and that's fine.
Example: the concept "User" across three contexts
- id: UUID
- email: string
- password: hashed
- roles: string[]
- last_login_at
- id: UUID
- plan: string
- payment_method
- invoices: Invoice[]
- billing_address
- id: UUID
- name: string
- avatar_url
- bio: string
- preferences: []
Rule: Each bounded context owns its model. Contexts communicate through explicit integrations (shared IDs, domain events, or an anti-corruption layer) — never through shared databases or shared objects.
Domain Events
A domain event records something notable that happened in the domain. It decouples the trigger from the side effects.
Rule: Domain events decouple the cause from the effect. The emitter doesn't know (or care) who's listening — adding a new handler never changes the domain logic.
Layered Architecture
DDD organizes code into four layers. The Domain layer is the center — it has zero dependencies on any other layer.
Rule: Dependencies always point inward — toward the Domain. The Domain knows nothing about the database, framework, or HTTP. This makes the core logic portable and independently testable.