Files
vac-optimizer/.agents/skills/domain-driven-design/references/building-blocks.md
T
2026-09-25 10:00:00 +02:00

36 lines
2.4 KiB
Markdown

# Entities, Value Objects, and Aggregates
Start from identity and business invariants rather than database tables or a target class count.
## Identity and value
An entity retains identity through changes; a value object is interchangeable with another value having the same attributes. Choose equality and mutability accordingly. Use existing identifier conventions rather than adding a new ID scheme by default.
Value objects should enforce their actual invariants and support immutable transformations. Do not infer business rules from examples: negative money may be valid for one concept and invalid for another.
## Aggregate ownership
An aggregate owns a cohesive set of state and invariants, with a root controlling its changes. Keep it small enough to load and update for its real use cases; use references by ID for independent aggregates where the project's model calls for them.
Ask:
- Which rules must hold after every successful operation?
- Who owns each lifecycle and may change its state?
- Which state must be read and written together?
- What prevents two concurrent commands from both accepting incompatible outcomes?
- Can a partial result or delayed update be valid?
Do not embed a growing independent lifecycle merely to make all relationships reachable through one object.
## Atomicity and concurrency
Aggregate boundaries and transaction boundaries are related, not identical. When an operation must commit or roll back across multiple aggregate documents, use the supported service-layer transaction required by the domain.
In this repository, [ADR-0011](../../../../docs/adr/0011-rental-aggregate-boundaries.md) explicitly requires Mongo transactions for relevant rental operations. Preserve optimistic version checks, occupancy contention, and uniqueness constraints; replacing them with asynchronous events or a query-only overlap check would weaken the invariant.
Use eventual consistency only when delayed or partial progress is acceptable, with explicit failure and recovery handling. Keep remote calls and long-running work outside database transactions.
## Verify the boundary
Exercise the actual operation, including invalid transitions, stale versions, duplicate commands, and competing callers where relevant. Prove the invariant at the storage/integration boundary when an in-memory test cannot establish it. Preserve distinct existing test coverage when moving behavior behind a new interface.