| name | book--implementing-domain-driven-design--full |
| description | Implementing DDD (Vaughn Vernon) — Full rules — comprehensive mandatory coding standards. Use when asked to apply Implementing DDD principles or review code against Implementing DDD standards. |
| origin | github.com/ciembor/agent-rules-books (MIT) |
| license | MIT |
| version | 1.0.0 |
| compatibility | yana-ai >= 0.14.0 |
OBEY Implementing Domain-Driven Design by Vaughn Vernon
Purpose
This repository follows Implementing Domain-Driven Design in the practical style of Vaughn Vernon:
apply DDD operationally, with explicit bounded contexts, disciplined aggregates, and implementation patterns that survive real systems.
All code generation, edits, and reviews must optimize for:
- explicit bounded contexts
- local ubiquitous language
- small aggregate boundaries
- identities over object graph coupling
- eventual consistency where appropriate
- context mapping instead of shared muddled models
- practical DDD implementation instead of theory theater
This file is a binding engineering policy: MUST is binding, SHOULD is a strong default, and MUST NOT is forbidden.
Primary Directive
Model the domain in a way that can actually be implemented and evolved.
When uncertain:
- identify the bounded context
- use the local ubiquitous language
- define the aggregate consistency boundary conservatively
- reference other aggregates by identity
- keep infrastructure outside the model
- integrate across contexts through explicit translation
Reject designs that sound like DDD but behave like generic CRUD plus renamed classes.
Strategic Design Rules
Bounded Context Is Mandatory
- Every substantial domain area must belong to a named bounded context.
- A model is valid only inside its bounded context.
- Terms may change meaning across contexts; that is normal and must be respected.
- Do not share model classes across contexts by default.
Context Mapping Is a Design Artifact
- Every context interaction must have an explicit relationship.
- Translation responsibility must be visible.
- Upstream/downstream influence matters.
- External models, partner systems, and legacy systems must not define the local model.
Core Domain Protection
- Protect the core domain from generic abstractions and vendor terms.
- Spend the richest modeling effort where competitive or operational complexity truly lives.
- Keep supporting subdomains simpler.
Anti-patterns (MUST NOT):
- one global company model
- shared domain package crossing all contexts
- context boundaries existing only in diagrams but not in code
- context integration via direct imports of each other's domain classes
Ubiquitous Language Rules
- Use business terms exactly as they are understood in the current bounded context.
- One concept gets one term inside the context.
- One term must not carry multiple meanings inside the same context.
- Rename code when understanding improves.
- Tests, events, commands, repositories, and application services must all speak the same language.
Required behavior:
- use local domain terms in class, method, event, and package names
- remove technical placeholders when a real domain term exists
Aggregate Rules of Thumb
Aggregates Are Consistency Boundaries
- Design aggregates around invariants that must hold immediately.
- Keep aggregates as small as possible.
- Small aggregates scale better in both understanding and throughput.
- Large object graphs are not evidence of good modeling.
Aggregate Root Discipline
- Only the aggregate root may be referenced directly from outside.
- All invariant-changing operations must go through the root.
- Internal members must not be mutated directly by external code.
- Expose intention-revealing behavior, not arbitrary setters.
Reference Other Aggregates by Identity
- Prefer IDs over direct object references across aggregate boundaries.
- Avoid loading large connected graphs by default.
- Cross-aggregate coordination should usually be eventual, not transactional.
One Aggregate per Transaction by Default
- Modify one aggregate in one transaction unless there is a compelling reason not to.
- Do not stretch transactions across many aggregates out of convenience.
- Use events, policies, or process coordination when consistency can be eventual.
Anti-patterns (MUST NOT):
- aggregates sized to fit ORM navigation
- transactions updating many aggregates by default
- aggregate roots exposing mutable child collections
- direct cross-aggregate navigation baked into the model
Entity and Value Object Rules
Entities
- Use entities where identity and lifecycle matter.
- Entities must protect meaningful state transitions.
- Entity methods must express domain behavior, not generic state changes.
- Entities must not be passive ORM containers in behavior-rich domains.
Value Objects
- Use value objects aggressively where primitives hide meaning.
- Value objects must be immutable by default.
- Validation belongs in value object construction.
- Equality is by value, not identity.
Required behavior:
- model local value concepts explicitly instead of passing raw primitives for meaningful identifiers, quantities, ranges, names, or descriptive whole values
- keep invariant enforcement near the concept itself
Domain and Transformation Service Rules
- Use a domain service for a domain-significant operation that requires multiple domain objects and fits no single entity or value object.
- Name domain services in the ubiquitous language.
- Use transformation services when domain information must be transformed without assigning behavior to the wrong object.
- Keep technical transformation, serialization, transport, and persistence mapping outside the domain model.
Anti-patterns (MUST NOT):
- moving behavior into services to avoid modeling entities or value objects
- hiding technical mapping behind a domain-sounding service name
Repository Rules
- Repositories exist for aggregate roots.
- Repository interfaces must be defined by the domain or application code that needs them.
- Repositories reconstitute and persist aggregates.
- Repository APIs should reflect aggregate access needs, not generic table CRUD.
- Repositories must return domain objects or domain-oriented results, not ORM rows.
Anti-patterns (MUST NOT):
- giant generic repository abstractions
- repository per table without aggregate thinking
- business rules inside repository implementations
- repositories returning persistence-layer entities into the domain
Domain Event Rules
- Publish domain events for meaningful business facts.
- Event names must be in the past tense.
- Domain events are part of the model, not transport mechanics.
- Use events to coordinate across aggregates or contexts when immediate consistency is not required.
- Keep event payloads meaningful and local to the model.
Event Sourcing
- Use event sourcing only when storing the sequence of domain events is the right persistence model for the aggregate.
- Keep event streams consistent with aggregate identity and versioning.
- Rebuild state from events deterministically.
- Version events and upcasters or translators when event meaning evolves.
- Do not choose event sourcing just because domain events exist.
Anti-patterns (MUST NOT):
- using events for every property change
- event names that describe commands instead of facts
- domain events carrying framework request objects or persistence artifacts
- using events to compensate for missing aggregate design
Application Service Rules
- Application services coordinate use cases.
- They load aggregates, invoke domain behavior, persist results, and publish resulting events.
- Application services must not contain the domain model's core decision logic.
- Application services must be thin enough that the model still matters.
- Application services may own transaction boundaries and integration coordination.
Anti-patterns (MUST NOT):
- application services containing all branching business rules
- controllers duplicating application service orchestration
- repositories and application services both implementing the same invariants
Module and Package Rules
- Packages/modules must reflect bounded contexts first.
- Within a context, organize around domain and use-case ownership, not only technical layers.
- Avoid a giant
shared or common package for domain concepts.
- Keep the model visible in the structure.
Preferred structure examples:
identity/domain
identity/application
identity/infrastructure
identity/interfaces
Context Integration Rules
Anticorruption Layer
Use when integrating with legacy systems or foreign models.
Rules (MUST unless marked SHOULD or MUST NOT):
- Translate foreign language into the local context's language.
- Keep foreign schemas and statuses out of local domain objects.
- Own the translation explicitly.
Identity Across Contexts
- Use explicit identifiers and integration messages.
- Do not pass local aggregates directly across context boundaries.
- Keep contract models separate from local models.
Anti-patterns (MUST NOT):
- importing another context's domain package
- shared enums across contexts with different semantics
- direct DB coupling between contexts
Client Representation and Scope Discipline
- Use DTOs, projections, use-case queries, rendition adapters, or mediators when client needs differ from aggregate shape.
- Expose REST resources as application-facing representations rather than aggregate internals.
- Tailor representations for different clients without changing the domain model for each client.
- Compose multiple bounded contexts at the application or integration layer, not by merging their models.
- Keep command behavior separate from query models when consistency, performance, or representation needs justify the split.
- Keep scope identifiers explicit where context or ownership affects invariants or access.
Practical Simplicity Rule
- Not every subdomain needs full-blown DDD ceremony.
- Use richer modeling where complexity is real.
- Use simpler patterns in supporting areas.
- However, once invariants and lifecycle complexity appear, model them honestly.
Anti-patterns (MUST NOT):
- using DDD vocabulary without changing design
- over-modeling trivial CRUD subdomains
- refusing to model real complexity because “simple services are enough”
Code Generation Rules
When generating code, follow this order:
- identify the bounded context
- state the ubiquitous language term(s)
- determine whether the concept is entity, value object, aggregate root, domain event, repository, or application service
- define aggregate boundary conservatively
- reference other aggregates by ID
- place invariants on the aggregate root or local model
- define repositories around aggregate access
- define application services around use cases
- define translation layers for context or infrastructure boundaries
Avoid by default:
- direct cross-context model reuse
- ORM-shaped aggregates
- all-powerful application services
- generic repositories
- one transaction touching many aggregates
- shared domain packages across contexts
Review Rules
When reviewing or modifying code, actively look for:
- missing bounded context ownership
- context bleeding
- shared models across different contexts
- foreign vocabularies polluting the local context
- oversized aggregates
- aggregate roots not protecting invariants
- external code mutating aggregate internals
- cross-aggregate references by object instead of identity
- events that are really commands
- repository contracts shaped like table CRUD
Testing Rules
- Test aggregate invariants directly.
- Test valid and invalid state transitions.
- Test value object validation and behavior.
- Test domain events as outcomes of domain behavior.
- Test repositories as infrastructure separately from aggregate rules.
- Test anticorruption and translation layers explicitly.
- Test application services for orchestration, not for all domain decisions.
Review Checklist
Before finalizing any change, verify:
- Is the bounded context explicit?
- Is the local ubiquitous language used consistently?
- Are aggregates small and centered on immediate invariants?
- Are cross-aggregate references by identity?
- Does one transaction usually modify one aggregate?
- Are repository interfaces aggregate-oriented?
- Are domain events facts rather than commands?
- Are application services orchestrating rather than owning the model?
- Are foreign models translated explicitly?
- Did we avoid shared-model shortcuts across contexts?
If any answer is no, revise before shipping.
Final Instruction
When uncertain, choose the option that:
- protects the bounded context
- keeps aggregates small
- keeps identities explicit
- preserves local language
- moves cross-boundary coordination toward events and translation rather than shared object graphs
Reject DDD theater and model the real operational domain.