mirror of
https://github.com/s-frick/effigenix.git
synced 2026-03-28 12:09:35 +01:00
184 lines
5.1 KiB
Markdown
184 lines
5.1 KiB
Markdown
# DDD Rules Checklist
|
|
|
|
Use this checklist to validate your domain model against DDD principles.
|
|
|
|
## Aggregate Rules
|
|
|
|
### Boundaries
|
|
- [ ] Aggregate has a clearly defined boundary
|
|
- [ ] Aggregate Root is identified and documented
|
|
- [ ] Only Aggregate Root is accessible from outside
|
|
- [ ] Child entities are encapsulated (not exported or accessed directly)
|
|
- [ ] Aggregate is the smallest consistent unit
|
|
|
|
### Invariants
|
|
- [ ] All invariants are documented with `// Invariant:` comments
|
|
- [ ] Constructor validates all invariants
|
|
- [ ] Every mutation method maintains invariants
|
|
- [ ] Invalid state is impossible to create
|
|
- [ ] Aggregate rejects invalid operations (returns error)
|
|
|
|
### References
|
|
- [ ] No direct object references to other Aggregates
|
|
- [ ] References to other Aggregates use ID only
|
|
- [ ] ID references are typed (not raw strings/ints)
|
|
- [ ] Cross-aggregate consistency is eventual (not immediate)
|
|
|
|
### Transactions
|
|
- [ ] One Aggregate = one transaction boundary
|
|
- [ ] No multi-aggregate transactions in domain layer
|
|
- [ ] Application layer coordinates multiple aggregates if needed
|
|
|
|
### Sizing
|
|
- [ ] Aggregate is not too large (performance issues)
|
|
- [ ] Aggregate is not too small (consistency issues)
|
|
- [ ] "Just right" - protects business invariants, nothing more
|
|
|
|
---
|
|
|
|
## Entity Rules
|
|
|
|
### Identity
|
|
- [ ] Has a unique identifier
|
|
- [ ] ID is assigned at creation time
|
|
- [ ] ID is immutable after creation
|
|
- [ ] ID type is specific (e.g., `AccountID`, not `string`)
|
|
|
|
### Equality
|
|
- [ ] Equals compares by ID only
|
|
- [ ] Two entities with same ID are considered equal
|
|
- [ ] Attribute changes don't affect equality
|
|
|
|
### Mutability
|
|
- [ ] State changes through explicit methods
|
|
- [ ] No public setters
|
|
- [ ] Methods express domain operations (not CRUD)
|
|
- [ ] Methods return errors for invalid operations
|
|
|
|
---
|
|
|
|
## Value Object Rules
|
|
|
|
### Immutability
|
|
- [ ] All fields are private/unexported
|
|
- [ ] No setter methods
|
|
- [ ] No methods that modify internal state
|
|
- [ ] "Modification" creates new instance
|
|
|
|
### Equality
|
|
- [ ] Equals compares ALL fields
|
|
- [ ] Two VOs with same values are interchangeable
|
|
- [ ] No identity concept
|
|
|
|
### Validation
|
|
- [ ] Constructor validates input
|
|
- [ ] Invalid VOs cannot be created
|
|
- [ ] Returns error for invalid input
|
|
- [ ] Provides `MustXxx()` variant for tests (panics on error)
|
|
|
|
### Self-Containment
|
|
- [ ] VO contains all related logic
|
|
- [ ] Domain logic lives in VO methods
|
|
- [ ] Example: `Money.Add(other Money) Money`
|
|
|
|
---
|
|
|
|
## Repository Rules
|
|
|
|
### Interface Location
|
|
- [ ] Repository interface defined in domain layer
|
|
- [ ] Implementation in infrastructure layer
|
|
- [ ] Domain doesn't know about infrastructure
|
|
|
|
### Methods
|
|
- [ ] Methods operate on Aggregates (not entities)
|
|
- [ ] `Save(aggregate)` - persists aggregate
|
|
- [ ] `FindByID(id)` - retrieves aggregate
|
|
- [ ] No methods that bypass Aggregate Root
|
|
|
|
### Transactions
|
|
- [ ] Repository doesn't manage transactions
|
|
- [ ] Application layer manages transaction scope
|
|
- [ ] One repository call = one aggregate
|
|
|
|
---
|
|
|
|
## Domain Service Rules
|
|
|
|
### When to Use
|
|
- [ ] Operation spans multiple aggregates
|
|
- [ ] Operation doesn't naturally belong to any entity/VO
|
|
- [ ] Significant domain logic that's not entity behavior
|
|
|
|
### Implementation
|
|
- [ ] Stateless (no instance variables)
|
|
- [ ] Named after domain operation (e.g., `TransferService`)
|
|
- [ ] Injected dependencies via constructor
|
|
- [ ] Returns domain objects, not DTOs
|
|
|
|
---
|
|
|
|
## Domain Event Rules
|
|
|
|
### Naming
|
|
- [ ] Past tense (e.g., `AccountCreated`, `TransferCompleted`)
|
|
- [ ] Describes what happened, not what to do
|
|
- [ ] Domain language, not technical terms
|
|
|
|
### Content
|
|
- [ ] Contains all data needed by handlers
|
|
- [ ] Immutable after creation
|
|
- [ ] Includes aggregate ID and timestamp
|
|
|
|
### Publishing
|
|
- [ ] Events raised by Aggregates
|
|
- [ ] Published after aggregate is saved
|
|
- [ ] Handlers in application or infrastructure layer
|
|
|
|
---
|
|
|
|
## Clean Architecture Rules
|
|
|
|
### Dependency Direction
|
|
- [ ] Domain layer has no external dependencies
|
|
- [ ] Application layer depends only on Domain
|
|
- [ ] Infrastructure depends on Domain and Application
|
|
- [ ] No circular dependencies
|
|
|
|
### Layer Contents
|
|
- [ ] Domain: Entities, VOs, Aggregates, Repository interfaces, Domain Services
|
|
- [ ] Application: Use Cases, Application Services, DTOs
|
|
- [ ] Infrastructure: Repository implementations, External services, Framework code
|
|
|
|
### Interface Segregation
|
|
- [ ] Small, focused interfaces
|
|
- [ ] Defined by consumer (domain layer)
|
|
- [ ] Implemented by provider (infrastructure)
|
|
|
|
---
|
|
|
|
## Common Anti-Patterns to Avoid
|
|
|
|
### Anemic Domain Model
|
|
- ❌ Entities with only getters/setters
|
|
- ❌ All logic in services
|
|
- ✅ Rich domain model with behavior
|
|
|
|
### Large Aggregates
|
|
- ❌ Loading entire object graph
|
|
- ❌ Too many entities in one aggregate
|
|
- ✅ Small, focused aggregates
|
|
|
|
### Aggregate References
|
|
- ❌ `order.Customer` (direct reference)
|
|
- ✅ `order.CustomerID` (ID reference)
|
|
|
|
### Business Logic Leakage
|
|
- ❌ Validation in controllers
|
|
- ❌ Business rules in repositories
|
|
- ✅ All business logic in domain layer
|
|
|
|
### Technical Concepts in Domain
|
|
- ❌ `@Entity`, `@Column` annotations
|
|
- ❌ JSON serialization tags
|
|
- ✅ Pure domain objects, mapping in infrastructure
|