Design by contract as self testing code idea by Martin Fowler
Yes, this pattern has names and precedents. Martin Folwer official site. Sits boldly and pains some developers… at the intersection of a few well-known ideas. Helps as and works a “fill in the gaps” kind of approach.

Names / related patterns
- Design by Contract (DbC) / Invariants
- You define preconditions, postconditions, and invariants for functions / classes.
- In Design by Contract… these contracts are usually checked at runtime and can raise error immediately when violated.
- Your “assert the outcome of
groupTabsByAge” is essentially a postcondition + invariant check on the result. This can live in production / test code in a Domain / Page level object.
- Runtime Invariant Checking / Assertion Checks in Production
- Keeping invariant checks in production code (often guarded by/as a flag) is an established technique. Especially in safety‑critical or high‑reliability systems. We do have transactions and such, the idea is similar. Immediate verification.
- Literature talks about “efficient runtime invariant checking” as a way to catch violations early in real executions. Those fails will force You to address the issue.
- Self‑Testing Code
- Martin Fowler’s “Self Testing Code” concept is about having automated tests tightly coupled with the runtime/production/running code so you can execute methods/functions anytime , anywhere and trust the result.
- Some communities (e.g., Python) historically encouraged self‑tests in modules that run when the module is executed directly.
- You can find articles explicitly advocating “self‑testing code” via embedded assertions and preconditions in production.
- Guardrails (especially for AI)
- In AI contexts, “guardrail pattern” means wrapping inputs/outputs with validation and safety checks before/in the middle / after using an LLM or agents. Be sure twice.
- Your use case (guarding against AI refactors breaking ordering) is conceptually similar: a runtime guardrail around a critical function’s output.

But Hey ! It is “heresy” to put tests in production code?
Feels counter‑intuitive only if you equate “tests” with “unit test files that should never ship”. Advocated by people is a yes or not purely based on their experience. If it works for You – go for it ! You can always remove it later. If it helps You in any way, the idea is just.
There is always a BUT …
- Assertions / invariants in production are normal in many languages and domains (e.g.,
assertin C/C++, Java, Rust; contract checking proposals in C/C++). - The key is how you include them:
- Use cheap, local checks (O(n), not heavy test harnesses).
- Make them fail fast (throw, abort, or log + alert).
- Gate them by environment:ts
if (process.env.NODE_ENV !== 'production') { assertGroupTabsByAgeInvariant(tabs, groups); }or a dedicated flag likeENABLE_RUNTIME_INVARIANTS.
This gives you:
- Strong guardrails in dev/test and possibly staging.
- Optional hardening in production (depending on your risk tolerance and performance constraints).

Common patterns in practice
You’ll see this in several forms:
- Design by Contract style methods:t
sfunction doX(...): Result { // preconditions // core logic // postconditions / invariants return result; }Fowler’s “Test Invariant” article proposes exactly this: apassesInvariant()method used both in tests and conceptually in production. - Self‑test hooks:
- Some libraries expose a
selfTest()orrunInvariants()that can be called in CI or on startup to validate internal consistency. - In AI systems, “guardrail wrapper” patterns validate outputs before they’re used downstream.[medium]
- Some libraries expose a
- Feature‑flagged runtime checks:
- Heavy or expensive checks enabled only in canary builds or for a small % of requests.
- Light structural checks (like your ordering invariant) often left on everywhere.
How to frame it in your codebase
You can document this explicitly as:
“
groupTabsByAgeincludes runtime invariants (postconditions) that validate ordering and grouping. These are part of our design-by-contract / guardrail strategy to prevent silent regressions, especially from AI-assisted refactors.”
That way:
- It’s not “mysterious test code in prod”; it’s an intentional contract enforcement mechanism.
- New devs (and AIs) understand: if you break this, you must also update or remove the invariant, which is a conscious decision.
If you’d like, I can suggest a small naming convention and utility layer (e.g., invariant(), postcondition()) to make this pattern consistent across your plugin.


