--- slug: invariant type: pattern summary: "A condition that must always hold regardless of what changes around it, expressing what your code can never be allowed to violate." created: 2026-04-04 updated: 2026-05-12 related: aggregate: relation: informs note: "Invariants spanning multiple objects define which objects must live inside the same aggregate." architecture-fitness-function: relation: related note: "A fitness function is the executable form of an architectural invariant: a structural condition that must always hold." constraint: relation: depends-on note: "Invariants are often derived from requirements and constraints." fail-fast-and-loud: relation: enforced-by note: "The loud half of the pattern is precisely how a violated invariant should surface." failure-mode: relation: related note: "A violated invariant is often the mechanism of a failure mode." performance-envelope: relation: contrasts-with note: "Envelopes define acceptable *ranges*, while invariants define absolute rules." refactor: relation: enables note: "Known invariants make it safe to change internal structure." regression: relation: detects note: "Violated invariants are a common form of regression." requirement: relation: depends-on note: "Invariants are often derived from requirements and constraints." silent-failure: relation: detects note: "Invariants convert silent failures into loud ones." test: relation: enables note: "Invariants give tests something specific to verify." test-oracle: relation: used-by note: "Invariants serve as a form of property-based oracle." --- # Invariant > **Pattern** > > A named solution to a recurring problem. > "The art of programming is the art of organizing complexity, of mastering multitude and avoiding its bastard chaos." > — Edsger Dijkstra ## Understand This First - [Requirement](requirement.md), [Constraint](constraint.md) -- invariants are often derived from requirements and constraints. ## Context When you build or modify software, whether by hand or by directing an AI agent, you need some way to express what must *always* be true, regardless of what changes around it. This is a **tactical** pattern: it operates at the level of individual functions, data structures, and system boundaries. An invariant sits downstream of [Requirements](requirement.md) and [Constraints](constraint.md). Requirements say what the system should do; invariants say what must *never* be violated while doing it. ## Problem Software changes constantly. New features are added, edge cases are handled, data formats evolve. With every change, there's a risk that some fundamental property of the system breaks: an account balance goes negative when the rules say it can't, a list that should always be sorted becomes unsorted, a security token gets shared between users. How do you protect the things that must not break? ## Forces - Code changes frequently, and each change is an opportunity for something to break. - Not all rules are equally important; some are absolute, others are preferences. - Stating a rule in a comment isn't the same as enforcing it. - Overly rigid systems are hard to evolve; overly loose systems break silently. ## Solution Identify the conditions that must *always* hold for your system to be valid, and make them explicit. An invariant is a statement like "every order has at least one line item" or "the total of all account balances is zero." The key word is *always*: an invariant isn't a temporary condition or a goal; it's a permanent truth about valid states. Once you've identified an invariant, enforce it. The strongest enforcement is in code: a constructor that refuses to create an invalid object, a function that checks its preconditions, a type system that makes illegal states unrepresentable. Weaker but still useful enforcement includes [Tests](test.md) that verify the invariant holds after every operation, and assertions that crash the program rather than letting it continue in a broken state. The real power of invariants is that they reduce the space of things you have to worry about. If you *know* a list is always sorted, you can use binary search without checking. If you *know* an account balance is never negative, you don't need to handle that case everywhere it's read. ## How It Plays Out A banking application enforces the invariant that no account balance may go negative. Every withdrawal function checks the balance before proceeding. This single rule prevents an entire class of bugs (overdraft errors, corrupted ledgers, inconsistent reports) from ever reaching production. In an agentic coding workflow, invariants serve as guardrails for AI-generated code. When you tell an agent "add a discount feature to the checkout flow," the agent may not know that order totals must never be negative. But if that invariant is enforced in the `Order` type itself, perhaps through a constructor that rejects negative totals, the agent's code will fail fast if it violates the rule, rather than silently introducing corruption. > **💡 Tip** > > When directing an AI agent, state your invariants explicitly in the prompt or in code comments. Agents can't infer business rules they've never seen. > **💡 Example Prompt** > > "Add a validation check to the Order constructor: the total must never be negative. If someone tries to create an order with a negative total, raise a ValueError with a clear message. Add a test that verifies this." ## Consequences Explicit invariants catch bugs early and reduce the number of things developers (and agents) must keep in their heads. They make code easier to reason about because you can rely on guaranteed properties. The cost is rigidity. Every invariant constrains future changes. If you later need to allow negative balances for a new feature, you must rework the invariant and every piece of code that relied on it. Choose your invariants carefully: enforce what truly must be true, and leave room for what might change. ## Sources - C. A. R. Hoare's "[An Axiomatic Basis for Computer Programming](https://doi.org/10.1145/363235.363259)" (*Communications of the ACM*, 1969) gave invariants their formal footing. The paper's rules of inference for loops require the programmer to identify a predicate that the loop body preserves — the **loop invariant** — and this is where the term entered mainstream programming discourse. - Edsger Dijkstra extended the machinery in *[A Discipline of Programming](https://openlibrary.org/works/OL4780088W)* (Prentice-Hall, 1976), where predicate transformers and the weakest-precondition calculus give invariants a central role in reasoning about correctness. The epigraph is from Dijkstra's earlier *[Notes on Structured Programming](https://www.cs.utexas.edu/~EWD/ewd02xx/EWD249.PDF)* (EWD 249, 1970). - Bertrand Meyer baked invariants into a production language with Eiffel and his **Design by Contract** methodology, described most fully in *[Object-Oriented Software Construction](https://openlibrary.org/books/OL657292M/Object-oriented_software_construction)* (Prentice-Hall, 1988; 2nd ed. 1997). The idea that a class has an `invariant` clause enforced at every public-method boundary comes from this work and remains the clearest model for how invariants should live inside code. - Eric Evans's *[Domain-Driven Design: Tackling Complexity in the Heart of Software](https://www.oreilly.com/library/view/domain-driven-design-tackling/0321125215/)* (Addison-Wesley, 2003) is the source for the "Informs: Aggregate" link in this article. Evans argues that aggregate roots exist precisely to enforce invariants that span multiple objects, and that factories must be atomic so that no client ever sees an aggregate in a state that violates its invariants. --- - [Next: Test](test.md) - [Previous: Correctness, Testing, and Evolution](correctness-testing-and-evolution.md)