ArchitectureJune 10, 20261 min

Tests as living contracts

Most people treat tests as a chore: proof for the CI gate, a tax on shipping. I've come to see them as something more useful — the contract your code signs about how it's supposed to behave. Unlike a comment or a wiki page, this contract can't quietly drift out of date, because the moment it stops being true, it fails.

Documentation that can't lie

A test says "given this input, the system promises this output." That's documentation with teeth. A README can describe behavior that changed three commits ago; a test describes behavior that is true right now, or the build is red. When I want to understand what a module actually guarantees, I read its tests before its prose.

From examples to properties

Example tests check specific cases. Property tests check rules that must always hold, across hundreds of generated inputs. In a project like BillParty, the contract isn't "splitting $30 three ways gives $10 each" — it's "the shares always sum back to the total," for any amount and any split. State the property, let the tool hunt for the counterexample. When it can't find one, you've verified a law of your system, not a single anecdote.

Test the domain, not the framework

The contracts worth writing are about your domain rules — the math, the invariants, the things that must never break. The framework already has its own tests; you don't need to re-verify that the router routes. Point your suite at the core, where being wrong is expensive, and let it stand guard there.

Treated this way, tests stop being overhead. They become the living, enforced description of what your software promises — and the thing that lets you change everything else with confidence.

Related notes