A manifesto
Code as a Contract — a manifesto
Code is not instructions to a machine that humans happen to read. Code is a contract between many parties — the customer, the business, the payment processor, the next developer, the on-call engineer at 3am — that a machine happens to execute.
Read any well-drafted legal contract and you find the same structure good code wants: definitions first, then sections stating each party's obligations, responsibilities and abilities, the business rules and how they are applied, and the succession of events — what must happen, in what order, and who has to do it.
We hold these principles
- Definitions come first, and are declared, not implied. Types are the contract's Definitions section. A party, an amount, a deadline each gets a name and a shape before any clause uses it.
- Every business rule has a name. A rule that exists only as an inline
ifis an unwritten verbal agreement — unenforceable and disputed later. - The operative clause reads top-to-bottom. The main function of an interaction has minimal — ideally zero — cyclomatic complexity. It barely does anything itself: it calls named functions that abstract the internals of the contract. Anyone can read it aloud in a meeting.
- Terms are pure; execution is separate. Deciding what the contract says is a pure function of facts. Performing the contract (charging cards, writing rows, sending mail) happens at the edges, after the decision. You can judge the terms without a courtroom.
- Tests are case law. Each pure unit test is a scenario a party could dispute, named as a claim, settled by the contract at the highest level.
- The principle applies recursively — without abuse. Implementations of the named functions follow the same discipline, but splitting stops when a function's body is plainer than another name would be. A contract drowning in cross-references is as bad as one long run-on clause.
- Changes are amendments. A behavior change must be legible as an amendment: the diff shows which clause changed and which case law (tests) now rules differently.
- Execution follows the succession of events. The boundary of every interaction is a performer with near-zero branching: it gathers the facts into a frozen evidence file (the only place the outside world is translated into the Definitions), consults the terms, and performs the decision — citing only the decision's own fields, never re-interpreting the terms. If performing needs more information, the decision's Definition is defective; fix it there.
- Operational demands are schedules. Caching, queuing, retries, timeouts, forms and screens — obligations about how performance happens are not scattered through the code as incantations. Each is declared as frozen data (a schedule, in the legal sense: an annex the clauses cite), and executed by a generic performer that holds no rules of its own. Any judgment a schedule requires — is this cached fact still fresh, should this delivery retry, is this field valid — is a pure function of the schedule and the facts, and gets case law like any other term.
- The docket is generated, never hand-written. The human-readable specification is produced from the case law (test names, grouped by clause), so it can never drift from behavior. Prose spec layers that do not execute are a second contract over the same subject matter — and two contracts is how disputes start.
Read the full manifesto Repository
Companion papers
- Schedules — how the internals are drafted.
- Code as Contract vs. Gherkin — a comparison paper, not the manifesto.