Tactical DDD: behaviour and consistency
Tactical DDD provides building blocks for implementing a domain model. Start with the decisions and rules, then choose the objects needed to express them.
Entities and values
An entity has continuity of identity. A Party remains the same canonical Party when its platform access state changes. A value object is identified by meaning and values. An exact provider/instance/external-reference tuple describes a binding without borrowing a provider's identifier as the canonical Party identity.
Aggregates and invariants
An aggregate groups state whose immediate rules are controlled through one root. An invariant must hold at the business boundary where it applies. Project owns its complete child membership set; independent membership writes would bypass its complete-observation and uniqueness rules.
PartyAuthentication owns its access state and authentication generation. The actual transition below validates its input, preserves unchanged state, protects overflow and records a private fact when the generation changes.
Domain tests exercise these transitions. Cross-root uniqueness, such as issuer/subject ownership, also requires the owner repository's concurrent uniqueness enforcement.
Creation, restoration and repositories
Creation establishes valid initial state and may raise new facts. Restoration validates persisted state and treats invalid bytes as corruption. It raises no new business facts merely because an existing aggregate was loaded.
The application repository loads and saves the aggregate. Its persistence adaptor owns snapshot and database mappings. Aggregate children have no independent write repository. Database tables can differ from the object structure while preserving the root's atomic boundary.
A domain service expresses domain behaviour with no natural entity or value owner. An application handler coordinates a use case through ports. Keep provider I/O, transaction mechanisms and dependency-container resolution outside the domain.
Exercise: explain why Project memberships belong to the Project root while a PartyProviderBinding has its own lifecycle. Use their invariants as evidence.
Next: Hexagonal architecture.
Adapted from the architecture reference, with Pharos examples.
Page source
Source snapshot ยท Revision f928834c8.