Guarding architecture
REQUIRED BACKGROUND: the principal-engineering skill.
Overview
Structural invariants are load-bearing contracts: violating one surfaces as a class of bugs, not a single defect. An invariant that matters gets a name, a written rationale, and a mechanical guard; an invariant without a guard is a wish.
The pattern
- Name the invariants. Numbered and citable ("Law 3"), each with a Statement (technology-neutral, meant to outlast any framework), a Rationale, and Implications. The Rationale is a concrete failure narrative: the class of bugs that appears when the invariant is violated, told from an incident, not an abstraction.
- Split the stable from the volatile. The principles document changes rarely and names no classes; its current realization (the canonical owners, the guards, the reference designs) lives in a companion that changes with the code. When the two disagree, the invariant governs and the realization document gets corrected.
- Enforce mechanically. Every enforceable invariant gets an architecture test that fails the build: dependency directions, package boundaries, layering rules, forbidden imports. What cannot be build-enforced becomes a named review check with the invariant cited.
- Violations mean redesign, never justification. A design that violates a named invariant is wrong by construction: redesign it, do not argue the exception into the spec. Watering the contract down to match nonconforming code is the banned move; the violation gets recorded and the code gets fixed (the same rule the technical-writer plugin applies to normative documents).
- Specs show conformance. A design that touches guarded ground names the invariants it touches and shows, per invariant, how it upholds each; the reviewer checks claims against named invariants instead of debating taste.
- Exceptions are amendments. A genuine exception proposes an amendment, naming the invariant it bends and the boundary of the bend; silent exceptions are how an invariant becomes a suggestion. This is the only legal form of exception, and point 4 bans every other; an unreachable owner does not create one, so the change waits or lands conforming. A genuinely temporary exception is a dated waiver with an expiry condition and the owner's sign-off, recorded in the volatile realization document, not by amending the stable invariant for a passing condition.
- An unexplained guard exclusion is a violation hidden from the build. Whoever finds one surfaces it to the invariant's owner. An exclusion is never precedent for the next one; extending an exclusion list "like the others did" ratifies erosion instead of following a pattern.
Common invariant classes
Worth guarding in most systems, as examples rather than mandates:
- One canonical owner per concern (see
keeping-one-source-of-truth).
- Dependency direction: the domain never imports the delivery mechanism.
- Critical-path isolation: no I/O and no slow or optional dependency on the hot path.
- Fail-closed boundaries: a gate that cannot evaluate must deny (see
handling-failures).
- Migration immutability (see the hard rules in
principal-engineering).
Common mistakes
- A principles document full of class names: the realization document wearing the wrong title; split them.
- Adding the import "for now". Boundaries die by single convenient imports; the guard exists because each violation is locally reasonable.
- An invariant asserted in review but absent from the build: enforced exactly as often as the right reviewer is present.
- Justifying a violation by the cost of conforming. The cost argument may be right, but its correct form is an amendment to the invariant, decided by the owner, recorded (via
recording-decisions where installed), never a quiet exception in one spec.
- Principles written as taste ("prefer small modules") instead of contracts ("module X never imports module Y"). A contract can fail a build; taste can only fail a mood.