The Shape of the System

How to implement

Code gets read far more than it gets written, and it gets changed more often than it gets read, and then it runs out in a world that fails partially, at the worst possible moment, while you're asleep. Implementing is the phase where MANIFESTO.md stops being advice and turns into the actual diff, so you want correctness built into the shape of what you write rather than into whoever happens to be paying attention next time round. The objective here is the manifesto's, taken straight: minimise what a tired engineer must hold in their head to make a correct change, subject to keeping the blast radius bounded for anything an attacker or an unlucky caller controls. Most of the moves below buy you the first part. The ones that add code to contain failure are paying for the second. When the two pull against each other, sort it out by working out who controls the input and how wide the blast radius goes. None of it is free. And this is also where most of the code-level tenets finally turn into a diff, which is why this phase runs longer than the gate phases on either side of it.

I

Re-check the plan against the world before you build

The plan was computed against a snapshot the world may no longer match; confirm its assumptions still hold at the first line, not the last.

A plan handed off to implementation is a compare-and-swap sitting there waiting to fail. The schema it assumed, the API it was aimed at, the invariant it leaned on - any of those might have moved since it was written (tenet XI's TOCTOU). Re-read the assumptions the plan wrote down and check them against the code as it actually is now, before you commit to the shape. Applying a stale plan with your eyes shut is the exact race the plan got split up to avoid. Trust what the code says now and not what the plan recorded back then. "It was true last sprint" isn't the same thing as "it is true".

  • A schema assumption: read the migration state before writing the query the plan assumed, not coding against the shape from the design doc, now two migrations stale.
  • A dependency contract: check the version actually deployed, not trusting the interface the plan named, since renamed.
  • A flag's state: confirm what the flag currently gates, not assuming the rollout the plan described already finished.

Tension: This pulls against momentum. Re-deriving the whole plan at implementation time is waste, and it's a refusal to start. Re-check only the load-bearing assumptions, the ones whose being wrong would change the approach, and carry on with the rest.

Ask yourself: Which assumption would quietly corrupt this work if it had changed since the plan was written, and have I actually looked, or am I just trusting the snapshot?

II

Parse at the door; make the illegal state unrepresentable

Turn unstructured input into a typed, constrained value once at the boundary, so the bad shape can't be built or passed inward, and a well-formed value can still be hostile.

Validation keeps re-asking "is this okay?" at thirty-nine call sites and then the fortieth one forgets. Parsing answers "what is this, exactly?" once and hands back a narrower thing whose validity is carried in how it's represented (III). Cross the boundary by changing the type (UnvalidatedInput to ValidatedInput) so the raw form physically can't reach the database call. Then guard whatever the type can't encode (IV): cap the size before you allocate anything, re-derive identity from the verified token instead of whatever the payload claims, and bound the array lengths an attacker got to pick. Model the UI as a discriminated union so "spinner and stale data" is untypeable, rather than three booleans that between them encode five nonsense states.

  • Backend: parse the request body into a typed value at the handler, bounded in size first, not passing the raw map inward and re-checking fields everywhere.
  • Frontend: loading | error | loaded(data) as one state vs three booleans that can encode "loaded and erroring".
  • Storage: a NOT NULL, a CHECK, a unique index. The schema refuses the bad row for every writer, including the migration and the psql prompt.

Tension: This cuts against locality and re-validation (I, IV). Re-parsing at every internal hop is clutter, and it's a latency tax that reduces no threat. Parse once at each real boundary, the process edge, the deserialisation point, the privilege change, and carry the parsed type inward, so internal callers trust the type and not the wire.

Ask yourself: Past this line, is it structurally impossible to be holding the raw, unchecked form, or am I just adding one more check that someone downstream can skip?

III

Keep the reasoning local; give every ambient dependency one seam

A reader should verify this code from itself and its declared inputs; every clock, RNG, and client it touches reaches it through exactly one override point.

When understanding one function needs you to know the call order of three others, plus a flag set in some constructor, plus a global that gets mutated somewhere else, you haven't written a function. You've written a puzzle spread out across the repo (I). Derive behaviour from the props and the arguments, not from action-at-a-distance. And the ambient dependencies (now(), random(), the HTTP client, the environment) each need one declared seam a test can reach (II), or else the same inputs give you different outputs and reproducing anything needs a séance. A controlled clock is fine. An uncontrolled Date.now() four frames down with no override is the flake you'll be chasing for days.

  • Backend: a handler reading request-scoped, explicitly-passed config vs one reaching into a process-global mutated by middleware.
  • Frontend: a component deriving everything from props and local state vs one whose behaviour depends on a useEffect three files away mutating shared context.
  • Testing seam: a function reachable via an injected clock and httpClient is reproducible, vs a hardcoded Date.now() and a module-level client buried deep.

Tension: This trades against single source of truth (XIV) and DRY. Inlining everything just to stay self-contained will eventually duplicate the authoritative definition of some fact, and then the copies drift. Keep the control flow and invariants local, but let named, owned shared facts live elsewhere behind an explicit dependency. Copy the stuff that's only coincidentally similar; unify only what genuinely has to change together.

Ask yourself: To talk myself into believing this is correct, how far from this screen do I have to look, and could a test pin this behaviour down through a single declared override?

IV

Name to reveal, not to label

A name is the cheapest documentation and the most-read token you write; encode the one fact a reader gets wrong without it, because a misleading name is worse than none.

The reader meets the name before they ever get to the body, and a precise one lets them skip the body altogether: retryWithBackoff tells you more than handle, and pendingChargesByAccount more than data (XXII). A misleading name is worse than no name, because it installs a false model that the next reader then debugs against for an hour. So encode the load-bearing fact the type can't already carry - the unit, the ordering, whether there's a side effect - and stop there.

  • Backend: chargeOnceIdempotent(key) warns of the semantics vs doCharge(), which hides them until the duplicate-billing incident.
  • Data: revenue_usd_cents is unambiguous everywhere vs amount, which invites the unit-mismatch bug that ships a 100x error.
  • Frontend: useDebouncedSearch says when it fires vs useSearch, which makes the reader open the file every time.

Tension: A name is a second copy of the invariant it encodes (XIV), and a copy can drift: rename chargeOnceIdempotent everywhere the day idempotency gets dropped, or else the name now lies, which is the precise failure it was warning about in the first place. Let the type (III) carry the invariant wherever it can, and keep the name for facts no type captures: units, ordering, whether there's a side effect. And don't go encoding everything; getUserByIdWithRetryAndCacheFromPrimaryReplica reveals nothing by trying to reveal the lot. Precision, not length.

Ask yourself: Could a reader predict what this does, its units, and its caveats from the name on its own, and is this name carrying a fact no type already carries?

V

Keep the responsive path clear, and deadline every wait you don't control

A path that owes a deadline must never wait inline on work whose completion depends on a party you don't control, and every cross-boundary wait has a cutoff.

A request handler, a UI thread, a frame budget - each one owes a heartbeat to some user's eye or a watchdog, and the moment it synchronously calls a slow network, or a lock held by who-knows-what, its responsiveness is now hostage to a stranger's worst day (V). Get that work off the responsive path and make it observable. async/await and a pending state, or a job queue and a 202, or an off-thread load the frame reads if it's ready. And a cross-boundary call with no timeout is a bet you're going to lose (VI), because a hung dependency with no deadline doesn't fail. It spreads. It eats your threads, then your caller's threads, and one slow database melts the whole fleet.

  • Frontend: hand a heavy parse to a worker and render pending, not a synchronous fetch that freezes scroll and input.
  • Backend: enqueue the third-party call, return 202, surface "queue full" as 503, rather than tying tail latency to their bad day until the pool starves.
  • The long-job exception: a six-hour batch gets progress, heartbeat, and cancellation, not a wall-clock deadline that murders correct work at hour five.

Tension: The deadline has to actually cancel, and then there's the data-dependent case. A timeout that doesn't cancel and propagate just orphans the slow work, and it might fire off a duplicate, so it's only safe when the op is cancellable or idempotent (X). And in-process work whose cost scales with input you don't bound - say a client-side sort over user data - is an uncontrolled-latency path even though it's "yours". Measure it at realistic scale.

Ask yourself: On this responsive path, am I waiting on anything whose worst-case latency I don't control, and if it never comes back, does my system look dead or just degraded?

VI

Measure on a monotonic clock; order with logic, not the wall clock

Wall-clock time is a hostile input: it steps backwards, skews across machines, and cannot establish which event came first; measure durations monotonically and order with logic.

The deadlines you just set, and any ordering you lean on, will break if you trust the wall clock (XXIII). Measure each duration, deadline, and timeout from a monotonic source, because the wall clock jumps backwards on an NTP correction or a leap second, and a deadline measured against it can fire instantly or never fire at all. Don't decide which of two events happened first by comparing timestamps across machines - their clocks disagree. Use a logical clock or a fenced sequence (IX). And a TTL or token expiry checked against the wall clock can be shifted by a clock jump, or by a client that's lying to you.

  • Durations: elapsed time read from a monotonic clock vs end - start on the wall clock, which goes negative the moment NTP steps it back.
  • Ordering: a logical clock or a fenced sequence across hosts, not a created_at comparison that clock skew silently reorders.
  • Expiry: a lease measured on a monotonic base, not a wall-clock deadline an NTP step or a lying peer can shift.

Tension: The wall clock isn't useless. It's the only thing that answers "what time is it for a human?" Use it to show a timestamp and to fire at a calendar moment. Just don't ever measure an interval with it or settle an order with it, because those are the two things it can't be trusted to do.

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?

VII

Bound what callers can create; own and release what you acquire

Every resource a caller can ask for in a loop gets a ceiling, and everything you acquire has exactly one owner that releases it on every exit path, including error and panic.

Connections, threads, queue depth, retries, recursion, payload size - anything a caller can ask for over and over is an OOM or a DoS waiting to be set off, whether by an attacker or by your own retry storm (VII). Give caller-driven and time-unbounded growth a ceiling. The twelve months of the year don't need one. And everything you acquire - a task, a timer, a subprocess, a subscription, a file handle, a lock - is an orphan-in-waiting until something releases it on every path out (VIII). The runtime reclaims memory and nothing else, never external resources, so use the scoping construct where there is one (with, defer, RAII) and release by hand only where there isn't.

  • Backend: a fixed pool with wait-or-reject degrades into 503s, unlike unbounded thread creation per request turning a spike into a death spiral.
  • Frontend: a listener registered on mount and torn down on unmount, not the missing cleanup that leaks the screen the user already left.
  • Data: cap batch size and parallelism, rather than one skewed key OOMing the cluster.

Tension: This pulls against YAGNI (XXI). Not every list needs a configurable max today, and premature limits turn into wrong limits that page you at 3am. Sort it out by who controls the growth: caller-, input-, or time-driven growth always gets a ceiling, and a fixed set doesn't. The owner rule, though, isn't negotiable the way the ceiling is.

Ask yourself: What's the maximum this can grow to, who controls that, and on every exit path, including the panic, what releases what I acquired?

VIII

Measure before you optimise, but fix caller-controlled complexity on sight

Performance is a property you measure, not a vibe, so profile before you trade clarity for speed; the exception is super-linear cost in caller- or attacker-controlled size, which is a correctness bug you fix without a profiler.

Most performance work is "measure first, then make the common case fast", and the cold 95% should stay legible, because that's where the next bug is hiding (XVII). But there are two things you fix on recognition while you're writing them, no profiler needed. First, complexity that's super-linear in input a caller or attacker controls isn't a performance question at all, it's the DoS of (IV) and (VII), and "dev data was fine" is exactly how it ships. Second, the reliable antipatterns - the N+1 query, the per-row loop over a vectorisable op, the per-frame allocation in the hot loop.

  • Databases: batch the N+1 into one query with a join or IN, not the innocent-looking loop that is 500 round-trips per request.
  • Data/ML: vectorise or push the filter into the engine vs a per-row Python loop, hours vs seconds, dollars vs cents.
  • Caller-controlled size: bound or rewrite the super-linear path on input an attacker sizes, not waiting for a profiler that only ever sees friendly dev data.

Tension: This pulls against simplicity and the reader (I, XXI). Every optimisation spends clarity, so buy it only where a profiler proved you had to, and leave the cold path readable. The carve-out is deliberately narrow: only caller-controlled complexity and the handful of known antipatterns are fix-on-sight, and everything else waits for a measurement.

Ask yourself: Is this cost in caller-controlled size (bound it now, no profiler) or a known antipattern (fix it), or am I about to rewrite cold, readable code into clever code I never measured?

IX

Make the mutation race-safe and replay-safe

If two actors can interleave between your check and your act, the check is a guess; and in a world of retries, the only safe operation is one that's harmless to repeat.

if not exists: create, if balance ≥ amount: debit - each of these is two operations pretending to be one, and where concurrent requests or overlapping runs can interleave, the window is invisible in review and devastating in production (IX). Fix it visibly. There's atomicity (INSERT ... ON CONFLICT, compare-and-swap on a version), or serialisation (one owner, a consistent lock order), or commutativity (make the act idempotent so the race does no harm). And separately from all that, the lost ack and the redelivered message both mean the same attempt shows up twice, so key your writes by a stable id and make creates upserts (X). That way retries, crash recovery, and at-least-once messaging are safe instead of corrupting.

  • Databases: UPDATE ... WHERE balance >= amount checking rows-affected vs read-modify-write across two statements.
  • Frontend: disable on submit and dedupe by request id, not two rapid clicks double-charging.
  • Messaging: consumers dedupe by message id, so at-least-once behaves like exactly-once where it counts.

Tension: Idempotency keys and dedupe tables are real machinery with storage and expiry, so don't build them for a read that genuinely is safe to repeat. And "it's single-threaded" is the assumption that turns out wrong more often than any other once you're at scale. Pay for the machinery only where a repeat or an interleave actually touches money, or state, or the outside world.

Ask yourself: Can two actors actually run this between my read and my act, and if this runs twice because something retried, does it come out the same as running it once?

X

Make failure visible; never let it be swallowed

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 tunnels up as an invisible exception through ten frames, the reader of any one frame can't see what might blow up beneath them, and the happy path is just a lie (XIII). Make failure visible and impossible to ignore in whatever your language makes idiomatic - a Result or (value, err) that the tooling nags you to handle, a typed exception caught at one deliberate boundary, an error code in embedded - but never a bare except: or an empty catch. A swallowed error is just a wrong state that's learned how to hide. Then you pick your stance by blast radius. A glue script halts loudly on the first bad step, because if it carries on it corrupts everything downstream. A long-running service degrades (XIX) instead, because halting it is an outage.

  • Backend: (value, err) forces the caller to confront failure at the site where the context to handle it lives.
  • Frontend: a fetch returning { ok } | { error } renders the error state by design, not an unhandled rejection vanishing into the console.
  • Scripting: set -euo pipefail so a failed step halts the chain, not the default that charges on, corrupting the next step.

Tension: Fail-fast pulls against degrade (XIX). Thread errors through everywhere and you drown the happy path, so let them propagate with as little ceremony as you can (?, one catch boundary) to where the decision context lives. 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 quietly disappears?

XI

Emit the signal while you write the code, or there is nothing to observe

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.

A partial failure hardly ever leaves a stack trace. What it leaves is a latency cliff, a rising error rate, a queue creeping up, a retry budget draining away, a fallback that nobody noticed for a week (XVIII). The signals that catch those things aren't added in production. They're written here, while you write the code. So as each piece goes in, emit what will later prove it worked, or show how it didn't: a trace id through every hop, counters on the rejection and retry paths, the breaker state, source-vs-cache drift, the deadline budget remaining, a bounded counter for missed frames. Instrument the failure path you just wrote, not only the happy one, because what you don't emit now can't be observed later, and you can't debug what you can't see.

  • Backend: a trace id propagated through every hop and a counter on the rejection path vs a log line on success only, which goes quiet exactly when things break.
  • Frontend/embedded: real-user monitoring and a bounded counter for missed deadlines, not a crash on a device you will never ssh into and never hear about.
  • Data/ML: emit records-in against records-out, and freshness, because the model never throws, it just quietly gets worse as the world moves.

Tension: Telemetry is itself an unbounded resource (VII) with a cost and a leak risk, so sample it, bound what you keep, and never log the secret. "Log everything" is its own kind of failure - the one signal you actually need gets drowned in the noise of the ones you didn't. Emit what proves an invariant, not whatever happened to be in scope.

Ask yourself: When an invariant here breaks at 3am, what signal will say so, and am I emitting it now while I write the code, or only wishing later that I had?

XII

Hold one source of truth; grant the least privilege

Every fact has one authoritative owner and the rest is derived; every component gets the narrowest authority that does its job, so a bug or breach is contained by what it was never granted.

The same fact in two places is really two facts, and they'll disagree the moment one update misses the other: the cache that drifts away from its rows, two services each holding a writable copy of "the user's plan" (XIV). Pick the owner, derive the rest, and mark every deliberate copy with an invalidation path and a staleness budget. And hand out only the authority a component actually needs (XVI), which is the runtime sibling of making over-reach unrepresentable. A function that takes the two fields it touches, rather than the god-object, tells the reader exactly what it can affect.

  • State: server state is the source; the client cache is a derived view with explicit invalidation vs a parallel kingdom of truth synced by hand.
  • Privilege: the reporting job connects read-only, so an injection in it can't drop a table it has no grant to drop.
  • Tokens: a scope narrow and short-lived vs a broad, long-lived credential that one leak turns into the keys to everything.

Tension: Declared divergence is fine, it's the undeclared kind that's the bug (XIV). Caches, replicas, and optimistic UI are valuable, deliberate duplications, and each one needs a named owner, an invalidation path, and a reconciliation point. An undeclared copy is a bug. A declared, invalidated, reconciled one is engineering.

Ask yourself: If these two copies disagreed at 3am, which is right and where does it reconcile, and what could this component touch if it were fully compromised?

XIII

Remove the state before you guard it

The most reliable handling of a failure mode is to not have it; reach for fewer states before more guards, and delete more than you add.

Software is the only material where more of it makes the rest heavier (XXI). Some complexity belongs to the problem and you've got to carry it. The rest is yours, imposed by you: the abstraction for a future that never came, the "temporary" flag that turned into a permanent branch. Before you write the guard, ask whether the state can just not exist at all. A stateless handler can't go stale, an idempotent op can't be corrupted by a retry, a deleted config option can't be misconfigured. The dead branch you leave behind is the one that springs back to life in an incident.

  • Backend: three small obvious services vs one "flexible" engine driven by a config DSL that reinvents a programming language badly.
  • Frontend: local component state until shared state actually demands a store; delete the unused component and its CSS, because "we might reuse it" is what version control is for.
  • Lifecycle: rip out the flag the day the rollout completes, not a permanent branch nobody remembers the purpose of.

Tension: Simplicity collides with the seams of reversibility (XX) and with single source of truth (XIV), because the simplest local choice can end up duplicating. The tiebreaker is the objective: minimise what the next human has to hold in their head. And YAGNI applies to features, not to limits (VII) or failure handling. A missing guardrail isn't simplicity, it's a liability.

Ask yourself: Can I delete this state, flag, or branch entirely, instead of writing the code that keeps it correct?

XIV

Write the test as you build it

A test is the structural enforcer that re-runs the rule for everyone forever; write it alongside the code, pinning the contract and the decision, not the internals.

Every move above has a test sitting inside it, and the cheapest time to write that test is right now, while the code and the reasons behind it are still in your head and haven't slipped off into some later phase that then has to dig them back out (XXIV). Pin the promise the code makes at its boundary (XV) and the irreversible decision you split out (XI), which you built pure for exactly this reason, so it swallows ten thousand cases and has zero side effects. Get at the behaviour through the seam you just put in (II), throw the worst value you can think of at the parser you wrote (III, IV), and cover the failure path too, not just the happy one (XIII). A bug that got out is a missing test. But pin the contract and not the private shape, or the test turns into a tax that punishes whoever refactors next.

  • The decision: property-test whichRowsToPurge(state) to death vs driving the live DELETE to find out what it would have done.
  • The seam: assert the behaviour through the injected clock and httpClient, not a sleep and a real network call that flakes on a bad day.
  • The boundary: fuzz the parser with the oversized and malformed input, not only the example from the docs that was always going to pass.

Tension: This is test-authoring, not verification. Writing the test belongs here, in the build, while the reasoning is fresh; proving the change actually resolves the issue end-to-end is a separate phase (see the verify guide). And pin behaviour, not internals (XXIV): coverage of private lines is the tax that punishes the very refactors this house style wants cheap.

Ask yourself: Did I write the test that pins this behaviour while I built it, and does it assert the contract and the decision rather than the shape the next refactor will rightly change?

XV

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 bit of work you owe, and it's the bit people skip most (XII). A process that exits with buffered writes still unflushed, or messages it consumed but never acked, or requests dropped halfway through a handshake, doesn't fail in any loud way. It quietly loses whatever someone downstream was counting on, and the way you find out is a data discrepancy that nobody can explain later. The OS reclaims the memory, but it never reclaims the meaning. The floor here, and this holds even for a one-shot script: leave a complete output or leave none, write to a temp path and atomically rename once it's worked, trap the signal so you can clean up the partials. And because you might get killed abruptly anyway, the durability contract has to live somewhere else as well - a WAL, at-least-once redelivery, idempotent writes (X) - so that the abrupt exit is something the design already survives.

  • Backend: on SIGTERM, stop the listener, drain in-flight within a grace window, close the pool, then exit. A rolling deploy drops zero requests.
  • Scripting: temp-write-then-rename and a signal trap; commit the stream offset only after the record is durably written, because ack-before-persist eats data on restart.
  • Mobile: flush unsaved state and queued analytics on background. The OS may kill you without a second warning.

Tension: This is paid for against the hang (VI). An unbounded graceful drain that waits forever for a stuck request is no better than dropping it. Bound the drain with a deadline, 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?

The through-line

Every move here is the manifesto's one move wearing the diff's clothes: push correctness out of the maintainer's vigilance and into the structure of the code, the parsed type, the local function, the bounded resource, the atomic step, the deadline, the single owner, the visible failure, the kept promise. Write it so the next person can make a correct change while staying ignorant of 99% of the system. Not because they went and read every other file, but because the illegal state can't be built in the first place, the hostile input can't get in, and the wrong thing just cannot be expressed.

Write for the person who will read this at 2am with a pager going off, knowing less than you know now. Make the right thing the easy thing, make the wrong thing hard to express, and never make them hold in their head what the code could have held for them.