New here? Start at the front door. Five ways in, depending on why you came.
Software gets read far more than it gets written. It gets changed more than it gets read, and then it runs in a world that fails partially, at the worst possible moment, usually while you're asleep. So build correctness into the shape of the system, not into the vigilance of the people keeping it going. Any rule you can only enforce by remembering it is a rule that will eventually get forgotten, and any defence you have to run by hand gets skipped the first time there's a deadline. The objective has two terms and you're meant to push on both of them at the same time: minimise what a tired engineer has to hold in their head to make a correct change, while keeping the blast radius bounded for anything an attacker or an unlucky caller controls. Most of the tenets here buy you that first term. The ones that add code and state to contain failure are paying for the second. When two tenets pull against each other, and sooner or later they will, you don't resolve it with a slogan. It's a judgement about who controls the input and how wide the blast radius is. If the input is caller- or attacker-controlled and the blast radius is wide, pay the cost now. If it's self-controlled and contained, you can defer it, but write down why. These tenets work on one part and one boundary at a time, because that's about all a bounded mind can keep hold of at once. The failures that only turn up once the whole thing is assembled, the ones that belong to no single part, get their own page, The Shape of the Whole. Every tenet below names the failure it stops, the tension it sets up, and one question to ask yourself mid-edit. None of them is free.
I
Locality of reasoning over global cleverness
A reader should be able to verify a piece of code correct by looking only at that piece and its declared inputs.
When understanding one function means you also have to know the call order of three others, and a flag set in a constructor, and some global that gets mutated somewhere else, then you haven't really written a function. You've written a puzzle and scattered the pieces across the repo. Action-at-a-distance is the biggest tax there is on changing code, because before the reader can touch anything they have to rebuild all that invisible context in their head first. Locality is the thing that lets people make correct changes while staying ignorant of 99% of the system.
- Frontend: a component that derives everything from its props and local state vs one whose behaviour depends on a
useEffectthree files away mutating shared context. - Backend: a handler that reads request-scoped, explicitly-passed config vs one reaching into a process-global singleton mutated by middleware.
- Data/ML: a stage that declares its input schema and emits a new dataset vs one that mutates a shared dataframe in place, so stage 7's correctness depends on stage 2's side effects.
Tension: DRY and single source of truth (XIV) push back here. Inlining everything so each unit stands on its own ends up duplicating logic that then drifts apart. Resolve it by scope: keep control flow and invariants local, but let named, owned shared facts live somewhere else as long as the dependency is explicit (II). Duplicating a three-line guard is cheaper than some spooky-action abstraction, and the wrong abstraction costs you more than the copy does, but duplicating the authoritative definition of a fact is exactly (XIV)'s bug. Copy the things that are only coincidentally similar and will drift apart anyway. Unify only what's genuinely the same fact and has to change together.
Ask yourself: To convince myself this code is correct, how far from this screen do I have to look?
Lineage: local reasoning / the frame rule [O'Hearn, Reynolds & Yang 2001]; information hiding [Parnas 1972]; deep modules / complexity-as-cognitive-load [Ousterhout 2018]; coupling and cohesion [Constantine et al. 1974]; action-at-a-distance [Dominus 1999], spooky-action [Einstein 1947]; the wrong abstraction [Metz 2016], Rule of Three [Fowler 1999]; DRY / single source of truth [Hunt & Thomas 1999]; software read more than written [Abelson & Sussman 1985]
II
Make the data flow explicit, and give every ambient dependency one override point
Show where state comes from and where effects go; an ambient dependency with no declared override is a bug you can't see yet.
Globals, mutable module state, and now() and random() in particular, pulled out of the ether, make behaviour depend on things that aren't in the call. So the same inputs give you different outputs and the tests need a séance to reproduce anything. The rule is not "pass everything as an argument". Threading a clock and an RNG down through forty layers is its own kind of parameter soup. The rule is that every ambient dependency has exactly one declared seam a test can actually reach: an injected default, an overridable context, a virtual clock. A controlled seam is fine. An uncontrolled Date.now() buried four frames down with no override is the bug. This is the precondition for both locality (I) and any honest test at all.
- Testing/backend: a function reachable via an injected
clockandhttpClientis reproducible; a hardcodedDate.now()and a module-level client deep inside is a flake you'll chase for days. - Frontend: prefer props and explicit stores to deeply-nested implicit context; one-way data flow exists so you can answer "why did this re-render?"
- Scripting/glue: pass config and paths as arguments, not via a mutated
os.environa reader has to hunt for. Invisible environment state is a debugging trap.
Ask yourself: Could a test pin this behaviour through a single declared override, and if not, which ambient input has no seam?
Lineage: dependency injection [Fowler 2004], dependency inversion [Martin 1996]; seam [Feathers 2004]; test double / virtual clock [Meszaros 2007]; one-way data flow [Facebook 2014]; props vs implicit context [Dodds 2018]; referential transparency [Quine 1960; Strachey 1967]; flaky tests [Micco 2016]; ambient authority [Miller, Yee & Shapiro 2003]
III
Parse, don't validate: make the illegal state unrepresentable
Turn unstructured input into a typed, constrained value once at the door, so the bad shape can't be built or passed on.
Validation answers "is this okay?" and then throws the answer away, so every later function has to ask it again, and some of them forget. The rule holds at thirty-nine of forty call sites. Parsing answers "what is this, exactly?" and hands back a narrower thing (an Email, a NonEmptyList, a PaidOrder) whose validity is carried in the representation itself and can't be un-checked. This tenet is purely about shape: structure refuses the malformed for everyone, forever, including the call sites that don't even exist yet. (Whether a well-formed value is also hostile is (IV)'s job, not the type's: too big, unauthorised, or lying about its identity.)
- Backend/types: separate
UnvalidatedInputandValidatedInputso an unvalidated value physically cannot reach the database call; the boundary cross is the function that changes the type. - Frontend: model UI as a discriminated union (
loading | error | loaded(data)) so "spinner showing and stale data rendered" is literally untypeable, instead of three booleans encoding five nonsense states. - Databases: a
NOT NULL, aCHECK, a foreign key, a partial unique index. The schema refuses the bad row for every writer, including the migration script and the intern at apsqlprompt.
Tension: In Python, JS, Bash, or a notebook the compiler won't carry this for you, and even in strong type systems you can build a whole cathedral of phantom types that nobody can read. The principle survives, just demoted to a single chokepoint that everything funnels through. For tabular or array data there are no per-cell types you can make unrepresentable; the structural form is a schema asserted once at ingestion (pandera, pydantic, Great Expectations) that yields a validated frame downstream code is allowed to assume, with the bad rows quarantined off. For whole-dataset and dynamic-language work, validate-once-at-the-edge isn't a fallback. It is the realistic ceiling, and it still beats forty scattered checks, which beat a comment.
Ask yourself: Past this line, is it structurally impossible to be holding the raw, unchecked form, or am I just adding one more check someone can skip?
Lineage: parse, don't validate [King 2019]; make illegal states unrepresentable [Minsky 2010], popularised [Wlaschin 2013], UI sum types [Feldman 2016]; type-driven development [Brady 2017]; correct by construction [Dijkstra 1976]; phantom types [Leijen & Meijer 1999]; declarative constraints [Codd 1970]; pandera/pydantic/Great Expectations [Bantilan 2018], [Colvin 2017], [Gong & Campbell 2017]
IV
Everything across a trust boundary is hostile until proven otherwise
A well-formed value can still be an attack; bound its size before you allocate, and authorise the actor separately from authenticating them.
Tenet III makes the value well-formed. Tenet IV starts from the idea that a well-formed value can still be hostile, and it guards the things a type can't encode. There are three of them. Crashing on malformed input is a free DoS. Allocating in proportion to a size the attacker picks is the 2 GB JSON body that parses fine and then kills your heap. And trusting an identity or authority that the request merely asserts about itself is the classic privilege escalation. Authentication tells you who; it says nothing about what they may do. So verify the signature, and then check that this subject is actually authorised for this specific action. The boundary is the socket, the form field, the queue message, last week's data dump, a sibling service, and the dependency you import and the CI that runs with your secrets. A library runs with your privileges (tenet XVI), a build job runs with your keys, and the code you didn't write but shipped is still code you shipped. Pin it and verify it.
- Web/backend: cap body size and array lengths before deserialising; re-derive identity from the verified token, never from a
userIdin the payload; client-side validation is UX, not security. - Supply chain: lockfiles with checksums, signature verification, a minimised dependency surface (tenet XXI), and least privilege (tenet XVI) on the build. A typosquat or a poisoned transitive dep is a boundary crossing, not a convenience.
- Embedded/ML: clamp every reading off the bus or ADC to a physical range before it reaches actuator maths; quarantine the row whose null-rate or dtype violates the schema rather than
NaN-poisoning a model you only discover three weeks later.
Tension: Locality and parse-once (tenets I, III) cut the other way here. Re-validating at every internal hop is tenet III's anti-pattern and a latency tax, and zero-trust between your own in-process functions buys you clutter for no real reduction in threat. So bound the trust boundary deliberately: validate and parse once at each real crossing - process edge, deserialisation point, privilege change - and carry the parsed type (tenet III) inward, so internal callers trust the type and not the wire.
Ask yourself: What is the worst single value, or the worst package, the other side could send here, and have I bounded the size, re-verified the authority, and pinned what I trust before acting on it?
Lineage: trust boundary [Swiderski & Snyder 2004]; all input is evil [Howard & LeBlanc 2002]; authn vs authz [Lampson 1971 / Saltzer & Schroeder 1975]; STRIDE (escalation/DoS) [Kohnfelder & Garg 1999]; least privilege & complete mediation [Saltzer & Schroeder 1975]; bound size before allocating [OWASP API4 2023], billion laughs [Billion Laughs 2002], zip bomb [Zip bomb 1996]; supply chain pin & verify [SLSA / Sigstore 2021], typosquatting [Tschacher 2016]; zero trust [Kindervag 2010]; client-side validation is UX [OWASP Input Validation 2021]
V
Keep the responsive path free of uncontrolled-latency work
A path that owes someone a deadline must never wait inline on work whose completion depends on a party you don't control.
A UI thread, an event loop, a request handler, a game frame, a scheduler tick - each one is a heartbeat with a deadline it owes to a user's eye, or a watchdog, or a 16 ms frame budget. The instant it synchronously calls a slow network, or a disk, or a lock held by who-knows, its responsiveness is hostage to a stranger's worst day. The general move is to get that work off the responsive path and make it observable, and the right mechanism depends on the domain: async/await plus a pending state in a UI; a job queue and a 202 in a service; an off-thread load in a game loop that the frame reads if it's ready; a background process or a separate stage in a script, so the one thread a human is watching never goes dark. In a concurrent server the specific form is a bounded queue with a separate worker that returns an explicit "full" as backpressure, but the queue is just one instance of the rule, it isn't the rule.
- Frontend: hand a heavy parse to a Web Worker and render a pending state; a synchronous
fetchor a data-dependent 200 ms sort on the main thread freezes scroll and input. - Backend: enqueue the third-party call or the transcode, return
202, surface "queue full" as a503. Don't tie your tail latency to their bad day until the thread pool starves. - Scripting/data: a long step belongs in a background job or a separate stage, not inline on the only thread, where the user sits staring at a dead terminal.
Tension: A queue absorbs bursts, not sustained overload. Under sustained load a deep buffer just delays the rejection and fills up with already-dead work, every item past its deadline by the time you reach it. Pair it with deadline-aware shedding: fast-reject work whose deadline (tenet VI) will expire before you serve it, prefer freshest-first, and add the seam only where a real uncontrolled-latency dependency exists. Watch out for the data-dependent case. In-process work whose cost scales with input you don't bound - a client-side sort over user data, say - is an uncontrolled-latency path even though it's "yours", so measure it at realistic scale before you decide.
Ask yourself: On this responsive path, am I waiting on anything whose worst-case latency I don't control, and if it never returns, does my system look dead?
Lineage: don't block the event loop [Node.js (Don't Block the Event Loop)]; 16 ms frame budget [Irish & Lewis 2015], 100 ms threshold [Miller 1968]; Web Worker [WHATWG / Hickson 2009]; async/await [Syme 2007; C# 5.0 2012]; 202/503 [RFC 9110 2022]; backpressure [Reactive Streams 2015], bounded buffer [Dijkstra 1965 (EWD123)]; tail latency [Dean & Barroso 2013]; load shedding & deadline-aware shedding [Ulrich 2016], [Maurer 2015]; deep buffer just delays rejection [Little 1961]; watchdog/heartbeat [Murphy & Barr 2001]; game-loop decoupling [Fiedler 2004; Witters 2009]
VI
Every wait across an uncontrolled boundary has a deadline
A cross-boundary call with no timeout is a bet that the other side is always fast and always answers; you will lose it.
Scope this to waits that cross a boundary you don't control: a network, an IPC, a lock you don't own. A hung dependency without a deadline doesn't fail, it spreads. It eats the caller's threads, then the caller's caller's threads, until one slow database melts the whole fleet. A deadline turns an unbounded hang into a bounded, observable error. But a deadline only protects you from a hung dependency, not from a slow-but-progressing one. A six-hour training run, a 50 GB sort, a multi-hour query - that's correct long work, and an arbitrary timeout would just kill it. The right tool there is progress, heartbeat, and cancellation, not a wall-clock cutoff. There are two hard parts the headline hides. A timeout that doesn't cancel and propagate just orphans the slow work (tenet VII) and may fire a duplicate, so a deadline is only safe when the operation is cancellable or idempotent (tenet X) on retry. And the retry policy that follows from all this lives in tenet XIX, not here.
- Distributed systems: propagate a deadline through the call chain, so a 5 s edge budget isn't spent waiting on a service that itself waits 30 s.
- Databases: set
statement_timeoutand connection-acquisition timeouts; one runaway query must not hold a pool slot forever. - Data/ML (the exception): a legitimately long batch job gets cancellation and a progress signal, not a deadline that murders correct work at hour five.
Ask yourself: Does this wait cross a boundary I don't control, and if so, what's the cutoff, is the work cancellable or idempotent if it fires, and where is the number written down?
Lineage: Timeouts / Fail Fast stability patterns [Nygard 2007]; cascading failure & deadline propagation/budget [Ulrich 2016]; deadline vs timeout [Sheehy 2015]; statement_timeout [PostgreSQL 2002], connection-acquisition timeout [Wooldridge 2013]; cooperative cancellation [Microsoft 2010]; idempotent retry-safety [RFC 7231 2014], idempotent term [Peirce 1870]
VII
Bound what callers can create; release what you acquire
Every resource has a ceiling, and everything you acquire has exactly one owner that releases it on every exit path, including error and panic.
Anything a caller can ask for in a loop (connections, threads, queue depth, retries, cache keys, recursion, payload size) is a DoS or an OOM waiting to happen, whether it's an attacker who triggers it or just your own retry storm. And anything you go and acquire (a goroutine, a timer, a subprocess, a subscription, a file handle, a lock) is an orphan-in-waiting unless something releases it. In garbage-collected and scripting languages the runtime reclaims memory and nothing else: a subscription, timer, subprocess, file handle, or lock is still yours to release by hand. Use the language's scoping construct where there is one (with, defer, try/finally, RAII) and release manually only where there isn't. "Unbounded" is just a synonym for "fails later, mysteriously, in production".
- Backend: a fixed pool with a wait-or-reject policy degrades into
503s; unbounded connection or thread creation per request turns a spike into a death spiral. - Data/ML: cap batch size and parallelism, or one skewed key OOMs the cluster; cap retries with backoff or a flaky upstream becomes a self-inflicted DDoS.
- Mobile/frontend: an unbounded image cache is an OOM kill; a timer or listener registered on mount and not torn down on unmount leaks the screen the user already left.
Tension: This invites the YAGNI objection. Not every list needs a configurable max today, and premature limits become wrong limits that page you at 3am. The way out is to ask who controls the growth. If it's caller-driven, external-input-driven, or unbounded-by-time, it always gets a ceiling. The twelve months of the year do not. A missing limit isn't a missing feature, it's an unbounded liability. The owner rule, unlike the ceiling, can't be negotiated away.
Ask yourself: What's the maximum this can grow to, who controls that (me or my caller), and on every exit path, what releases what I acquired?
Lineage: RAII [Stroustrup 1994], single-owner Drop [Klabnik & Nichols 2018], language scoping [Klabnik & Nichols 2018]; bound the unbounded / Unbounded Result Sets & Bulkhead [Nygard 2007]; bounded pool wait-or-reject [Wooldridge 2013], 503 [RFC 9110 2022]; cap retries with backoff+jitter [Brooker 2015]; GC reclaims memory not external resources [Bloch 2001]; YAGNI applies to features not limits [Beck 1999]
VIII
Tear down what you set up; subscribe for latency, reconcile for correctness
Every subscription, listener, or handle you register has a teardown that runs when either side goes away, and prefer the event over the timer, except where the event is silence.
A cache, a registry, an observer, a parent supervising its children will routinely outlive the thing it references. In a garbage-collected language the rule is about lifecycle and not memory: clean up the listener on unmount, or it goes on firing callbacks into a thing that no longer exists. The manual-memory version (Rust, C++, Swift/ARC) is where you actually choose the reference strength, and there the trade gets sharp. A strong claim from the long-lived side wedges teardown and leaks. A weak claim risks the watched thing being collected or evicted out from under a user who's still active (the listener that quietly stops, the cache entry that vanishes mid-use). Hold weak where the watcher survives the watched disappearing, and hold strong-with-explicit-teardown where it doesn't. And learn that something is finished from the event (a close, a done, an unmount, a DMA-complete interrupt) rather than from a clock.
- Frontend: a listener set up on mount and removed on unmount; the missing cleanup keeps a dead component alive and updating.
- Mobile / manual-memory: a callback strongly retaining a screen pins it after the user left; the long-lived side holds weakly, the short-lived side owns. In embedded, detect "DMA done" from its completion interrupt, not a status-bit poll.
- Distributed/backend: subscribe to the close event for latency, but keep an idempotent (X) reconciliation sweep for correctness. Across a boundary you can miss the edge.
Tension: Events are sharp but lossy. A pure event-driven design is right only when the event is guaranteed to be delivered somewhere you can't miss it. When completion is absence (a crash, a hang, a disconnect emits no event at all), a timer or heartbeat is the only signal you'll get, and a missed edge across a boundary (IV) wedges you forever. So subscribe for latency, but keep a level-triggered, convergent reconciler (X) for correctness. Poll where the truth is silence and subscribe everywhere else.
Ask yourself: Does every thing I registered have a teardown, and am I learning "it's done" from an event, with a reconciler behind it for the edge I might miss?
Lineage: edge vs level-triggered control loops [Hockin 2017], hardware origin [Intel 8259 1976]; self-stabilisation / convergent reconciler [Dijkstra 1974]; effect cleanup on unmount [React 2019], observer Attach/Detach [GoF 1994]; lifecycle not memory / RAII [Stroustrup 1994], strong/weak refs & retain cycles [Apple 2011]; completion-is-absence / failure detection [Chandra & Toueg 1996]; idempotent sweep [Peirce 1870]
IX
Check-then-act on shared state is a race unless it's atomic or serialised
If two actors can interleave between your check and your act, the check is a guess.
if not exists: create, if balance ≥ amount: debit, "reserve the last seat": every one of these is two operations pretending to be one. This only bites where two actors can actually interleave, so concurrent requests, multiple workers, overlapping cron runs, parallel partitions. In code that's genuinely single-threaded and single-run there's no window, and the heavy machinery is just waste. But "it's single-threaded" is the assumption that turns out wrong most often at scale, and the window is invisible in review and devastating in production. The correct fixes come in three families, and the reader should be able to see which one you picked: atomicity (one indivisible step, including optimistic compare-and-swap on a version, then retry), serialisation (one owner, or a consistent lock order), or commutativity (make the act idempotent so the race does no harm).
- Databases:
INSERT ... ON CONFLICTor a unique constraint, notSELECTthenINSERT;UPDATE ... WHERE balance >= amountchecking rows-affected, not read-modify-write. - Distributed systems: a compare-and-swap or a fenced lease, not "read the flag, then take the lease", and expect to be wrong about holding it.
- Frontend/scripting: disable on submit or dedupe by request id, or two rapid clicks double-charge; two overlapping cron runs claim work by atomic rename, not by checking a "processing" flag.
Ask yourself: Can two actors actually run this between my read and my act, and if so, have I made that window atomic, serialised, or harmless?
Lineage: check-then-act / read-modify-write compound actions [Goetz 2006]; TOCTOU [McPhee 1974; Bishop & Dilger 1996]; atomicity [Härder & Reuter 1983], linearisability [Herlihy & Wing 1990]; compare-and-swap [IBM System/370 1970], optimistic concurrency [Kung & Robinson 1981]; serialisability [Eswaran et al. 1976], lock ordering [Coffman et al. 1971]; commutativity [Shapiro et al. 2011], idempotent [Peirce 1870]; fenced lease [Kleppmann 2016], lease [Gray & Cheriton 1989]; INSERT ... ON CONFLICT [PostgreSQL 9.5 2016]
X
Make operations idempotent so "do it again" is always safe
In a world of retries, redelivery, and at-least-once everything, the only safe operation is one that's harmless to repeat.
Where (IX) is about concurrent interleaving of one logical attempt, X is about sequential re-delivery of the same attempt: the lost ack, the redelivered message, the double-click, the job re-run after a crash. They share a fix, a stable key, but the failures they prevent are different. If "apply once" and "apply twice" don't give the same result, then every retry becomes a corruption, which is why idempotency is the thing that makes (XIX)'s retries, crash recovery, and at-least-once messaging safe instead of dangerous. Key your writes by a stable id, make creates upserts, and make the pipeline re-runnable from any point.
- Backend: an idempotency key on payment and order creation returns the original result on retry instead of charging twice.
- Data/infra: a Terraform run or a batch job you can re-execute to the same end state recovers from a half-finished run by just running it again, with no forensic cleanup.
- Distributed/messaging: consumers dedupe by message id, so at-least-once delivery behaves like exactly-once where it counts.
Tension: Idempotency keys, dedupe tables, and reconciliation are real machinery with storage and expiry. Don't build it for a read that's genuinely safe to repeat. Spend it where a repeat mutates money, state, or the outside world.
Ask yourself: If this runs twice because something retried, is the result identical to running it once?
Lineage: idempotent term [Peirce 1870], idempotent methods / retry-safety [RFC 7231 2014]; idempotency key [Leach 2017]; at-least-once delivery [Birrell & Nelson 1984], exactly-once is faked [Treat 2015], dedupe-by-id [Confluent 2017]; Two Generals (the lost ack) [Gray 1978]; upsert [SQL:2003 MERGE]; convergence to end state [Burgess 1995]; 'two hard problems' aphorism [Verraes 2015]
XI
Separate the irreversible decision from its effect
Make "should we / which ones" a pure, exhaustively-testable function that returns a plan; make the doing a thin wrapper that only executes the plan.
The catastrophic verbs - delete, kill, charge, send, overwrite, launch - are dangerous mostly because the reasoning is fused right into them. A delete() that works out what to delete while it's deleting can't be tested without something actually getting deleted, so the code that most needs proof is the code you end up testing least. Split them. A pure whichRowsToPurge(state) -> ids can be hammered with ten thousand cases and no side effects at all, and the wrapper that takes those ids and runs DELETE is small enough to read in one breath. This seam is also the thing that makes dry-run, four-eyes approval and undo possible. They all hook in here.
- Backend/billing:
decideCharge(cart) -> ChargeIntentis property-tested to death; the gateway call merely realises a fully-formed, idempotent (X) intent and never touches a live gateway in a test. - Data engineering: the job computes the diff as a reviewable manifest, logs it, dry-runs it; a separate trivial step applies the approved plan. Never fuse the query and the
rm. - Infra/scripting:
terraform planthenapply; thefind -deleteone-liner that fuses choosing and deleting is how you erase the wrong directory at 2am.
Tension: The plan goes stale, a TOCTOU window (IX). The split brings back the very race (IX) warns about, because the plan was computed against a snapshot that the effect may no longer match by the time you apply it. Close it: pin the plan to a state version and re-check at apply (compare-and-swap on the version), or make the effect conditional on the precondition still holding. A stale plan applied blindly is the race you split the code to avoid in the first place. And where the verb is cheap and undoable, skip the seam altogether. The intermediate plan is just ceremony for trivial, reversible actions.
Ask yourself: Can I test this irreversible decision without doing it, is the doing-part obviously correct, and is the plan still valid at the moment it executes?
Lineage: functional core, imperative shell [Bernhardt 2012]; command-query separation [Meyer 1988]; plan/apply [HashiCorp 2014]; dry-run; four-eyes [Four-eyes principle]; property-based testing [Claessen & Hughes 2000]; humble object [Feathers 2002], sans-IO [Benfield 2016]; TOCTOU window [McPhee 1974; Bishop & Dilger 1996], CAS-on-version [IBM System/370 1970]; Decider [Chassaing 2021]
XII
Finish your obligations before you exit
Stop accepting new work, drain or hand off in-flight work within a bounded deadline, flush and ack only what is durably done, then exit.
Shutdown isn't the absence of work. It's the last work you owe, and the one most likely to get skipped. A process that exits with buffered writes unflushed, or messages consumed but not acked, or requests dropped halfway through a handshake, doesn't fail loudly. It quietly loses whatever someone downstream was counting on, and you find out later from a data discrepancy that nobody can explain. The OS reclaims memory, never meaning. The floor here applies to everything, even a one-shot script: leave either a complete output or none at all. Write to a temp path and atomically rename on success, so a half-written CSV never gets mistaken for a finished one, and trap signals to clean up. And since you might get killed abruptly anyway, the durability contract has to live somewhere else too - a WAL, at-least-once redelivery, idempotent writes (X) - so that an abrupt exit is survivable by design rather than by luck.
- Backend: on
SIGTERM, stop the listener, drain in-flight requests within a grace window, close the pool, then exit. A rolling deploy drops zero requests instead of 500-ing every connection mid-flight. - Scripting/data: the killed script leaves a complete file or nothing: temp-write-then-rename, and a signal trap that removes partials; commit the stream offset only after the record is durably written, because ack-before-persist silently eats data on restart.
- Mobile/embedded: flush unsaved state and queued analytics on background or low battery; the OS may kill you without a second warning, and the user's last edit is your obligation.
Tension: Unbounded graceful drain is its own kind of hang. A shutdown that waits forever for a stuck request is no better than one that just drops it. Bound the drain with a deadline (VI), then force-exit.
Ask yourself: If this were told to stop right now, what has it accepted that would silently vanish, and does my shutdown path complete those obligations within a deadline?
Lineage: graceful drain [Envoy 2017], SIGTERM grace window [Dinesh 2018], signal trap [POSIX signal(7) 1988]; atomic temp-then-rename [POSIX rename() 2024], maildir idiom [Bernstein 1995]; write-ahead log [Gray 1978]; durability (ACID) [Härder & Reuter 1983]; at-least-once taxonomy [Spector 1982]; idempotent writes [Peirce 1870]; crash-only [Candea & Fox 2003]; commit offset after durable write [Confluent 2017]
XIII
Failure modes must be visible and impossible to swallow
Make every way this can fail legible to the next reader without running it, and handle failure where the context to decide lives; the sin is the silent swallow, not the keyword.
When a failure is an invisible exception tunnelling up through ten frames, the reader sitting in any one of those frames can't see what might blow up beneath them, so handling turns into guesswork and the happy path becomes a lie. The invariant is that failure stays visible and can't be ignored. The mechanism, though, is whatever your language makes idiomatic. A Result or (value, err) where you have them, so the tooling nags you to handle the case. Typed exceptions caught at a deliberate boundary, where exceptions are the idiom (Python's EAFP, Ruby), count as a first-class way of doing this and not a fallback, as long as there's no bare except: or empty catch. Error codes with no allocation in embedded. A swallowed error is a wrong state that has learned to hide.
- Backend / Go-style:
(value, err)forces the caller to confront failure at the call site, where the context to handle it lives. - Frontend: a fetch returning
{ ok } | { error }, or a typed exception caught at one boundary, lets the component render the error state by design instead of an unhandled rejection vanishing into the console. - Scripting/glue (fail fast):
set -euo pipefailso a failed step halts the chain; the default (a failed command ignored while the script charges on, corrupting the next step) is the trap.
Tension: Fail-fast and degrade (XIX) want opposite things. Threading errors everywhere can drown the happy path, so let them propagate with minimal ceremony (
?, monadic bind, one catch boundary) to where the context to decide lives. And the two error stances really do conflict. A glue script or a data pipeline should halt loudly on the first bad step, because carrying on corrupts everything downstream. A long-running service should degrade (XIX) instead, because halting is an outage. Choose by blast radius: abort where a wrong result silently propagates, degrade where staying up with less is the lesser harm.
Ask yourself: Can the next reader see this call can fail just by reading it, and is there any path where the failure silently disappears?
Lineage: Python's EAFP [Python Glossary (EAFP/LBYL)]; errors-as-values [Pike 2015], (value, err) at the call site [Gerrand 2011]; Result/Either, monadic bind [Moggi 1991; Wadler 1992],
?operator [Rust RFC 243 2014]; swallowed-error anti-pattern [Howard & LeBlanc 2002]; fail fast [Shore 2004]
XIV
One source of truth; derive the rest
Every fact has exactly one authoritative owner; everything else is a computed or subscribed view.
The same fact stored in two places is two facts, and sooner or later one update misses the other and they disagree. Not if, when. The cache that drifts from the rows it's meant to count, two denormalised columns, two services each holding a writable copy of "the user's plan" - every one of those is a future bug where the system holds two beliefs at once and you can't tell which one is real. Pick the owner, derive everything downstream from it, and make the derivation cheap enough that you're never tempted to cache a second copy.
- Databases: the normalised table is truth; a materialised view is a derivation the database keeps honest, not a hand-maintained duplicate two writers update independently.
- Frontend: server state is the source; the client cache (React Query, a store) is a derived view with explicit invalidation, not a parallel kingdom of truth you sync by hand and pray.
- Distributed/config: one service owns each entity; others hold read replicas or projections clearly marked as derived, never a second master.
Tension: Declared divergence is fine; undeclared is the bug. Caches and read replicas are deliberate, valuable duplications, and so is UI that diverges on purpose. An optimistic update or an in-progress form draft is meant to be temporarily "wrong" relative to the server. So the rule isn't "never copy". It's that every copy has a named owner, an invalidation path back to the source, and a staleness budget, and for deliberate divergence you also add a defined reconciliation point where the server confirms or you roll back. A copy only earns the name engineering once it's declared, invalidated and reconciled. Short of that it's just a bug.
Ask yourself: If these two copies disagreed at 3am, which one is right, why does the other exist, and where does it reconcile?
Lineage: single source of truth / DRY [Hunt & Thomas 1999]; client cache as derived view of server state [Linsley 2020], optimistic update confirm-or-rollback [TanStack & Apollo 2016]; materialised view & schema synthesis [Kleppmann 2017]; ubiquitous-language ownership [Evans 2003]; cache invalidation is hard [Karlton 1996]
XV
Name the boundary, version the contract: strict in, tolerant of the unknown
Every place control, data, or trust changes hands is an interface; declare it on purpose, and evolve it without breaking consumers you can't force to upgrade.
A boundary you didn't design is one your bugs designed for you. When a module reaches into another's internals, when a service trusts an undocumented header, when the ORM table shape leaks into the public JSON, you've got an implicit contract nobody can see, test, or change safely. And contracts live in time. Clients persist, events sit in queues for days, and mobile apps you can't force-upgrade keep sending last year's payload at you. So evolve additively, give every deprecation a window, and settle the strict-vs-tolerant question precisely: reject what violates an invariant you depend on; ignore what you simply don't understand (the unknown-additive field from a newer or older peer). The boundary parser is now your most security-critical, most-tested code, because a bug there is a bug everywhere downstream that trusted it.
- Backend/API: the public response is a contract pinned by a test that fails the instant a refactor drops a field; add fields, never repurpose them, version the breaking change behind a deprecation window.
- Distributed/data: a wire or event schema evolves with tolerant readers and forward/backward compatibility (Avro, Protobuf rules), because a consumer on old code is not a bug, it's Tuesday.
- Mobile: the server serves clients three versions back; "everyone updates" is a wish, not a deployment strategy.
Ask yourself: If I shipped this and an old consumer hit it unchanged, would it break, and does this contract reject what it must while ignoring what it merely doesn't recognise?
Lineage: Postel's robustness principle [Postel 1980 (RFC 761)], reconsidered [Allman 2011]; tolerant reader [Fowler 2011]; Hyrum's Law [Wright 2012]; consumer-driven contracts [Robinson 2006]; SemVer [Preston-Werner 2013]; schema evolution / forward-backward compat [Kleppmann 2012]; deprecation/sunset window [Wilde 2019]; interface as designed boundary [Parnas 1972]; boundary parser as most-tested code [Sassaman et al. 2011]
XVI
Least privilege, by construction
Give every component the narrowest authority that lets it do its job, so a bug or breach is contained by what it was never granted.
Authority you hand out is authority that can be misused. Maybe by an attacker who compromises the component, maybe by a bug that does the wrong thing with full power, maybe by some future caller who never knew the power was sitting there. This is the runtime sibling of "make over-reach unrepresentable" (tenet III): containment is cheaper than trust. It also reads as honest intent. A function that takes only the two fields it touches, rather than the god-object, tells the reader exactly what it can affect.
- Backend: the reporting job connects with a read-only role, so a SQL injection in it cannot drop a table it has no grant to drop; scope tokens short and narrow.
- Cloud/infra/supply chain: a function scoped to one bucket can't exfiltrate the others when a dependency is compromised; the CI job (tenet IV) gets only the secrets it needs. Broad
*IAM is the difference between an incident and a catastrophe. - Frontend: an iframe with a tight
sandboxand aContent-Security-Policywhitelisting origins gives third-party code exactly the powers you grant and not one more.
Ask yourself: If this component were fully compromised or simply buggy, what's the most it could touch, and does it actually need all of that?
Lineage: least privilege & fail-safe defaults [Saltzer & Schroeder 1975]; least authority (POLA) [Miller 2006], capability [Dennis & Van Horn 1966]; OAuth scopes [Saltzer & Schroeder 1975], IAM least privilege [AWS 2023]; iframe sandbox [WHATWG / Hickson 2009], Content-Security-Policy [WAF / CSP Stamm et al. 2010]; god-object counterexample [Riel 1996]; SQL injection bounded by read-only grant [Forristal 1998]
XVII
Measure, then make the common case fast, but bound the unbounded without a profiler
Performance is a falsifiable property of the running system, not a vibe; profile before you trade clarity for speed, except for complexity in caller- or attacker-controlled size, which is a correctness bug you fix on sight.
The O(n²) that's instant on dev data melts at production scale, and the per-row round-trip (the N+1 query, the chatty RPC) is the most common latency-and-cost disaster in software and stays invisible right up until the data grows. Your intuition about where the time goes is usually wrong on cold or unfamiliar paths, so measure those first. But there are two carve-outs that override "measure first". One is that complexity which is super-linear in caller- or attacker-controlled input is the DoS of tenets IV and VII rather than a tuning question, so you bound or fix it without a profiler... "dev data was fine" is exactly how it ships. The other is that some antipatterns are reliable enough to fix on recognition, no profile required: the N+1 round-trip, the per-row loop over a vectorisable op, the per-frame allocation. "Measure first" only governs which legible code you're allowed to make illegible. It never licenses an unbounded blowup.
- Databases/backend: batch the N+1
SELECTinto one query with a join orIN; the innocent-looking loop is 500 round-trips per request. - Data/ML: vectorise or push the filter into the engine instead of a per-row Python loop: hours vs seconds, dollars vs cents.
- Game/embedded: lay out data for cache locality and amortise allocation out of the hot loop; a per-frame
mallocis the dropped frame you can't profile away later.
Tension: Speed here is paid for in simplicity and the reader (tenets I, XXI). Every optimisation spends clarity. Buy it only where a profiler proved you must, and keep the cold 95% legible, because that's where the next bug hides. And throughput is money: unbounded fan-out, retained data and always-on compute are financial failure modes, not just slow ones.
Ask yourself: Is this cost in caller-controlled size (then bound it now, no profiler) or a known antipattern (then fix it), or am I rewriting cold, readable code into clever code I never measured?
Lineage: premature optimisation / measure first [Knuth 1974], measure before tuning [Pike 1989]; make the common case fast [Hennessy & Patterson 1990], Amdahl's law [Amdahl 1967]; N+1 / chatty interface [Fowler 2002]; algorithmic-complexity DoS [Crosby & Wallach 2003]; vectorise [Iverson 1962]; cache locality [Bell 1978]
XVIII
Make it observable, or you are guessing
Correctness is a property of the running system; emit the signals that prove your invariants held, and instrument the failure modes, not just the happy path.
You will not debug a partial failure from a stack trace, because often there isn't one: there's a latency cliff, a rising error rate, a queue depth creeping up, a retry budget quietly draining away, a silent fallback nobody noticed for a week. Observability is the verification layer, the thing that makes every other tenet checkable in production rather than just intended back in review. Queue depth (V, VII), rejection and retry counts (VI, XIX), breaker state (XIX), source-vs-cache drift (XIV), deadline budget remaining (VI), input-distribution and null-rate drift (IV). And this is not "log everything", because noise is its own kind of failure.
- Backend/distributed: a trace id running through every hop turns "it's slow somewhere" into "it's slow here", and RED/USE metrics make saturation legible before it's an outage.
- Data/ML: track records-in vs records-out, freshness/lag, and prediction drift. The model didn't throw anything, it just quietly got worse as the world moved on.
- Frontend/embedded: real-user monitoring and client error reporting show you the crash on the device you'll never
sshinto, and a bounded counter for missed deadlines turns "feels janky" into a number.
Tension: Telemetry is itself an unbounded resource (VII) with a cost and a leak risk: sample it, bound it, and never log the secret.
Ask yourself: When this invariant breaks at 3am, what signal tells me, and is it already being emitted?
Lineage: observability [Kalman 1960], software framing [Bourgon 2017]; three pillars [Bourgon 2017], [Sridharan 2018]; distributed tracing [Sigelman et al. 2010]; RED [Wilkie 2015], USE [Gregg 2012], golden signals & SLOs [Beyer et al. 2016]; alerts must be actionable, noise is its own failure [Ewaschuk 2013]; model/data drift [Schlimmer & Granger 1986]; never log the secret [OWASP Logging Cheat Sheet]
XIX
Degrade in tiers; contain the blast radius
When a dependency dies, lose a feature, not the system, and make sure one tenant's bad day isn't everyone's.
This tenet owns the retry lifecycle the others defer to.
What separates an incident from an outage is whether the failure stays contained. A recommendations service falling over should give you a page without recommendations, not a 500. Design the fallback before you need it, whether that's a cached value, stale-but-serviceable data, or a degraded mode. Containment is the spatial twin: bulkheads, per-tenant quotas, separate pools, and cell isolation all make sure a poisoned input or some greedy customer can't take down the shared substrate. Retries live here, in full: a budget, exponential backoff, jitter so that clients that failed together don't all retry together into a thundering herd, and a circuit breaker that fails fast to give the downstream some room to heal, which is only safe because the operation is idempotent (X) and the wait was deadlined (VI).
- Frontend: an error boundary around a widget shows a fallback just for that widget while the rest of the app keeps working, instead of white-screening the whole thing.
- Distributed systems: bulkhead thread pools per dependency, so a slow downstream exhausts its pool and not the service's; a breaker plus jittered backoff turns a blip into graceful degradation rather than a retry storm.
- Data/ML: if the live feature store is down, serve a cached or default feature vector and a slightly worse prediction instead of erroring the request.
Tension: Fallbacks and bulkheads are real complexity, and an untested degraded path is just a second bug waiting for the worst moment to fire. Build the tiers you'll actually exercise, and rehearse them. (And note the genuine conflict with (XIII)'s fail-fast: degrade where staying up with less is the lesser harm; abort where proceeding corrupts.)
Ask yourself: When this dependency is down or this tenant goes rogue, what's the smallest thing I can lose, and have I ever actually run that path?
Lineage: circuit breaker, bulkheads, fail fast [Nygard 2007], [Shore 2004]; graceful degradation & retry budget & load shedding & cascading failure [Beyer et al. 2016], [Ulrich 2016]; blast radius & cell isolation [AWS 2019]; backoff + jitter [Brooker 2015], thundering herd [Molloy & Lever 2000]; idempotent retry [RFC 7231 2014]; error boundary [React 2017]; rehearse the tiers [Principles of Chaos 2015]
XX
Optimise for reversibility, deletion, and change
Prefer decisions you can undo; build a seam only when you can name the second concrete thing that will go through it.
Software is in motion. The code you write will be wrong about something, and the only real question is how expensive being wrong turns out to be. Reversibility at deploy time, things like feature flags, expand-then-contract migrations, canary and shadow deploys with auto-rollback, soft deletes, lets you ship into reality, watch (XVIII), and back out again without any ceremony. Reversibility at build time, a vendor behind a narrow interface, a feature behind one flag in one folder, a model behind a stable scoring interface, lets you swap or delete a piece without an archaeology dig for all its tendrils. The big-bang rewrite and the irreversible one-shot migration aren't bold, they're bets you've forbidden yourself from losing gracefully.
- Backend/DB: expand → backfill → dual-write → switch reads → then drop keeps every intermediate state runnable and rollback-able; the drop-and-rename in one transaction is a cliff.
- Frontend/mobile: ship behind a flag and ramp 1% → 100%, so a bad release is a config toggle and not an app-store resubmission.
- ML/data: shadow-deploy the new model on live traffic and promote it on evidence; write to a new partition and swap pointers, because overwriting in place destroys the only thing that could have saved you.
Tension: Two faces here, the seam test and the duty to forget. Speculative flexibility is the most expensive clutter there is. The test for a seam is concrete: build it only when you can name the second real thing that will go through it (the second vendor, the actual rollback you'll run) with an owner and an expiry. One hypothetical future is not a seam, it's clutter; give every flag and scaffold an owner and a sunset, or you'll drown in zombie flags. And reversibility collides with a real duty to forget: data you keep is breach surface and legal liability (deletion rights). Soft-delete for recoverability, but keep a true hard-delete path and an encoded retention policy for the data you must destroy: a TTL, a droppable partition, or column-level classification (IV). Resolve it per data class, and never default to keep-forever.
Ask yourself: When this is wrong in a year, is the fix a scalpel or a demolition, can I name the second thing using this seam, and is anything here data I'm obligated to delete?
Lineage: reversible vs irreversible decisions [Bezos 2016]; feature flags / sunset [Hodgson 2017]; expand→contract / parallel change & canary [Sato 2014]; dark/shadow launch [Letuchy 2008]; big-bang rewrite trap [Spolsky 2000], strangler fig [Fowler 2004]; speculative generality [Fowler 1999]; seam [Feathers 2004]; deletion rights [GDPR 2016 (Art. 17)], TTL/retention [RFC 1035 1987]; reversible deploys [Forsgren et al. 2018]
XXI
Simplicity is the budget that funds everything else
The state you don't have can't be wrong; remove the case before you handle it, and delete more than you add.
Software is the only material where having more of it makes the rest heavier. Some complexity is essential, it belongs to the problem itself, and you have to carry it. The rest is accidental, some of it yours and some of it imposed on you: the abstraction for a future that never came, the configurability nobody asked for, the "temporary" flag that became a permanent branch. The most reliable way to handle a failure mode is to not have it in the first place. A stateless handler can't have stale state, an idempotent op can't be corrupted by a retry, a deleted config option can't be misconfigured. Reach for fewer states before more guards. Subtraction is real progress. The dead branch you leave behind is the one that springs back on you in an incident.
- Backend: three small obvious services beat one "flexible" engine driven by a config DSL that reinvents a programming language badly; rip out the flag once the rollout is done.
- Frontend: local component state beats a global store until shared state actually demands one; delete the unused component and its CSS, since "we might reuse it" is what version control is for.
- Data/ML: a SQL query beats a Spark job beats a bespoke framework, until the data size forces the next tier: pay for the tier when the problem bills you, not before.
Tension: Simplicity now can mean rigidity later (vs the seams of tenet XX), and the simplest local choice can end up duplicating something (vs tenet XIV). When those pull against each other, go back to this manifesto's root: keep down what the next human has to hold in their head to make a correct change. YAGNI is about features. It is not about limits (VII) or failure handling, where a missing guardrail is just a liability dressed up to look like simplicity.
Ask yourself: Can I delete this state, flag, or branch entirely instead of writing the code that keeps it correct?
Lineage: essential vs accidental complexity [Brooks 1986], mutable state as accidental complexity [Moseley & Marks 2006]; simplicity → reliability [Dijkstra 1975 (EWD498)], [Hoare 1980]; YAGNI [Beck 1999]; config DSL reinvents a language [Greenspun 1993], worse is better [Gabriel 1990]; subtraction is progress [Saint-Exupéry 1939]; components that aren't there [Bell 1978]; software gets heavier [Lehman 1974]; idempotent [Peirce 1870]
XXII
Name to reveal, not to label
A name is the cheapest documentation and the most-read line of code; encode the one fact a reader gets wrong without it, because a misleading name is worse than none.
A reader spends more time reading names than any other token, and a precise name lets them skip the body altogether. retryWithBackoff tells you more than handle does, and pendingChargesByAccount tells you more than data. A misleading name is worse, because it installs a false model that the reader then debugs against for an hour. So encode the load-bearing fact that the type can't already carry: the unit, the ordering, whether there's a side effect.
- Backend:
chargeOnceIdempotent(key)warns you about the semantics;doCharge()hides them right up until the duplicate-billing incident. - Data:
revenue_usd_centsis unambiguous everywhere it shows up;amountinvites the unit-mismatch bug that ships a 100x error. - Frontend:
useDebouncedSearchtells you when it fires; withuseSearchthe reader has to open the file every single time.
Tension: A name that encodes an invariant is, in effect, a duplicate of that invariant (XIV), and the duplicate can drift. The day idempotency gets dropped you have to rename
chargeOnceIdempotenteverywhere it appears, or the name now lies - which is the exact failure it was meant to warn against. So where a type (III) can carry the invariant, let it, and keep name-encoding for the facts no type captures: units, ordering, whether there's a side effect. Don't try to encode everything either (getUserByIdWithRetryAndCacheFromPrimaryReplica): reveal the one fact and let locality (I) carry the rest. It's precision you want, not length.
Ask yourself: Could a reader predict what this does, its units, and its caveats from the name alone, and is this name a fact no type already carries?
Lineage: naming is hard [Karlton 1996]; intention-revealing / avoid disinformation names [Martin 2008]; ubiquitous language [Evans 2003]; units-in-names / Hungarian [Simonyi 1999; Spolsky 2005], unit-mismatch failure [NASA MCO 1999]; precision-not-length [Fowler 1999]; idempotent semantics in names [Peirce 1870], [RFC 7231 2014]
XXIII
Time is an input that lies; measure with a monotonic clock, order with logic
Wall-clock time is not trustworthy: it steps backwards, skews across machines, and cannot establish causality; treat it as the hostile input (IV) it is.
The manifesto leans on now() and deadlines (II, VI) and ordering (IX), and all of that breaks the moment you trust the wall clock. Measure every duration, deadline, and timeout against a monotonic clock, because the wall clock jumps backwards on NTP correction and on leap seconds. A deadline measured against the wall clock can fire instantly, or it can fail to fire at all. And don't establish ordering or causality across machines by comparing timestamps - two events' wall-clock times prove nothing about which one actually happened first. Use logical or causal ordering instead, or a fenced sequence (IX). A TTL or token expiry checked against the wall clock can be shifted by a clock jump, or by an attacker.
- Distributed systems: order events by a logical clock or a fenced sequence, never by
created_atacross hosts; clock skew is a race (IX) wearing a timestamp. - Billing/security: a token or lease expiry should be a duration on a monotonic base, not a wall-clock comparison that an NTP step or a lying client can move.
- Embedded/realtime: a control deadline is elapsed monotonic time; if the RTC resyncs mid-loop, the wall-clock maths corrupts the timing and says nothing about it.
Ask yourself: Am I measuring a duration (use a monotonic clock) or asserting an order across machines (use logical ordering), and would a backward clock jump or a lying peer break this?
Lineage: no global 'now' [Sheehy 2015]; happens-before / logical clocks [Lamport 1978], vector clocks [Fidge & Mattern 1988]; monotonic vs wall clock [POSIX.1j 2000], NTP steps backwards [Mills 2010 (RFC 5905)]; time is an input that lies [Sussman 2012]; fenced sequence [Kleppmann 2016]; TrueTime / bounded uncertainty [Corbett et al. 2012]
XXIV
Make the run reproducible; encode the invariant as a test
A run you can't reproduce you can't debug, audit, or roll back; and where a type can't carry an invariant, an executable test must.
Two failure modes come from one root: correctness that lives in someone's head, or on someone's machine, instead of in the structure. "Works on my machine" and "we can't reproduce the model in production" both come from unpinned dependencies, seeds nobody wrote down, and input data that was never versioned. The defence is structural - lockfiles, pinned toolchains, seeded randomness recorded alongside the output, and immutable, versioned inputs to every build, every pipeline, and every training run. The second mode is the dynamic-language floor for (III) and the verification arm of (XI) and (XV), and an automated test is the canonical structural enforcer here. It re-runs the rule for everyone, forever, including the call sites that don't exist yet. Property- and fuzz-test the parsers (III, IV); test behaviour at the boundaries (XV) and at the decisions (XI), not the internals.
- Data/ML: pin the environment, snapshot and version the dataset, and record the seed alongside the metrics: a result you can't regenerate is an anecdote, not a finding.
- Builds/scripting: a lockfile and a pinned toolchain make the build deterministic across machines and across months; "it built last quarter" is not a build.
- All domains (test as structure): a bug that escaped is a missing test, not just a bad commit, but test the contract, not the internals, or the test turns into a tax that punishes refactoring.
Tension: Tests coupled to the implementation are a tax that punishes the very refactors this manifesto wants to keep cheap (XX). Pin the behaviour at the boundary and at the decision, not the private shape. And reproducibility infrastructure is itself state - lockfiles drift, snapshots cost storage - so own it and expire it like any other state.
Ask yourself: Could someone else regenerate this exact result from pinned inputs, and is this invariant enforced by something that re-runs without me?
Lineage: property-based testing [Claessen & Hughes 2000], fuzzing [Miller et al. 1990]; reproducible & hermetic builds [Reproducible Builds 2013], lockfiles [Reproducible Builds 2013]; reproducible research / seed-recorded [Claerbout & Karrenbach 1992]; tests as spec & test-the-contract [Beck 2002], [Beck 2019]; 'works on my machine' [Cooney 2007]; testing shows presence not absence [Dijkstra 1970 (EWD249)]
XXV
Process is structure when code structure runs out
The 2am pager-holder this manifesto keeps invoking needs structure too: a named owner and a runbook for every service, flag, cache, and risky migration, and a second pair of eyes by process for the irreversible act.
Every preceding tenet pushes correctness into the code, but some correctness just can't live there. When the system breaks at 3am, observability (XVIII) tells the on-call what broke; only a runbook tells them what to do about a known failure mode, and only a named owner tells them who decides when it's something new. The irreversible act (XI) gets a second reviewer enforced by process. Four-eyes is a practice you have to adopt, not just a capability the decision/effect seam happens to enable. Every service, feature flag, cache, and risky migration has one owner of record, so "who owns this?" is never the first question of the incident.
- Backend/distributed: each service and on-call rotation has an owner and a runbook of known failure modes and their first responses; the unowned service is the one nobody dares touch during the outage.
- Infra/data: the irreversible migration (XI, XX) needs a named approver before it runs - process enforcing the four-eyes the seam made possible.
- All domains: every flag (XX), cache (XIV), and quota (VII) has an owner and an expiry, so it doesn't turn into a zombie nobody will delete.
Tension: Process is overhead. Ceremony on the cheap and reversible is just friction, and teams will find ways around it, so keep runbooks and four-eyes for the things that are genuinely irreversible and the things that are genuinely on-call. Bureaucracy for its own sake wears away the trust it was supposed to encode.
Ask yourself: When this breaks and I'm not here, does someone know they own it and know what to do about it, and does the irreversible step force a second human because the process says so, not because somebody happened to be feeling careful?
Lineage: service ownership / you build it you run it [Vogels 2006]; runbook & on-call [Beyer et al. 2016]; four-eyes / separation of privilege [Four-eyes principle], [Saltzer & Schroeder 1975]; flag owner+expiry [Hodgson 2017]; observability cross-ref [Kalman 1960]; pit of success / illegal-states-unrepresentable [Mariani 2003], [Minsky 2010]; ceremony only for the irreversible [Bezos 2016]; humans create safety [Cook 1998]
The through-line
Every tenet here is one move wearing different clothes. Push correctness out of human vigilance and into the structure of the system: types, schemas, ownership, boundaries, atomic steps, deadlines, tests, reproducible runs, and, where the code runs out, process. The illegal state can't be built. The hostile input can't get in, the irreversible act can't fire untested, the clock can't lie without something catching it, and the promise doesn't go unkept. Not because everyone remembered, but because the wrong thing cannot be expressed in the first place.
When two tenets pull against each other (bound-everything vs YAGNI, unrepresentable-states vs dynamic-language reality, locality vs single-source-of-truth, strict-parse vs tolerant-read, fail-fast vs degrade, consistency vs availability under partition, reversibility vs the duty to forget, seams vs simplicity), there's no slogan that settles it. You go back to the objective and say it again: cut down what a tired engineer has to hold in their head, while keeping a bounded blast radius around whatever an attacker or some unlucky caller gets to control. If the blast radius is wide and the input is someone else's, pay for it now. If it's contained and it's yours, you can defer, but write down why you did.
Write for the person who is going to read this at 2am with a pager going off, and who knows less than you know now. Make the right thing the easy thing and make the wrong thing hard to even express, and never make them hold in their head what the code could have held for them.
Lineage: programs written for people to read [Abelson & Sussman 1985]; complexity as cognitive load / what an engineer must hold in their head [Ousterhout 2018], [Miller 1956]; essential vs accidental complexity [Brooks 1986]; correctness in the shape of the system, not vigilance [Weinberg 1971]; the 'X over Y' values form [Beck et al. 2001]; make the right thing easy / pit of success [Mariani 2003], affordances [Norman 1988]; bounded blast radius via least privilege [Saltzer & Schroeder 1975], trust boundary [Swiderski & Snyder 2004]; named tensions: CAP [Brewer / Gilbert & Lynch 2002], fail-fast [Shore 2004], YAGNI [Beck 1999], Postel [Postel 1980 (RFC 761)], DRY [Hunt & Thomas 1999], illegal-states-unrepresentable [Minsky 2010], duty to forget [GDPR 2016 (Art. 17)]
Appendix: Sources & Influences
This manifesto invents almost nothing. Every tenet is a synthesis of established work (research papers, named patterns, hard-won operational practice) recompressed into one structural argument. This appendix credits the originators. Where a tenet leans on a distinctive coinage, that coinage belongs to its author: "Parse, don't validate" is Alexis King's; "make illegal states unrepresentable" is Yaron Minsky's; "local reasoning" is the O'Hearn-Reynolds-Yang separation-logic programme's; "least privilege" is Saltzer & Schroeder's. Where the manifesto borrows standard field vocabulary (blast radius, idempotency, backpressure) we trace it back to its earliest meaningful origin rather than claim it. Bibliography entries are sorted by citation key, and the per-tenet lineage lines appear inline with each tenet.
Bibliography
- [Abelson & Sussman 1985] Harold Abelson, Gerald Jay Sussman & Julie Sussman, "Structure and Interpretation of Computer Programs". MIT Press, 1984/1985. https://mitpress.mit.edu/sites/default/files/sicp/full-text/book/book.html. "programs must be written for people to read, and only incidentally for machines to execute"; grounds the preamble premise and locality; tenets I, II, XXII, PREAMBLE.
- [Allman 2011] Eric Allman, "The Robustness Principle Reconsidered". ACM Queue 9(6) / CACM, 2011. https://queue.acm.org/detail.cfm?id=1999945. The security/ossification critique of naive Postel, grounding 'reject what violates an invariant'; tenet XV.
- [Amdahl 1967] Gene M. Amdahl, "Validity of the Single Processor Approach to Achieving Large Scale Computing Capabilities". AFIPS Spring Joint Computer Conference, Vol. 30, 1967. https://dl.acm.org/doi/10.1145/1465482.1465560. The quantitative law behind 'make the common case fast'; tenet XVII.
- [Apple 2011] Apple Inc., "Introducing Automatic Reference Counting" (WWDC 2011, session 323) / The Swift Programming Language: Automatic Reference Counting. 2011. https://developer.apple.com/videos/play/wwdc2011/323/. Strong/weak references and retain cycles, grounding reference-strength choice; tenet VIII.
- [AWS 2019] Amazon Web Services, "Reducing blast radius with cell-based architectures" (re:Invent 2019, ARC411-R). 2019. https://d1.awsstatic.com/events/reinvent/2019/REPEAT_1_Reducing_blast_radius_with_cell-based_architectures_ARC411-R1.pdf. 'blast radius' and cell isolation as fault-isolation; tenets XIX, PREAMBLE.
- [AWS 2023] Amazon Web Services, "SEC03-BP02 Grant least privilege access" (Well-Architected Framework / IAM best practices). 2023. https://docs.aws.amazon.com/wellarchitected/latest/framework/sec_permissions_least_privileges.html. IAM least privilege and the broad-
*-policy anti-pattern; tenet XVI. - [Bantilan 2018] Niels Bantilan, "pandera" (pandas/dataframe validation library). 2018. https://github.com/unionai-oss/pandera. Schema asserted once at ingestion yielding a validated frame; tenet III.
- [Beck 1999] Kent Beck, "Extreme Programming Explained: Embrace Change". Addison-Wesley, 1999. https://martinfowler.com/bliki/Yagni.html. Coinage of YAGNI on the C3/XP project; tenets VII, XX, XXI, PREAMBLE.
- [Beck 2002] Kent Beck, "Test-Driven Development: By Example". Addison-Wesley, 2002. https://www.oreilly.com/library/view/test-driven-development/0321146530/. Tests as executable spec and the red-green-refactor / bug-as-missing-test discipline; tenet XXIV.
- [Beck 2019] Kent Beck, "Test Desiderata". 2019. https://kentbeck.github.io/TestDesiderata/. 'tests should be coupled to behaviour and decoupled from structure', grounding 'test the contract, not the internals'; tenet XXIV.
- [Beck et al. 2001] Kent Beck et al., "Manifesto for Agile Software Development". 2001. https://agilemanifesto.org/. The software-manifesto genre and its values-over-process stance; tenet PREAMBLE.
- [Bell 1978] C. Gordon Bell, J. Craig Mudge & John E. McNamara, "Computer Engineering: A DEC View of Hardware Systems Design". Digital Press, 1978. https://gunkies.org/wiki/C._Gordon_Bell. 'the cheapest, fastest, most reliable components are those that aren't there', grounding 'don't have the failure mode'; tenet XXI.
- [Benfield 2016] Cory Benfield (docs by Brett Cannon), "Network protocols, sans I/O" (PyCon US 2016) / sans-io.readthedocs.io. 2016. https://sans-io.readthedocs.io/. The sans-IO pattern (protocol logic with zero I/O), precedent for compute-intent-then-do; tenet XI.
- [Bernhardt 2012] Gary Bernhardt, "Functional Core, Imperative Shell" (Destroy All Software) and "Boundaries" (SCNA 2012). 2012. https://www.destroyallsoftware.com/screencasts/catalog/functional-core-imperative-shell. Pure decision core, thin imperative shell; tenet XI.
- [Bernstein 1995] Daniel J. Bernstein, "Using maildir format" (qmail). c.1995. https://cr.yp.to/proto/maildir.html. Popularised the temp-then-rename crash-safety idiom (no partial reads); tenet XII.
- [Beyer et al. 2016] Betsy Beyer, Chris Jones, Jennifer Petoff & Niall Richard Murphy (eds.), "Site Reliability Engineering: How Google Runs Production Systems". O'Reilly, 2016. https://sre.google/sre-book/table-of-contents/. Runbooks, on-call ownership, error budgets, golden signals, and degradation as operational practice; tenets VI, XVIII, XIX, XXV.
- [Bezos 2016] Jeff Bezos, "Amazon 2015 Letter to Shareholders" (one-way vs two-way doors / Type 1 & 2 decisions). 2016. https://www.sec.gov/Archives/edgar/data/1018724/000119312516530910/d168744dex991.htm. Reversible vs irreversible decisions; tenets XX, XXV.
- [Billion Laughs 2002] Billion laughs / XML exponential entity-expansion DoS (CVE-2003-1564). 2002. https://en.wikipedia.org/wiki/Billion_laughs_attack. Small-input/huge-expansion bomb motivating size bounds; tenet IV.
- [Birrell & Nelson 1984] Andrew Birrell & Bruce Jay Nelson, "Implementing Remote Procedure Calls". ACM TOCS 2(1), 1984. https://dl.acm.org/doi/10.1145/2080.357392. RPC delivery-semantics (at-most-once) framing; tenet X.
- [Bloch 2001] Joshua Bloch, "Effective Java" (item 'Avoid finalizers [and cleaners]'). Addison-Wesley, 2001/2018. https://www.oreilly.com/library/view/effective-java-3rd/9780134686097/. GC reclaims memory but not external resources; tenet VII.
- [Bourgon 2017] Peter Bourgon, "Metrics, tracing, and logging". 2017. https://peter.bourgon.org/blog/2017/02/21/metrics-tracing-and-logging.html. The overlapping pillars of observability; tenet XVIII.
- [Brady 2017] Edwin Brady, "Type-Driven Development with Idris". Manning, 2017. https://www.manning.com/books/type-driven-development-with-idris. Types as the primary design artefact, applied at boundaries; tenet III.
- [Brewer / Gilbert & Lynch 2002] Eric Brewer (conjecture, PODC 2000); Seth Gilbert & Nancy Lynch, "Brewer's Conjecture and the Feasibility of Consistent, Available, Partition-Tolerant Web Services". ACM SIGACT News 33(2), 2002. https://groups.csail.mit.edu/tds/papers/Gilbert/Brewer2.pdf. The CAP theorem (consistency vs availability under partition); tenet PREAMBLE.
- [Brooker 2015] Marc Brooker, "Exponential Backoff And Jitter" (AWS Architecture Blog) / "Jitter: Making Things Better With Randomness". 2015. https://aws.amazon.com/blogs/architecture/exponential-backoff-and-jitter/. Jittered backoff so synchronised retries don't herd; tenets VII, XIX.
- [Brooks 1986] Frederick P. Brooks Jr., "No Silver Bullet: Essence and Accident in Software Engineering". Proc. IFIP 1986 (repr. IEEE Computer, Apr 1987). https://worrydream.com/refs/Brooks_1986_-_No_Silver_Bullet.pdf. The essential-vs-accidental complexity distinction; tenets XXI, I, XXII, PREAMBLE.
- [Burgess 1995] Mark Burgess, "Cfengine: A Site Configuration Engine". Computing Systems (USENIX), 1995. https://www.usenix.org/legacy/publications/compsystems/1995/sum_burgess.pdf. Convergence to a desired end state (idempotent configuration); tenet X.
- [Candea & Fox 2003] George Candea & Armando Fox, "Crash-Only Software". HotOS IX, 2003. https://www.usenix.org/conference/hotos-ix/crash-only-software. Abrupt termination as a designed-for, survivable path; tenet XII.
- [Chandra & Toueg 1996] Tushar Deepak Chandra & Sam Toueg, "Unreliable Failure Detectors for Reliable Distributed Systems". JACM 43(2), 1996. https://www.cs.utexas.edu/~lorenzo/corsi/cs380d/papers/p225-chandra.pdf. Completion-is-absence: a crash emits no event, so liveness needs a timer/heartbeat; tenet VIII.
- [Chassaing 2021] Jérémie Chassaing, "Functional Event Sourcing Decider". 2021. https://thinkbeforecoding.com/post/2021/12/17/functional-event-sourcing-decider. The Decider (decide returns intent as data; apply realises it); tenet XI.
- [Claerbout & Karrenbach 1992] Jon Claerbout & Martin Karrenbach, "Electronic documents give reproducible research a new meaning". SEG Technical Program Expanded Abstracts (pp. 601-604), 1992. https://doi.org/10.1190/1.1822162. Coined 'reproducible research', grounding seed-recorded-with-output; tenet XXIV.
- [Claessen & Hughes 2000] Koen Claessen & John Hughes, "QuickCheck: A Lightweight Tool for Random Testing of Haskell Programs". ICFP '00. https://dl.acm.org/doi/10.1145/351240.351266. Property-based testing of the pure decision function; tenets XI, XXIV.
- [Codd 1970] E. F. Codd, "A Relational Model of Data for Large Shared Data Banks". CACM 13(6), 1970. https://dl.acm.org/doi/10.1145/362384.362685. Declarative integrity constraints (NOT NULL/CHECK/FK) as a structural chokepoint; tenets III, XIV.
- [Coffman et al. 1971] E. G. Coffman, M. J. Elphick & A. Shoshani, "System Deadlocks" (with Havender 1968). ACM Computing Surveys 3(2), 1971. https://dl.acm.org/doi/10.1145/356586.356588. The four deadlock conditions; consistent lock order breaks circular wait; tenet IX.
- [Colvin 2017] Samuel Colvin, "pydantic" (type-hint-driven runtime validation). 2017. https://github.com/pydantic/pydantic. Parse-at-the-door into a typed model in dynamic Python; tenet III.
- [Confluent 2017] Confluent, "Exactly-once Semantics is Possible: Here's How Apache Kafka Does It" (KIP-98). 2017. https://www.confluent.io/blog/exactly-once-semantics-are-possible-heres-how-apache-kafka-does-it/. Idempotent producer / dedup-by-id making at-least-once behave like exactly-once; tenet X.
- [Constantine et al. 1974] W. P. Stevens, G. J. Myers & L. L. Constantine, "Structured Design". IBM Systems Journal 13(2), 1974. https://dl.acm.org/doi/10.1147/sj.132.0115. Coupling and cohesion, the structural frame behind tenet I's symptoms; tenet I.
- [Cook 1998] Richard I. Cook, "How Complex Systems Fail". Cognitive Technologies Laboratory, University of Chicago, 1998. https://how.complexsystems.fail/. Systems run degraded; humans-with-runbooks create safety; tenets XXV, XIX, XVIII.
- [Cooney 2007] Joseph Cooney (amplified by Jeff Atwood), "The 'Works on My Machine' Certification Program". 2007. https://blog.codinghorror.com/the-works-on-my-machine-certification-program/. The environment-drift aphorism; tenet XXIV.
- [Corbett et al. 2012] James C. Corbett, Jeffrey Dean et al. (Google), "Spanner: Google's Globally-Distributed Database" (TrueTime). OSDI 2012. https://research.google.com/archive/spanner-osdi2012.pdf. Reifying clock uncertainty as bounded intervals; tenet XXIII.
- [Crosby & Wallach 2003] Scott A. Crosby & Dan S. Wallach, "Denial of Service via Algorithmic Complexity Attacks". 12th USENIX Security Symposium, 2003. https://www.usenix.org/conference/12th-usenix-security-symposium/denial-service-algorithmic-complexity-attacks. Super-linear-in-attacker-input is a DoS, not a perf question; tenet XVII.
- [Dean & Barroso 2013] Jeffrey Dean & Luiz André Barroso, "The Tail at Scale". CACM 56(2), 2013. https://www.barroso.org/publications/TheTailAtScale.pdf. Tail latency and 'a stranger's worst day'; tenet V.
- [Dennis & Van Horn 1966] Jack B. Dennis & Earl C. Van Horn, "Programming Semantics for Multiprogrammed Computations". CACM 9(3), 1966. https://dl.acm.org/doi/10.1145/365230.365252. The capability as an unforgeable token of scoped authority; tenet XVI.
- [Dijkstra 1965 (EWD123)] Edsger W. Dijkstra, "Cooperating Sequential Processes" (EWD123). 1965. https://www.cs.utexas.edu/~EWD/transcriptions/EWD01xx/EWD123.html. The bounded-buffer producer/consumer pattern; tenet V.
- [Dijkstra 1970 (EWD249)] Edsger W. Dijkstra, "Notes On Structured Programming" (EWD249). 1970. https://www.cs.utexas.edu/~EWD/transcriptions/EWD02xx/EWD249.html. 'testing shows presence, not absence, of bugs'; tenet XXIV.
- [Dijkstra 1974] Edsger W. Dijkstra, "Self-stabilizing Systems in Spite of Distributed Control". CACM 17(11), 1974. https://dl.acm.org/doi/10.1145/361179.361202. Self-stabilisation (converge from any state), the root of the convergent reconciler; tenet VIII.
- [Dijkstra 1975 (EWD498)] Edsger W. Dijkstra, "EWD498: How do we tell truths that might hurt?" 1975. https://www.cs.virginia.edu/~evans/cs655/readings/ewd498.html. 'Simplicity is prerequisite for reliability'; tenet XXI.
- [Dijkstra 1976] Edsger W. Dijkstra, "A Discipline of Programming" (and EWD288). 1976. https://www.cs.utexas.edu/~EWD/transcriptions/EWD02xx/EWD288.html. Correct-by-construction program derivation; tenet III.
- [Dinesh 2018] Sandeep Dinesh, "Kubernetes best practices: terminating with grace". Google Cloud, 2018. https://cloud.google.com/blog/products/containers-kubernetes/kubernetes-best-practices-terminating-with-grace. SIGTERM → grace window → SIGKILL drain contract; tenet XII.
- [Dodds 2018] Kent C. Dodds, "Prop Drilling". 2018. https://kentcdodds.com/blog/prop-drilling. Explicit props/threading vs implicit context; tenet II.
- [Dominus 1999] Mark Jason Dominus, "Sins of Perl Revisited" (action-at-a-distance catchphrase). 1999. https://en.wikipedia.org/wiki/Action_at_a_distance_(computer_programming). Action-at-a-distance as a programming anti-pattern; tenets I, II.
- [Einstein 1947] Albert Einstein, letter to Max Born (3 March 1947), 'spukhafte Fernwirkung' / 'spooky action at a distance.' Pub. The Born-Einstein Letters, 1971. https://en.wiktionary.org/wiki/spooky_action_at_a_distance. The 'spooky-action' colouring of remote-effect abstractions; tenets I, II.
- [Envoy 2017] Envoy Proxy, "Architecture Overview: Draining". 2017. https://www.envoyproxy.io/docs/envoy/latest/intro/arch_overview/operations/draining. Graceful connection draining; tenet XII.
- [Eswaran et al. 1976] K. P. Eswaran, Jim N. Gray, Raymond A. Lorie & Irving L. Traiger, "The Notions of Consistency and Predicate Locks in a Database System". CACM 19(11), 1976. https://dl.acm.org/doi/10.1145/360363.360369. Serialisability as the correctness criterion behind 'serialise, one owner'; tenet IX.
- [Evans 2003] Eric Evans, "Domain-Driven Design: Tackling Complexity in the Heart of Software". Addison-Wesley, 2003. https://martinfowler.com/bliki/UbiquitousLanguage.html. Ubiquitous Language (a term means one thing everywhere); bounded contexts; tenets XXII, XV, XIV, III, IX.
- [Ewaschuk 2013] Rob Ewaschuk, "My Philosophy on Alerting" (basis for the SRE 'Monitoring Distributed Systems' chapter). 2013. https://docs.google.com/document/d/199PqyG3UsyXlwieHaqbGiWVa8eMWi8zzAn0YfcApr8Q/edit. Alerts must be actionable; noise/over-monitoring is its own failure; tenet XVIII.
- [Facebook 2014] Facebook (Jing Chen, F8 2014), "Flux: An Application Architecture for React". React blog, 2014. https://legacy.reactjs.org/blog/2014/05/06/flux.html. One-way / unidirectional data flow; tenet II.
- [Feathers 2002] Michael Feathers, "The Humble Dialog Box" (Humble Object lineage; later Meszaros 2007). 2002. https://martinfowler.com/articles/humble-dialog-box.html. Push logic out of the hard-to-test boundary; tenet XI.
- [Feathers 2004] Michael C. Feathers, "Working Effectively with Legacy Code". Prentice Hall, 2004. https://www.informit.com/articles/article.aspx?p=359417&seqNum=2. 'seam': a place to alter behaviour without editing in place; tenets II, XX.
- [Feldman 2016] Richard Feldman, "Making Impossible States Impossible" (elm-conf 2016). https://www.youtube.com/watch?v=IcgmSRJHu_8. Modelling UI state as a sum type so contradictory states are untypeable; tenet III.
- [Fidge & Mattern 1988] Colin J. Fidge & Friedemann Mattern (independent), vector clocks. 1988. https://en.wikipedia.org/wiki/Vector_clock. Vector clocks refining Lamport's logical clocks; tenet XXIII.
- [Fiedler 2004; Witters 2009] Glenn Fiedler, "Fix Your Timestep!" and Koen Witters, "deWiTTERS Game Loop". 2004 / 2009. https://gafferongames.com/post/fix_your_timestep/. Decoupling simulation from render so the frame never goes dark; tenet V.
- [Forristal 1998] Jeff Forristal ('rain.forest.puppy'), "NT Web Technology Vulnerabilities". Phrack 54(8), 1998. https://phrack.org/issues/54/8. First public documentation of SQL injection; tenet XVI.
- [Forsgren et al. 2018] Nicole Forsgren, Jez Humble & Gene Kim, "Accelerate". IT Revolution Press, 2018. https://itrevolution.com/product/accelerate/. Small, reversible, frequent change with fast recovery (DORA); tenets XX, XXIV, XIX, XXV.
- [Four-eyes principle] Dual control / 'Vieraugenprinzip' / two-person rule (accounting, banking, military). https://en.wikipedia.org/wiki/Four_eyes_principle. A second person approves the irreversible act; tenets XI, XXV.
- [Fowler 1999] Martin Fowler (with Kent Beck), "Refactoring: Improving the Design of Existing Code". Addison-Wesley, 1999. https://martinfowler.com/books/refactoring.html. Rule of Three (attrib. Don Roberts); code smells; behaviour-preserving change under a test net; tenets I, XVII, XX, XXIV.
- [Fowler 2002] Martin Fowler, "Patterns of Enterprise Application Architecture" / 'First Law of Distributed Object Design'. Addison-Wesley, 2002. https://martinfowler.com/bliki/FirstLaw.html. The chatty-interface anti-pattern; tenet XVII.
- [Fowler 2004] Martin Fowler, "Inversion of Control Containers and the Dependency Injection pattern". 2004. https://martinfowler.com/articles/injection.html. Coinage of 'Dependency Injection'; IoC vs DI; tenet II.
- [Fowler 2011] Martin Fowler, "Tolerant Reader". 2011. https://martinfowler.com/bliki/TolerantReader.html. Consume liberally, ignore unknown fields; tenet XV.
- [Gabriel 1990] Richard P. Gabriel, "Lisp: Good News, Bad News, How to Win Big": section 'The Rise of Worse Is Better'. 1990. https://dreamsongs.com/WorseIsBetter.html. Simple/incomplete designs winning, behind 'small obvious services'; tenet XXI.
- [GDPR 2016 (Art. 17)] Regulation (EU) 2016/679 (GDPR), Article 17: Right to erasure ('right to be forgotten'). 2016. https://eur-lex.europa.eu/eli/reg/2016/679/oj. The duty to forget / deletion obligation; tenets XX, PREAMBLE.
- [Gerrand 2011] Andrew Gerrand, "Error handling and Go". The Go Blog, 2011. https://go.dev/blog/error-handling-and-go. The (value, err) multiple-return convention forcing call-site error checks; tenet XIII.
- [Goetz 2006] Brian Goetz, Tim Peierls, Joshua Bloch, Joseph Bowbeer, David Holmes & Doug Lea, "Java Concurrency in Practice". Addison-Wesley, 2006. https://jcip.net/. Check-then-act and read-modify-write compound actions; tenets IX, VII, II, VIII.
- [GoF 1994] Erich Gamma, Richard Helm, Ralph Johnson & John Vlissides, "Design Patterns" (Observer). Addison-Wesley, 1994. https://en.wikipedia.org/wiki/Observer_pattern. Register/Attach implies Detach/teardown; tenet VIII.
- [Gong & Campbell 2017] Abe Gong & James Campbell, "Great Expectations" (data-quality framework). 2017. https://github.com/great-expectations/great_expectations. Declarative expectations quarantining bad rows at ingestion; tenet III.
- [Gray & Cheriton 1989] Cary G. Gray & David R. Cheriton, "Leases: An Efficient Fault-Tolerant Mechanism for Distributed File Cache Consistency". SOSP 12, 1989. https://dl.acm.org/doi/10.1145/74850.74870. The time-bounded lease underlying fenced leases; tenet IX.
- [Gray 1978] Jim Gray, "Notes on Data Base Operating Systems". 1978. https://jimgray.azurewebsites.net/papers/dbos.pdf. Introduces the write-ahead log protocol; names the Two Generals Paradox; tenets XII, X.
- [Greenspun 1993] Philip Greenspun, "Greenspun's Tenth Rule" (with the Inner-Platform Effect, Papadimoulis 2006). c.1993. https://en.wikipedia.org/wiki/Greenspun%27s_tenth_rule. Config DSLs that reinvent a language badly; tenet XXI.
- [Gregg 2012] Brendan Gregg, "Thinking Methodically about Performance" / 'The USE Method'. ACM Queue 10(12), 2012. https://www.brendangregg.com/usemethod.html. Utilisation/Saturation/Errors per resource; tenet XVIII.
- [HashiCorp 2014] HashiCorp, "Terraform: plan / apply" (execution plan). 2014. https://developer.hashicorp.com/terraform/cli/commands/plan. The reviewable plan then a separate apply; tenet XI.
- [Hennessy & Patterson 1990] John L. Hennessy & David A. Patterson, "Computer Architecture: A Quantitative Approach". Morgan Kaufmann, 1990. https://dl.acm.org/doi/book/10.5555/1999263. Codified 'make the common case fast'; tenet XVII.
- [Herlihy & Wing 1990] Maurice P. Herlihy & Jeannette M. Wing, "Linearizability: A Correctness Condition for Concurrent Objects". ACM TOPLAS 12(3), 1990. https://cs.brown.edu/people/mph/HerlihyW90/p463-herlihy.pdf. The formal 'one indivisible step' property; tenet IX.
- [Hoare 1980] C. A. R. Hoare, "The Emperor's Old Clothes" (1980 ACM Turing Award Lecture). CACM 24(2), 1981. https://dl.acm.org/doi/10.1145/358549.358561. 'so simple there are obviously no deficiencies'; simplicity → reliability; tenet XXI.
- [Hockin 2017] Tim Hockin, "Edge vs Level Triggered Logic" (talk). 2017. https://speakerdeck.com/thockin/edge-vs-level-triggered-logic. Applying level/edge-triggering to control loops; 'subscribe for latency, reconcile for correctness'; tenet VIII.
- [Hodgson 2017] Pete Hodgson (on martinfowler.com), "Feature Toggles (aka Feature Flags)". 2017. https://martinfowler.com/articles/feature-toggles.html. Feature flags, ramping, owner+sunset / toggle debt; tenets XX, XXV.
- [Howard & LeBlanc 2002] Michael Howard & David LeBlanc, "Writing Secure Code" (2nd ed.), ch. 'All Input Is Evil!'. Microsoft Press, 2002. https://www.oreilly.com/library/view/writing-secure-code/0735617228/ch10.html. 'all input is evil until proven otherwise'; tenet IV.
- [Huffman 1954] David A. Huffman, "The Synthesis of Sequential Switching Circuits". J. Franklin Institute, 1954. https://en.wikipedia.org/wiki/Race_condition. Earliest technical use of 'race condition'; tenet IX.
- [Hunt & Thomas 1999] Andrew Hunt & David Thomas, "The Pragmatic Programmer". Addison-Wesley, 1999. https://pragprog.com/titles/tpp20/the-pragmatic-programmer-20th-anniversary-edition/. The DRY principle (single authoritative representation); orthogonality; reversibility; tenets I, XIV, XX, PREAMBLE.
- [Härder & Reuter 1983] Theo Härder & Andreas Reuter, "Principles of Transaction-Oriented Database Recovery" (the ACID acronym). ACM Computing Surveys 15(4), 1983. https://dl.acm.org/doi/10.1145/289.291. Atomicity and durability as named transaction properties; tenets IX, XII.
- [IBM System/370 1970] IBM, "System/370 Principles of Operation": Compare and Swap (CS/CDS). 1970. https://en.wikipedia.org/wiki/Compare-and-swap. The CAS atomic primitive for optimistic concurrency; tenets IX, XI.
- [Intel 8259 1976] Intel 8259/8259A Programmable Interrupt Controller: edge- vs level-triggered modes. 1976. https://en.wikipedia.org/wiki/Intel_8259. The hardware origin of edge/level-triggered vocabulary; tenet VIII.
- [Irish & Lewis 2015] Paul Irish & Paul Lewis (Google Chrome), "Introducing RAIL: A User-Centric Model For Performance". Smashing Magazine, 2015. https://www.smashingmagazine.com/2015/10/rail-user-centric-model-performance/. The 16 ms frame budget; tenet V.
- [Iverson 1962] Kenneth E. Iverson, "A Programming Language" (array/vectorised paradigm; modern idiom via NumPy). Wiley, 1962. https://dl.acm.org/doi/10.1145/800169.805439. Vectorise instead of a per-row loop; tenet XVII.
- [Kalman 1960] Rudolf E. Kalman, "On the General Theory of Control Systems". Proc. 1st IFAC Congress, Moscow, 1960. https://www.semanticscholar.org/paper/On-the-general-theory-of-control-systems-K%C3%A1lm%C3%A1n/597cf3eb7fbd7c4b231451ec998b8a6ae9996c41. 'observability' as inferring internal state from outputs; tenets XVIII, XXV.
- [Karlton 1996] Phil Karlton (doc. by Tim Bray & Martin Fowler), "two hard things: cache invalidation and naming things". c.1996. https://www.karlton.org/2017/12/naming-things-hard/. Naming is hard and high-stakes; cache drift; tenets XXII, XIV.
- [Kindervag 2010] John Kindervag (Forrester), "No More Chewy Centers: Introducing the Zero Trust Model". 2010. https://www.forrester.com/blogs/a-look-back-at-zero-trust-never-trust-always-verify/. Zero trust (invoked critically against in-process re-validation); tenet IV.
- [King 2019] Alexis King, "Parse, don't validate". 2019. https://lexi-lambda.github.io/blog/2019/11/05/parse-don-t-validate/. Parse once into a narrower typed value (the NonEmpty example); tenets III, XV, XXIV, IV.
- [Klabnik & Nichols 2018] Steve Klabnik & Carol Nichols, "The Rust Programming Language": ch. 4 'What Is Ownership?'. 2018. https://doc.rust-lang.org/book/ch04-01-what-is-ownership.html. Single-owner model, Drop on every exit path; tenet VII.
- [Kleppmann 2012] Martin Kleppmann, "Schema evolution in Avro, Protocol Buffers and Thrift". 2012. https://martin.kleppmann.com/2012/12/05/schema-evolution-in-avro-protocol-buffers-thrift.html. Forward/backward compatibility rules; tenet XV.
- [Kleppmann 2016] Martin Kleppmann, "How to do distributed locking". 2016. https://martin.kleppmann.com/2016/02/08/how-to-do-distributed-locking.html. The fencing token; expect to be wrong about holding the lock; tenets IX, XXIII.
- [Kleppmann 2017] Martin Kleppmann, "Designing Data-Intensive Applications". O'Reilly, 2017. https://dataintensive.net/. Synthesis text for idempotency, races, schema evolution, source-of-truth, and clocks; tenets X, IX, XV, XIV, XXIII, VII.
- [Knuth 1974] Donald E. Knuth, "Structured Programming with go to Statements" (and 'Computer Programming as an Art'). ACM Computing Surveys 6(4) / CACM 17(12), 1974. https://dl.acm.org/doi/10.1145/356635.356640. 'premature optimisation is the root of all evil'; the 97%/3% split; tenet XVII.
- [Kohnfelder & Garg 1999] Loren Kohnfelder & Praerit Garg, "The Threats to Our Products" (STRIDE). Microsoft internal memo, 1999. https://adamshostack.medium.com/20-years-of-stride-looking-back-looking-forward-3be35e28cda3. STRIDE; elevation-of-privilege and DoS threat categories; tenet IV.
- [Kung & Robinson 1981] H. T. Kung & John T. Robinson, "On Optimistic Methods for Concurrency Control". ACM TODS 6(2), 1981. https://dl.acm.org/doi/10.1145/319566.319567. Optimistic concurrency (version + validate-then-retry); tenet IX.
- [Lamport 1978] Leslie Lamport, "Time, Clocks, and the Ordering of Events in a Distributed System". CACM 21(7), 1978. https://lamport.azurewebsites.net/pubs/time-clocks.pdf. Happens-before and logical clocks; no global 'now'; tenets XXIII, IX.
- [Lampson 1971 / Saltzer & Schroeder 1975] Butler W. Lampson, "Protection" (access-control matrix, 1971); Saltzer & Schroeder (1975). https://cseweb.ucsd.edu/classes/fa01/cse221/papers/lampson-protection-osr74.pdf. The authentication-vs-authorisation (who vs what) foundation; tenet IV.
- [Leach 2017] Brandur Leach, "Designing robust and predictable APIs with idempotency" / 'Implementing Stripe-like Idempotency Keys in Postgres'. 2017. https://stripe.com/blog/idempotency. The idempotency key (Stripe), returning the original result on retry; tenet X.
- [Lehman 1974] Manny Lehman, "Laws of Software Evolution" (continuing change & increasing complexity). 1974. https://en.wikipedia.org/wiki/Lehman%27s_laws_of_software_evolution. Code-as-liability / complexity accretion behind 'software gets heavier'; tenet XXI.
- [Leijen & Meijer 1999] Daan Leijen & Erik Meijer, "Domain-Specific Embedded Compilers" (phantom types). DSL'99. https://dl.acm.org/doi/10.1145/331963.331977. Phantom types behind validated/unvalidated markers; tenet III.
- [Letuchy 2008] Eugene Letuchy (Facebook), "Facebook Chat" (coined 'dark launch'). 2008. https://engineering.fb.com/2008/05/13/web/facebook-chat/. Dark/shadow launch against live traffic without user-visible effects; tenet XX.
- [Linsley 2020] Tanner Linsley, "React Query / TanStack Query" ('server state is a cache, not state'). 2020. https://tanstack.com/query/latest. The client cache as a derived view of server truth with explicit invalidation; tenet XIV.
- [Little 1961] John D. C. Little, "A Proof for the Queuing Formula: L = λW". Operations Research 9(3), 1961. https://www.jstor.org/stable/167570. At saturated throughput a deeper buffer only adds latency; tenet V.
- [Mariani 2003] Rico Mariani (doc. Brad Abrams; pop. Jeff Atwood), "The Pit of Success". 2003. https://blog.codinghorror.com/falling-into-the-pit-of-success/. Make the right thing easy, the wrong thing hard; tenets XXV, PREAMBLE, XXI.
- [Martin 1996] Robert C. Martin, "The Dependency Inversion Principle". C++ Report, 1996. https://www.cs.utexas.edu/~downing/papers/DIP-1996.pdf. High-level modules depend on abstractions, the rationale for a declared seam; tenet II.
- [Martin 2008] Robert C. Martin, "Clean Code" (ch. 'Meaningful Names'). Prentice Hall, 2008. https://ptgmedia.pearsoncmg.com/images/9780132350884/samplepages/9780132350884.pdf. Intention-revealing names; 'avoid disinformation' (misleading name worse than none); tenet XXII.
- [Maurer 2015] Ben Maurer, "Fail at Scale". ACM Queue 13(8), 2015. https://queue.acm.org/detail.cfm?id=2839461. Adaptive LIFO / freshest-first shedding of deadline-expired work; tenet V.
- [McPhee 1974; Bishop & Dilger 1996] W. S. McPhee, "Operating System Integrity in OS/VS2" (1974); Matt Bishop & Michael Dilger, "Checking for Race Conditions in File Accesses" (1996). https://nob.cs.ucdavis.edu/bishop/papers/1996-compsys/racecond.pdf. TOCTOU (the check-then-act window); tenets IX, XI.
- [Meszaros 2007] Gerard Meszaros, "xUnit Test Patterns" (Test Double; Virtual Clock). Addison-Wesley, 2007. http://xunitpatterns.com/Test%20Double.html. The swappable test double / virtual clock; tenet II.
- [Metz 2016] Sandi Metz, "The Wrong Abstraction". 2016. https://sandimetz.com/blog/2016/1/20/the-wrong-abstraction. 'duplication is far cheaper than the wrong abstraction'; tenet I.
- [Meyer 1988] Bertrand Meyer, "Object-Oriented Software Construction". Prentice Hall, 1988. https://www.eiffel.org/doc/eiffel/Object-Oriented_Software_Construction%2C_2nd_Edition. Command-Query Separation: a method either changes state or answers a question, not both; tenet XI.
- [Micco 2016] John Micco, "Flaky Tests at Google and How We Mitigate Them". Google Testing Blog, 2016. https://testing.googleblog.com/2016/05/flaky-tests-at-google-and-how-we.html. Uncontrolled ambient inputs cause flakes; tenet II.
- [Microsoft 2010] Microsoft, "Cancellation in Managed Threads" (CancellationToken). .NET Framework 4.0, 2010. https://learn.microsoft.com/en-us/dotnet/standard/threading/cancellation-in-managed-threads. Cooperative cancellation for long correct work; tenet VI.
- [Miller 1956] George A. Miller, "The Magical Number Seven, Plus or Minus Two". Psychological Review 63(2), 1956. https://doi.org/10.1037/h0043158. Working-memory limit behind 'what an engineer must hold in their head'; tenet PREAMBLE.
- [Miller 1968] Robert B. Miller, "Response time in man-computer conversational transactions". AFIPS Fall Joint Computer Conference, 1968. https://dl.acm.org/doi/10.1145/1476589.1476628. The 0.1 s / 1 s / 10 s perceptual thresholds (pop. Nielsen 1993); tenet V.
- [Miller 2006] Mark S. Miller, "Robust Composition: Towards a Unified Approach to Access Control and Concurrency Control" (PhD thesis; POLA). Johns Hopkins, 2006. https://worrydream.com/refs/Miller_2006_-_Robust_Composition.pdf. Principle of Least Authority; pass only the fields a function needs; tenet XVI.
- [Miller et al. 1990] Barton P. Miller, Lars Fredriksen & Bryan So, "An Empirical Study of the Reliability of UNIX Utilities". Communications of the ACM 33(12), 1990. https://dl.acm.org/doi/10.1145/96267.96279. The origin of fuzzing: random input to find crashes; tenet XXIV.
- [Miller, Yee & Shapiro 2003] Mark S. Miller, Ka-Ping Yee & Jonathan Shapiro, "Capability Myths Demolished" (ambient authority). 2003. https://papers.agoric.com/assets/pdf/papers/capability-myths-demolished.pdf. 'ambient authority' behind 'ambient dependency'; tenet II.
- [Mills 2010 (RFC 5905)] David L. Mills et al., "Network Time Protocol Version 4". RFC 5905, 2010. https://www.rfc-editor.org/rfc/rfc5905.html. NTP stepping makes the wall clock jump backward; tenet XXIII.
- [Minsky 2010] Yaron Minsky, "Effective ML" / 'Effective ML Revisited' (Jane Street). 2010/2011. https://blog.janestreet.com/effective-ml-revisited/. 'make illegal states unrepresentable'; tenets III, XXV, PREAMBLE.
- [Moggi 1991; Wadler 1992] Eugenio Moggi, "Notions of Computation and Monads" (1991); Philip Wadler, "Monads for Functional Programming" / 'How to Replace Failure by a List of Successes' (1985/1992). https://homepages.inf.ed.ac.uk/wadler/papers/marktoberdorf/baastad.pdf. Monadic error handling: errors as a sum type the caller must handle (monadic bind); tenet XIII.
- [Molloy & Lever 2000] Stephen P. Molloy & Chuck Lever, "Accept() Scalability in Linux" (thundering herd). USENIX ATC 2000. https://en.wikipedia.org/wiki/Thundering_herd_problem. Synchronised wakeups/retries (thundering herd); tenet XIX.
- [Moseley & Marks 2006] Ben Moseley & Peter Marks, "Out of the Tar Pit". 2006. https://curtclifton.net/papers/MoseleyMarks06a.pdf. Complexity, especially state, as the prime cause of unreliability; remove it before managing it; tenet XXI.
- [Murphy & Barr 2001] Niall Murphy & Michael Barr, "Introduction to Watchdog Timers". Embedded Systems Programming, 2001. https://www.embedded.com/introduction-to-watchdog-timers/. Heartbeat/watchdog: prove you're alive or be considered dead; tenet V.
- [NASA MCO 1999] Mars Climate Orbiter Mishap Investigation Board Phase I Report. 1999. https://en.wikipedia.org/wiki/Mars_Climate_Orbiter. The canonical unit-mismatch failure (units must travel with the value); tenet XXII.
- [Node.js (Don't Block the Event Loop)] Node.js / OpenJS Foundation, "Don't Block the Event Loop (or the Worker Pool)". c.2018. https://nodejs.org/en/learn/asynchronous-work/dont-block-the-event-loop. Keep the watched thread responsive; offload heavy work; tenet V.
- [Norman 1988] Donald A. Norman, "The Design of Everyday Things". 1988. https://www.nngroup.com/books/design-everyday-things-revised/. Affordances: make the correct action obvious and effortless; tenet PREAMBLE.
- [Nygard 2007] Michael T. Nygard, "Release It!: Design and Deploy Production-Ready Software". Pragmatic Bookshelf, 2007. https://pragprog.com/titles/mnee2/release-it-second-edition/. Timeouts, Circuit Breaker, Bulkheads, Fail Fast, Unbounded Result Sets, blast-radius/cascading-failure framing; tenets VI, VII, XIX, V, XIII.
- [O'Hearn, Reynolds & Yang 2001] Peter W. O'Hearn, John C. Reynolds & Hongseok Yang, "Local Reasoning about Programs that Alter Data Structures". CSL 2001, LNCS 2142. https://researchr.org/publication/OHearnRY01. 'local reasoning' / the frame rule behind locality; tenet I.
- [Ousterhout 2018] John Ousterhout, "A Philosophy of Software Design". Yaknyam Press, 2018. https://web.stanford.edu/~ouster/cgi-bin/book.php. Deep modules; complexity as cognitive load (what a maintainer must hold in their head); tenets I, XXI, XV, XVI, XXII, PREAMBLE.
- [OWASP API4 2023] OWASP, "API4:2023 Unrestricted Resource Consumption". 2023. https://owasp.org/API-Security/editions/2023/en/0xa4-unrestricted-resource-consumption/. Bound size before allocating; tenet IV.
- [OWASP Input Validation 2021] OWASP, "Input Validation Cheat Sheet". 2021. https://cheatsheetseries.owasp.org/cheatsheets/Input_Validation_Cheat_Sheet.html. Server-side validation is mandatory; 'client-side validation is UX, not security'; tenet IV.
- [OWASP Logging Cheat Sheet] OWASP, "Logging Cheat Sheet". https://cheatsheetseries.owasp.org/cheatsheets/Logging_Cheat_Sheet.html. Never log secrets/credentials/PII; tenet XVIII.
- [Parnas 1972] David L. Parnas, "On the Criteria To Be Used in Decomposing Systems into Modules". CACM 15(12), 1972. https://dl.acm.org/doi/10.1145/361598.361623. Information hiding; the interface as a deliberate contract; tenets I, XV.
- [Peirce 1870] Benjamin Peirce, "Linear Associative Algebra" (coined 'idempotent'). 1870. https://en.wikipedia.org/wiki/Idempotence. The mathematical origin of 'idempotent'; tenets X, IX, VI, XI, XII, XIX, XXI, XXII, VIII.
- [Pike 1989] Rob Pike, "Notes on Programming in C" (Rules 1-2). 1989. https://www.lysator.liu.se/c/pikestyle.html. Measure before tuning; bottlenecks occur in surprising places; tenet XVII.
- [Pike 2015] Rob Pike, "Errors are values". The Go Blog, 2015. https://go.dev/blog/errors-are-values. Go-style errors-as-values; tenet XIII.
- [POSIX rename() 2024] IEEE / The Open Group, "rename()" (atomicity of the namespace swap). IEEE Std 1003.1. https://pubs.opengroup.org/onlinepubs/9799919799/functions/rename.html. Temp-write-then-atomic-rename; tenet XII.
- [POSIX signal(7) 1988] IEEE Std 1003.1 (POSIX), SIGTERM / signal semantics. 1988. https://man7.org/linux/man-pages/man7/signal.7.html. SIGTERM as the catchable termination signal; trap to clean up; tenet XII.
- [POSIX.1j 2000] IEEE / The Open Group, "clock_gettime": CLOCK_MONOTONIC vs CLOCK_REALTIME. IEEE Std 1003.1j-2000. https://pubs.opengroup.org/onlinepubs/9699919799/functions/clock_getres.html. Measure durations with a monotonic clock; tenet XXIII.
- [Postel 1980 (RFC 761)] Jon Postel (ed.), "DoD Standard Transmission Control Protocol": the Robustness Principle (RFC 761 §2.10; restated RFC 793). 1980/1981. https://www.rfc-editor.org/rfc/rfc761. 'be conservative in what you do, be liberal in what you accept'; tenets XV, IV, PREAMBLE.
- [PostgreSQL 2002] PostgreSQL Global Development Group, "statement_timeout" (added in 7.3). 2002. https://www.postgresql.org/docs/current/runtime-config-client.html. Database-side query timeout; tenet VI.
- [PostgreSQL 9.5 2016] PostgreSQL Global Development Group, "INSERT ... ON CONFLICT" (UPSERT). 2016. https://www.postgresql.org/docs/current/sql-insert.html. Atomic upsert instead of SELECT-then-INSERT; tenet IX.
- [Preston-Werner 2013] Tom Preston-Werner, "Semantic Versioning (SemVer)". 2010-2013. https://semver.org/. MAJOR/MINOR/PATCH; breaking changes bump major; tenet XV.
- [Principles of Chaos 2015] Principles of Chaos Engineering (Netflix Chaos Monkey, 2011; principlesofchaos.org). 2015. https://principlesofchaos.org/. Rehearse failure modes; an untested degraded path is a latent bug; tenet XIX.
- [Python Glossary (EAFP/LBYL)] Python Software Foundation, "Glossary: EAFP / LBYL". https://docs.python.org/3/glossary.html#term-EAFP. 'Python's EAFP' (catch the failure where it occurs); tenet XIII.
- [Quine 1960; Strachey 1967] W. V. O. Quine, "Word and Object" (referential transparency); Christopher Strachey, "Fundamental Concepts in Programming Languages" (1967). https://reed.cs.depaul.edu/jriely/447/assets/articles/strachey-fundamental-concepts-in-programming-languages.pdf. Same-inputs-same-outputs; the property now()/random() break; tenet II.
- [React 2017] React core team, "Error Boundaries" (React 16). 2017. https://legacy.reactjs.org/docs/error-boundaries.html. Widget-level fallback instead of white-screening; tenet XIX.
- [React 2019] React core team, "Synchronizing with Effects" (useEffect cleanup). 2019. https://react.dev/learn/synchronizing-with-effects. Return a teardown so listeners/timers are removed on unmount; tenets VIII, VII.
- [Reactive Streams 2015] Reactive Streams initiative (Lightbend/Netflix/Pivotal/Red Hat). 2015. https://www.reactive-streams.org/. Backpressure: a slow consumer signals a fast producer; tenet V.
- [Reproducible Builds 2013] Debian Reproducible Builds project (Lunar et al.) / Bazel hermeticity. 2013/2015. https://reproducible-builds.org/docs/history/. Bit-for-bit, host-insensitive builds; tenet XXIV.
- [RFC 1035 1987] P. Mockapetris, "Domain Names" (DNS TTL; IP TTL in RFC 791). 1987. https://datatracker.ietf.org/doc/html/rfc1035. TTL as the root of encoded retention; tenet XX.
- [RFC 7231 2014] Roy Fielding & Julian Reschke, "HTTP/1.1: Semantics and Content" §4.2.2 (Idempotent Methods). RFC 7231, 2014. https://www.rfc-editor.org/rfc/rfc7231.html#section-4.2.2. Idempotency as retry-safety after a lost ack; tenets X, VI, XIX, XXII.
- [RFC 9110 2022] R. Fielding et al., "HTTP Semantics": 202 Accepted (§15.3.3), 503 Service Unavailable (§15.6.4). RFC 9110, 2022. https://www.rfc-editor.org/rfc/rfc9110.html. 202 to acknowledge async work; 503 for overload; tenets V, VII.
- [Riel 1996] Arthur J. Riel, "Object-Oriented Design Heuristics" (god class). Addison-Wesley, 1996. https://www.oreilly.com/library/view/object-oriented-design-heuristics/020163385X/. The god-object as the least-privilege counterexample; tenet XVI.
- [Robinson 2006] Ian Robinson (on martinfowler.com), "Consumer-Driven Contracts: A Service Evolution Pattern". 2006. https://martinfowler.com/articles/consumerDrivenContracts.html. A contract pinned by consumer tests that fail when a field is dropped; tenet XV.
- [Rust RFC 243 2014] Rust RFC 243 (idea by Aaron Turon), "Trait-based exception handling" (the
?operator). 2014. https://rust-lang.github.io/rfcs/0243-trait-based-exception-handling.html.?to propagate errors with minimal ceremony; tenet XIII. - [Saint-Exupéry 1939] Antoine de Saint-Exupéry, "Terre des Hommes" (Wind, Sand and Stars). 1939. https://en.wikiquote.org/wiki/Antoine_de_Saint_Exup%C3%A9ry. 'perfection is when there is nothing left to take away'; subtraction as progress; tenet XXI.
- [Saltzer & Schroeder 1975] Jerome H. Saltzer & Michael D. Schroeder, "The Protection of Information in Computer Systems". Proc. IEEE 63(9), 1975. https://web.mit.edu/Saltzer/www/publications/protection/. Least privilege, fail-safe defaults, complete mediation, separation of privilege; tenets XVI, IV, XXI, XI, XXV, PREAMBLE.
- [Sassaman et al. 2011] Len Sassaman, Meredith L. Patterson, Sergey Bratus & Anna Shubina, "The Halting Problems of Network Stack Insecurity" (LangSec). USENIX ;login: 36(6), 2011. https://langsec.org/papers/Sassaman.pdf. The boundary parser as the most security-critical code; tenet XV.
- [Sato 2014] Danilo Sato (on martinfowler.com), "Parallel Change (Expand and Contract)" and "Canary Release". 2014. https://martinfowler.com/bliki/ParallelChange.html. Expand→migrate→contract; canary release; tenet XX.
- [Schlimmer & Granger 1986] Jeffrey C. Schlimmer & Richard H. Granger Jr., "Incremental Learning from Noisy Data" (concept drift). Machine Learning 1(3), 1986. https://link.springer.com/article/10.1007/BF00116895. Models silently degrade as the world moves; tenet XVIII.
- [Shapiro et al. 2011] Marc Shapiro, Nuno Preguiça, Carlos Baquero & Marek Zawirski, "Conflict-free Replicated Data Types". SSS 2011. https://en.wikipedia.org/wiki/Idempotence. Commutativity so a race is harmless; tenet IX.
- [Sheehy 2015] Justin Sheehy, "There Is No Now: Problems with Simultaneity in Distributed Systems". ACM Queue 13(3), 2015. https://queue.acm.org/detail.cfm?id=2745385. No usable global 'now'; tenet XXIII.
- [Shore 2004] James Shore (ed. Martin Fowler), "Fail Fast". IEEE Software Design column, 2004. https://www.martinfowler.com/ieeeSoftware/failFast.pdf. Fail immediately and visibly; tenets XIII, XIX, PREAMBLE.
- [Sigelman et al. 2010] Benjamin H. Sigelman et al. (Google), "Dapper, a Large-Scale Distributed Systems Tracing Infrastructure". 2010. https://research.google/pubs/dapper-a-large-scale-distributed-systems-tracing-infrastructure/. Trace id propagated across hops; sampling as design; tenet XVIII.
- [Simonyi 1999; Spolsky 2005] Charles Simonyi (Hungarian notation) & Joel Spolsky, "Making Wrong Code Look Wrong". 2005. https://www.joelonsoftware.com/2005/05/11/making-wrong-code-look-wrong/. Encoding a semantic fact (the unit) in the name; Apps vs Systems Hungarian; tenet XXII.
- [SLSA / Sigstore 2021] SLSA framework (Google/OpenSSF) + Sigstore/Cosign. 2021. https://slsa.dev/. Pin and verify dependencies; lockfiles with checksums; signature verification; tenet IV.
- [Spector 1982] Alfred Z. Spector, "Performing Remote Operations Efficiently on a Local Computer Network". CACM 25(4), 1982. https://dl.acm.org/doi/10.1145/358468.358478. The remote-operation delivery-semantics taxonomy (at-least-once); tenet XII.
- [Spolsky 2000] Joel Spolsky, "Things You Should Never Do, Part I". Joel on Software, 2000. https://www.joelonsoftware.com/2000/04/06/things-you-should-never-do-part-i/. The big-bang rewrite as the irreversible bet to avoid; tenet XX.
- [SQL:2003 MERGE] ISO/IEC 9075 SQL:2003: MERGE (upsert). 2003. https://en.wikipedia.org/wiki/Merge_(SQL). Update-or-insert so a create is idempotent; tenet X.
- [Sridharan 2018] Cindy Sridharan, "Distributed Systems Observability". O'Reilly, 2018. https://www.oreilly.com/library/view/distributed-systems-observability/9781492033431/. Book-length 'three pillars' treatment of observability; tenet XVIII.
- [Stroustrup 1994] Bjarne Stroustrup (with Andrew Koenig), "The Design and Evolution of C++" (RAII). 1994. https://www.stroustrup.com/bs_faq2.html. RAII: release on every exit path via the object's destructor; tenets VII, VIII.
- [Sussman 2012] Noah Sussman, "Falsehoods Programmers Believe About Time". 2012. https://infiniteundo.com/post/25326999628/falsehoods-programmers-believe-about-time. Clocks routinely violate assumptions ('time is an input that lies'); tenet XXIII.
- [Swiderski & Snyder 2004] Frank Swiderski & Window Snyder (later Adam Shostack 2014), "Threat Modeling". Microsoft Press, 2004. https://www.google.com/books/edition/Threat_Modeling/Kp_K16uxJacC. The trust boundary on data-flow diagrams; tenets IV, PREAMBLE.
- [Syme 2007; C# 5.0 2012] Don Syme (F# async workflows, originator) and C# 5.0 / ES2017 (popularisers), async/await. 2007/2012. https://www.microsoft.com/en-us/research/wp-content/uploads/2016/02/async-padl-revised-v2.pdf. Async/await plus a pending state; tenet V.
- [TanStack & Apollo 2016] Apollo Client / TanStack Query, "Optimistic mutation results / Optimistic Updates". 2016. https://www.apollographql.com/docs/react/performance/optimistic-ui. Apply optimistically, then the server confirms or you roll back; tenet XIV.
- [Treat 2015] Tyler Treat, "You Cannot Have Exactly-Once Delivery". 2015. https://bravenewgeek.com/you-cannot-have-exactly-once-delivery/. At-least-once + idempotency = exactly-once processing; tenet X.
- [Tschacher 2016] Nikolai P. Tschacher, "Typosquatting in Programming Language Package Managers" (bachelor thesis). 2016. https://incolumitas.com/2016/06/08/typosquatting-package-managers/. A poisoned/typosquat dependency is a boundary crossing; tenet IV.
- [Ulrich 2016] Mike Ulrich, "Addressing Cascading Failures" (Google SRE Book, ch. 22). 2016. https://sre.google/sre-book/addressing-cascading-failures/. Cascading failure, deadline propagation/budget, retry amplification; tenets VI, XIX, V.
- [Verraes 2015] Mathias Verraes, "two hard problems in distributed systems: exactly-once delivery" (riff on Karlton). 2015. https://x.com/mathiasverraes/status/632260618599403520. The cultural backdrop for 'the only safe operation is one harmless to repeat'; tenet X.
- [Vogels 2006] Werner Vogels (interview by Jim Gray), "A Conversation with Werner Vogels" ('You build it, you run it'). ACM Queue 4(4), 2006. https://aws.amazon.com/blogs/aws/acm_queue_inter/. Service ownership / one owner of record; tenet XXV.
- [WAF / CSP Stamm et al. 2010] Sid Stamm, Brandon Sterne & Gervase Markham, "Reining in the Web with Content Security Policy". WWW 2010 (CSP). https://dl.acm.org/doi/10.1145/1772690.1772784. Content-Security-Policy allowlisting origins; tenet XVI.
- [Weinberg 1971] Gerald M. Weinberg, "The Psychology of Computer Programming". 1971. https://geraldmweinberg.com/Site/Programming_Psychology.html. Correctness in the shape of the system, not the vigilance of people; tenet PREAMBLE.
- [WHATWG / Hickson 2009] WHATWG (ed. Ian Hickson), "Web Workers" / iframe
sandbox. 2009/2010. https://html.spec.whatwg.org/multipage/workers.html. Web Workers (off-main-thread heavy work, tenet V) and the default-denysandboxattribute (tenet XVI); tenets V, XVI. - [Wilde 2019] Erik Wilde, "The Sunset HTTP Header Field". RFC 8594, 2019. https://www.rfc-editor.org/rfc/rfc8594. Deprecation/sunset window; tenet XV.
- [Wilkie 2015] Tom Wilkie, "The RED Method". 2015. https://grafana.com/files/grafanacon_eu_2018/Tom_Wilkie_GrafanaCon_EU_2018.pdf. Rate/Errors/Duration per service; tenet XVIII.
- [Wlaschin 2013] Scott Wlaschin, "Designing with types: Making illegal states unrepresentable". 2013. https://fsharpforfunandprofit.com/posts/designing-with-types-making-illegal-states-unrepresentable/. Popularising illegal-states-unrepresentable for domain modelling; tenet III.
- [Wooldridge 2013] Brett Wooldridge, "HikariCP" (connection-acquisition timeout / pool sizing). 2013. https://github.com/brettwooldridge/HikariCP. Bounded pool with wait-or-reject; a runaway query mustn't hold a slot forever; tenets VI, VII.
- [Wright 2012] Hyrum Wright (named by Titus Winters), "Hyrum's Law / Law of Implicit Dependencies" (Software Engineering at Google, 2020). c.2012. https://www.hyrumslaw.com/. Every observable behaviour becomes a depended-on contract; tenet XV.
- [Zip bomb 1996] Zip bomb / decompression bomb (42.zip). c.1996. https://en.wikipedia.org/wiki/Zip_bomb. A well-formed archive catastrophic on expansion; bound size before allocating; tenet IV.