Domain-Driven Design Skill
Apply DDD to build software that reflects deep understanding of the business domain.
Quick Reference
| Task |
Reference |
| Bounded contexts, subdomains, context maps |
strategic-design.md |
| Entities, value objects, aggregates, repositories |
tactical-design.md |
| Hexagonal, CQRS, Event Sourcing, Clean Architecture |
architecture-patterns.md |
| Event Storming facilitation & documentation |
event-storming.md |
| Python implementations (Pydantic, SQLAlchemy, FastAPI) |
python-patterns.md |
| TypeScript implementations (NestJS, TypeORM, Prisma) |
typescript-patterns.md |
| DDD code review criteria |
code-review.md |
Core Workflow
1. Identify the Task Type
Designing new system? → Start with strategic design, then tactical
Refactoring existing code? → Assess current state, identify bounded contexts, refactor incrementally
Generating scaffolding? → Determine patterns needed, generate code
Event Storming? → Follow facilitation guide
Code review? → Apply DDD checklist
2. Strategic Before Tactical
Always establish strategic design first:
- Identify subdomains (Core, Supporting, Generic)
- Define bounded contexts and their boundaries
- Map context relationships (upstream/downstream, conformist, ACL, etc.)
- Establish ubiquitous language per context
3. Select Architecture Pattern
Choose based on domain complexity and requirements:
| Pattern |
When to Use |
| Layered |
Simple CRUD, low complexity |
| Hexagonal |
Need to isolate domain from infrastructure |
| Clean Architecture |
Complex business rules, multiple delivery mechanisms |
| CQRS |
Different read/write models, complex queries |
| Event Sourcing |
Audit trail required, temporal queries, event-driven |
Patterns can be combined (e.g., Hexagonal + CQRS + Event Sourcing).
4. Apply Tactical Patterns
Select tactical building blocks based on needs:
| Building Block |
Purpose |
| Entity |
Identity matters, mutable, lifecycle |
| Value Object |
Defined by attributes, immutable, no identity |
| Aggregate |
Consistency boundary, transactional unit |
| Domain Service |
Stateless operations spanning multiple aggregates |
| Repository |
Collection-like interface for aggregate persistence |
| Domain Event |
Record of something significant that happened |
| Factory |
Complex object creation logic |
| Specification |
Encapsulated business rules for querying/validation |
5. Implementation Guidelines
General principles:
- Domain layer has ZERO infrastructure dependencies
- Depend on abstractions (interfaces/protocols), not concretions
- One aggregate = one repository = one transaction
- Aggregates reference other aggregates by ID only
- Validate invariants within aggregate boundaries
- Use domain events for cross-aggregate communication
Language selection:
- Read python-patterns.md for Python with Pydantic, SQLAlchemy, FastAPI
- Read typescript-patterns.md for TypeScript with NestJS, TypeORM, Prisma
Project Structure Template
src/
├── domain/ # Pure domain logic (no dependencies)
│ ├── model/ # Entities, Value Objects, Aggregates
│ ├── service/ # Domain Services
│ ├── event/ # Domain Events
│ ├── repository/ # Repository interfaces (ports)
│ └── specification/ # Business rule specifications
├── application/ # Use cases, orchestration
│ ├── command/ # Command handlers (write)
│ ├── query/ # Query handlers (read)
│ ├── dto/ # Data transfer objects
│ └── service/ # Application services
├── infrastructure/ # External concerns
│ ├── persistence/ # Repository implementations
│ ├── messaging/ # Event bus, message queue
│ └── external/ # Third-party integrations
└── interface/ # Delivery mechanisms
├── api/ # REST/GraphQL controllers
├── cli/ # Command-line interface
└── event/ # Event consumers
Anti-Patterns to Avoid
- Anemic Domain Model: Entities with only getters/setters, logic in services
- God Aggregate: Too many entities in one aggregate
- Shared Kernel Abuse: Overusing shared code between contexts
- Infrastructure Leak: Database concerns in domain layer
- Missing Ubiquitous Language: Technical terms instead of domain terms
- Aggregate Reference by Object: Should reference by ID only
- Transaction Across Aggregates: Violates consistency boundaries
When NOT to Use DDD
DDD adds complexity. Avoid for:
- Simple CRUD applications
- Technical/infrastructure projects without complex business logic
- Prototypes or throwaway code
- Teams unfamiliar with the domain (learn domain first)
Use DDD when:
- Complex, evolving business logic
- Long-lived systems requiring maintainability
- Multiple teams working on related domains
- Domain experts available for collaboration
1---2name: ddd3description: Domain-Driven Design system for software development. Use when designing new systems with DDD principles, refactoring existing codebases toward DDD, generating code scaffolding (entities, aggregates, repositories, domain events), facilitating Event Storming sessions, creating bounded context maps, or performing code reviews with a DDD lens. Covers both strategic design (bounded contexts, subdomains, context maps, ubiquitous language) and tactical design (entities, value objects, aggregates, domain services, repositories). Supports all major architecture patterns (Hexagonal/Ports & Adapters, CQRS, Event Sourcing, Clean Architecture) with language-agnostic guidance and concrete examples in Python and TypeScript.4---56# Domain-Driven Design Skill78Apply DDD to build software that reflects deep understanding of the business domain.910## Quick Reference1112| Task | Reference |13|------|-----------|14| Bounded contexts, subdomains, context maps | [strategic-design.md](references/strategic-design.md) |15| Entities, value objects, aggregates, repositories | [tactical-design.md](references/tactical-design.md) |16| Hexagonal, CQRS, Event Sourcing, Clean Architecture | [architecture-patterns.md](references/architecture-patterns.md) |17| Event Storming facilitation & documentation | [event-storming.md](references/event-storming.md) |18| Python implementations (Pydantic, SQLAlchemy, FastAPI) | [python-patterns.md](references/python-patterns.md) |19| TypeScript implementations (NestJS, TypeORM, Prisma) | [typescript-patterns.md](references/typescript-patterns.md) |20| DDD code review criteria | [code-review.md](references/code-review.md) |2122## Core Workflow2324### 1. Identify the Task Type2526**Designing new system?** → Start with strategic design, then tactical27**Refactoring existing code?** → Assess current state, identify bounded contexts, refactor incrementally28**Generating scaffolding?** → Determine patterns needed, generate code29**Event Storming?** → Follow facilitation guide30**Code review?** → Apply DDD checklist3132### 2. Strategic Before Tactical3334Always establish strategic design first:351. Identify **subdomains** (Core, Supporting, Generic)362. Define **bounded contexts** and their boundaries373. Map **context relationships** (upstream/downstream, conformist, ACL, etc.)384. Establish **ubiquitous language** per context3940### 3. Select Architecture Pattern4142Choose based on domain complexity and requirements:4344| Pattern | When to Use |45|---------|-------------|46| **Layered** | Simple CRUD, low complexity |47| **Hexagonal** | Need to isolate domain from infrastructure |48| **Clean Architecture** | Complex business rules, multiple delivery mechanisms |49| **CQRS** | Different read/write models, complex queries |50| **Event Sourcing** | Audit trail required, temporal queries, event-driven |5152Patterns can be combined (e.g., Hexagonal + CQRS + Event Sourcing).5354### 4. Apply Tactical Patterns5556Select tactical building blocks based on needs:5758| Building Block | Purpose |59|----------------|---------|60| **Entity** | Identity matters, mutable, lifecycle |61| **Value Object** | Defined by attributes, immutable, no identity |62| **Aggregate** | Consistency boundary, transactional unit |63| **Domain Service** | Stateless operations spanning multiple aggregates |64| **Repository** | Collection-like interface for aggregate persistence |65| **Domain Event** | Record of something significant that happened |66| **Factory** | Complex object creation logic |67| **Specification** | Encapsulated business rules for querying/validation |6869### 5. Implementation Guidelines7071**General principles:**72- Domain layer has ZERO infrastructure dependencies73- Depend on abstractions (interfaces/protocols), not concretions74- One aggregate = one repository = one transaction75- Aggregates reference other aggregates by ID only76- Validate invariants within aggregate boundaries77- Use domain events for cross-aggregate communication7879**Language selection:**80- Read [python-patterns.md](references/python-patterns.md) for Python with Pydantic, SQLAlchemy, FastAPI81- Read [typescript-patterns.md](references/typescript-patterns.md) for TypeScript with NestJS, TypeORM, Prisma8283## Project Structure Template8485```86src/87├── domain/ # Pure domain logic (no dependencies)88│ ├── model/ # Entities, Value Objects, Aggregates89│ ├── service/ # Domain Services90│ ├── event/ # Domain Events91│ ├── repository/ # Repository interfaces (ports)92│ └── specification/ # Business rule specifications93├── application/ # Use cases, orchestration94│ ├── command/ # Command handlers (write)95│ ├── query/ # Query handlers (read)96│ ├── dto/ # Data transfer objects97│ └── service/ # Application services98├── infrastructure/ # External concerns99│ ├── persistence/ # Repository implementations100│ ├── messaging/ # Event bus, message queue101│ └── external/ # Third-party integrations102└── interface/ # Delivery mechanisms103 ├── api/ # REST/GraphQL controllers104 ├── cli/ # Command-line interface105 └── event/ # Event consumers106```107108## Anti-Patterns to Avoid109110- **Anemic Domain Model**: Entities with only getters/setters, logic in services111- **God Aggregate**: Too many entities in one aggregate112- **Shared Kernel Abuse**: Overusing shared code between contexts113- **Infrastructure Leak**: Database concerns in domain layer114- **Missing Ubiquitous Language**: Technical terms instead of domain terms115- **Aggregate Reference by Object**: Should reference by ID only116- **Transaction Across Aggregates**: Violates consistency boundaries117118## When NOT to Use DDD119120DDD adds complexity. Avoid for:121- Simple CRUD applications122- Technical/infrastructure projects without complex business logic123- Prototypes or throwaway code124- Teams unfamiliar with the domain (learn domain first)125126Use DDD when:127- Complex, evolving business logic128- Long-lived systems requiring maintainability129- Multiple teams working on related domains130- Domain experts available for collaboration