Invariant Protection
Invariant protection ensures the rules that must always hold — balance non-negative, order total matches line items — are enforced at the only place that can guarantee them: the aggregate boundary.
Definition
Invariant protection is the design discipline of placing the rules that must always hold for a cluster of state inside the aggregate that owns that state, so that every mutation goes through the aggregate and the invariant is checked at the only boundary that can enforce it transactionally.
Context and scope
Applied in domain-driven design, concurrent stateful systems, and any context where a rule violated by one mutation corrupts all subsequent reads.
Common misconceptions
- Invariants are database constraints — constraints protect data integrity; invariants protect business rules, which span multiple rows and tables a constraint cannot express
- Invariants should be checked in the service layer — the service is callable from anywhere; only the aggregate boundary guarantees every mutation passes the check
Anti-patterns
- Checking the invariant in the controller and letting a second entry point bypass it, so the rule holds only for the audited path
- Enforcing the invariant with a database constraint that cannot express the cross-row business rule, giving a false sense of safety
Related concepts
Authoritative source
What it is
Invariant protection is the design discipline of placing the rules that must always hold for a cluster of state inside the aggregate that owns that state, so that every mutation goes through the aggregate and the invariant is checked at the only boundary that can enforce it transactionally. Applied in domain-driven design, concurrent stateful systems, and any context where a rule violated by one mutation corrupts all subsequent reads. The organizing principle is which decisions are hard to reverse and should be made once, versus which are easy to reverse and should be deferred.
How it works
Boundaries are drawn along axes of change: things that change together are colocated, things that change independently are separated by interfaces whose contracts are explicit and versioned. Dependencies point toward stability — domain logic depends on abstractions, infrastructure depends on domain, never the reverse. The structure makes the system’s intent legible without reading every module.
When to choose and pitfalls
Choose this structure when the system will outlive its first deployment and face requirements you cannot now predict. The pitfall is premature abstraction — adding indirection for a flexibility that never materializes, paying its complexity cost forever. The opposite pitfall is entangling concerns that later need to separate, forcing a rewrite instead of a refactor.