Field Note 66current

Agonize over the interface, not the choice behind it

Re-implementing a decision now costs hours. Changing an interface costs everyone standing on it. Spend deliberation at the boundary; hold the choice behind it loosely — on one condition: you know a decision was made, and where it lives. Unnoticed ones are the expensive kind.

By
Theo Zourzouvillys
Published
Est. reading time
Tags
architecturedesignprocessdecisionsllm
My Personal LLM Policy: Extract, not generate

The thinking is mine, whether it’s years old or from this week. What a model does is get it out of my head and onto the page — writing time I’d otherwise never spend, not substance I didn’t have. I read every line, I can defend any sentence, and the errors are mine: the same bar I hold everything here to, model or no model.

TL;DR

Deliberation is a budget, and it should be spent on boundaries. What a choice will cost you is no longer how hard it was to build. It is how many things you don’t control are standing on it.

  • The cost of re-implementing a decision has collapsed. The cost of changing an interface has not: on the far side of one are other teams, clients you have already shipped, and rows already written in the old shape. That asymmetry is the whole note.
  • So agonize at the boundary — the schema, the envelope, the error taxonomy, the identifiers, the data model. Behind the seam — the library, the algorithm, the internal structure, the storage engine — decide fast and hold it loosely.
  • The condition is that the decision has to be locatable. You need to be able to name it, point at where it lives, and replace it without a hunt. A decision nobody noticed making is not cheap to reverse at any price, because by then it isn’t one decision — it’s a hundred places.
  • The failure mode of the cheap era isn’t choosing wrong. It’s a hundred unnamed choices, made at generation speed, none of them written down, hardening into an architecture nobody chose.
  • Cheap to change is not free to churn. Record why, so the next person reopens the question on new evidence rather than on taste.

Context

The decision advice most of us absorbed was priced for a world where building the thing was the expensive part. Bezos’s 2015 shareholder letterJeff Bezos — 2015 Letter to ShareholdersIntroduces Type 1 and Type 2 decisions: one-way doors, consequential and nearly irreversible, deserving slow deliberation; and two-way doors, changeable and reversible, which 'can and should be made quickly by high judgment individuals or small groups'. A footnote names the opposite error — organisations that habitually use the light-weight process on Type 1 decisions go extinct before they get large.s2.q4cdn.com ↗ is the crispest version of it: Type 1 decisions are one-way doors, consequential and nearly irreversible, to be made slowly and with great deliberation; Type 2 decisions are two-way doors, and should be made quickly. The framework is good and I still use it. What has moved is where the line falls.

ParnasD.L. Parnas — On the Criteria To Be Used in Decomposing Systems into Modules (CACM 15(12), 1972)The paper that introduced information hiding. A system should be decomposed by the design decisions each module conceals from the rest, not by the steps in its processing — so that each of those decisions can later change without the rest of the system finding out.dl.acm.org ↗ supplied the other half fifty years ago: decompose a system by the decisions each module hides, not by the steps in its processing. A boundary exists precisely so the choice behind it can change without the rest of the system finding out. That argument has not changed. What changed is the payoff.

Re-implementing behind a stable contract used to be weeks, and weeks is what turned a merely-adequate choice into a permanent one. It’s now hours. Swap the queue client, replace the hand-rolled state machine, move the parser, take a second run at a module with a cleaner structure — given a real interface and tests, that’s an afternoon. ZFN-23Field Note · currentZFN-23 — Rewriting an implementation is fine — refactoring isn't always the answerRefactoring isn't always right. When the structure is wrong at the root, it's fine — often better — to rewrite an implementation from scratch. Clean interfaces and data models make the implementation disposable: stable contract, swappable internals. LLMs make it cheaper still.Why it's cited here: The sibling note, from the other end. There the claim is that an implementation behind a stable contract is safe to throw away; here the claim is what that does to the decision you make before writing anything.Open ZFN-23 → makes the case that rewriting behind a contract is safe; this note is about what that does to the decision you make before writing anything. If reversal is an afternoon, deliberating for a week to avoid it is an expensive way to be slightly less wrong.

Nothing similar happened to interfaces, because an interface isn’t code. It’s a promise to someone who isn’t in the room. Changing one means coordinating with teams who have their own roadmaps (ZFN-47Field Note · currentZFN-47 — Govern the contract between teams, not the code inside themTeams own services end to end; one team owns the gateway that dispatches to them. Govern exactly one thing centrally — the contract at the boundary (schema, identity, errors, idempotency) — and enforce it at runtime. Don't mandate libraries; ship them as an opt-in blueprint.Why it's cited here: Why the boundary stayed expensive. On the far side of a contract are teams with their own roadmaps, and no amount of generation speed rewrites their code for them.Open ZFN-47 →), clients you shipped and cannot recall, and data already on disk in the old shape (ZFN-62Field Note · currentZFN-62 — Expand, migrate, contract: schema changes in three movesEvery deploy runs two code versions against one database — and rollback runs yesterday's code on today's schema. No schema change may break either. So every migration is three shippable moves: expand (additive), migrate (backfill, verify), contract (remove, later, deliberately).Why it's cited here: The other reason boundaries stay expensive: data already written under a schema cannot be regenerated, so a shape change is three deploys and a backfill rather than an afternoon.Open ZFN-62 →). An LLM will rewrite every call site in your repository in minutes and can do nothing at all about the ones in someone else’s. Generation speed applies to code you own; a boundary is exactly the line where that stops being true.

So the thing that used to ration change was effort, and it doesn’t any more. What replaced it is awareness. You can be loosely bound to a decision — genuinely willing to redo it next month — as long as you know you made one and know where it lives. That qualifier carries the entire argument.

Recommendation

Spend deliberation in proportion to who is standing on the choice, and make sure every choice you make is one you can find again.

  • Sort by what’s on the far side, not by how important it feels. A storage engine feels like a momentous decision and is usually a contained one. A field name in a published payload feels trivial and is close to forever. The useful question isn’t “how significant is this?” — it’s “who would I have to call?”
  • Behind a seam, pick the boring option in an afternoon. You’re not choosing the final answer, you’re choosing the current one. Take the thing you can reason about today; the cost of being wrong is a rewrite you can afford.
  • Write down that a decision happened, even a cheap one. (ZFN-1Field Note · currentZFN-1 — Keep engineering decision recordsRecord significant engineering decisions as short, versioned markdown files — context, decision, consequences. Write one for cross-team contracts, directional principles, hard-to-reverse choices, and conventions others must follow. Cite them instead of re-arguing.Why it's cited here: The mechanism that makes a decision locatable. Cheap reversal only works if someone can find the choice and the reasoning behind it a year later.Open ZFN-1 →) A few lines. What you’re preserving isn’t the answer, it’s the fact that there was a question — plus enough context that someone can reopen it without re-deriving the problem. That record is the difference between a decision and a habit.
  • Give every decision one place to live. (ZFN-22Field Note · currentZFN-22 — Quarantine bad architecture behind an interface, then replace itWhen a subsystem is complex and badly architected, quarantine it at its seam: write a clean adapter interface over the mess so the rest of the system depends on the contract, then build a better implementation behind it and expose the new interface directly.Why it's cited here: Containment is the precondition. A choice with one place to live is cheap to revisit; the same choice spread across the codebase is not a decision any more.Open ZFN-22 →) One adapter, one module, one config value. If the honest answer to “where would I change this?” is a grep across the repository, it stopped being a decision a while ago.
  • Don’t gold-plate the interface either. “The boundary is expensive” is not a licence for speculative generality, which is its own permanent tax. Make it specific and honest — name what you actually mean (ZFN-51Field Note · currentZFN-51 — Design the request envelope before the first endpointAuth, idempotency keys, trace IDs, vector clocks: context about a request, not part of it. Define an envelope alongside the payload in the schema on day one — transport-native, per-hop vs propagated, owned by generated SDKs and middleware. The retrofit is what costs you.Open ZFN-51 →, ZFN-58Field Note · currentZFN-58 — Errors are part of the contractError paths are the half of your API clients depend on most, and usually the half nobody designed. Enumerate error codes in the schema like any other type: stable code, retryable-or-not, whose fault, structured params. Machines branch on codes — anyone parsing prose is broken.Open ZFN-58 →) — and version it so it can move. The goal is knowing which side of the line you’re on, not flexibility everywhere.
  • Reopen on evidence. Cheap reversal makes it tempting to re-litigate on taste, or on whatever someone read about last week. The recorded why is the test: if nothing in it has changed, neither has the decision.

Caveat. Some choices are structural even when they look internal. The data model is the classic one (ZFN-20Field Note · currentZFN-20 — The simplest-looking system is often the most complex to live withThe system that's simplest to stand up often isn't simplest to live with — it skips the correctness edge cases, so bugs and inconsistency surface fast. A more deliberate design has more parts but fewer surprises, and is often the simpler one over time.Open ZFN-20 →): it leaks into every consumer whether you meant it to or not, and no seam rescues you from getting it wrong. If a choice will reshape everything downstream, treat it as a boundary regardless of which directory it lives in.

Consequences

Easier:

  • Most decisions get faster, honestly rather than recklessly — and the interior is where most decisions are.
  • Being wrong is survivable exactly where you’re most likely to be wrong: inside, where you had the least information when you started.
  • Running two implementations against one interface becomes a normal way to settle an argument rather than a luxury.

Harder:

  • Generation outruns notice. Working at LLM speed produces decisions faster than anyone records them, and the result is a coherent-looking system full of choices nobody remembers making — the expensive kind. ZFN-28Open problem · currentZFN-28 — Capability without understanding: brute-force LLM PRsAn open problem: people brute-force PRs with LLMs in domains they don't understand, taking on more than their knowledge supports — and the struggle that used to teach them is smoothed away. How do we stop un-understood code without killing learning or banning a good tool?Open ZFN-28 → is the same failure seen from the understanding side.
  • Telling the two sides of the line apart is now the skill, and it’s a judgement call with no checklist. Bezos’s own footnote names the opposite error: organisations that habitually run the light-weight process on genuine one-way doors go extinct before they get large. Cheap change doesn’t abolish one-way doors, it moves some of them and leaves the rest exactly where they were.
  • Held loosely is one flinch from churn. A team that rewrites its internals every quarter because it now can has spent the entire saving.

New obligations:

  • Every boundary needs someone who can state what is promised across it, and a version story for when the promise changes.
  • Decision records stop being ceremony reserved for the big calls. They become the thing that keeps the cheap ones cheap.

References

  • Parnas (1972)D.L. Parnas — On the Criteria To Be Used in Decomposing Systems into Modules (CACM 15(12), 1972)The paper that introduced information hiding. A system should be decomposed by the design decisions each module conceals from the rest, not by the steps in its processing — so that each of those decisions can later change without the rest of the system finding out.dl.acm.org ↗ — the original case that a module boundary exists to hide a decision so it can change. The cost side of this note, written fifty years before the benefit side moved.
  • Bezos, 2015 letter to shareholdersJeff Bezos — 2015 Letter to ShareholdersIntroduces Type 1 and Type 2 decisions: one-way doors, consequential and nearly irreversible, deserving slow deliberation; and two-way doors, changeable and reversible, which 'can and should be made quickly by high judgment individuals or small groups'. A footnote names the opposite error — organisations that habitually use the light-weight process on Type 1 decisions go extinct before they get large.s2.q4cdn.com ↗ — one-way and two-way doors. The frame this note revises: cheap reimplementation moves doors between the two lanes, it doesn’t remove the lanes.
  • ZFN-23Field Note · currentZFN-23 — Rewriting an implementation is fine — refactoring isn't always the answerRefactoring isn't always right. When the structure is wrong at the root, it's fine — often better — to rewrite an implementation from scratch. Clean interfaces and data models make the implementation disposable: stable contract, swappable internals. LLMs make it cheaper still.Why it's cited here: The sibling note, from the other end. There the claim is that an implementation behind a stable contract is safe to throw away; here the claim is what that does to the decision you make before writing anything.Open ZFN-23 → — the sibling note. Rewriting behind a contract is safe; this one is about the decision you make before you write.
  • ZFN-1Field Note · currentZFN-1 — Keep engineering decision recordsRecord significant engineering decisions as short, versioned markdown files — context, decision, consequences. Write one for cross-team contracts, directional principles, hard-to-reverse choices, and conventions others must follow. Cite them instead of re-arguing.Why it's cited here: The mechanism that makes a decision locatable. Cheap reversal only works if someone can find the choice and the reasoning behind it a year later.Open ZFN-1 → — how a decision stays locatable once it’s cheap.
  • ZFN-22Field Note · currentZFN-22 — Quarantine bad architecture behind an interface, then replace itWhen a subsystem is complex and badly architected, quarantine it at its seam: write a clean adapter interface over the mess so the rest of the system depends on the contract, then build a better implementation behind it and expose the new interface directly.Why it's cited here: Containment is the precondition. A choice with one place to live is cheap to revisit; the same choice spread across the codebase is not a decision any more.Open ZFN-22 → — containment: one place to change it.
  • ZFN-47Field Note · currentZFN-47 — Govern the contract between teams, not the code inside themTeams own services end to end; one team owns the gateway that dispatches to them. Govern exactly one thing centrally — the contract at the boundary (schema, identity, errors, idempotency) — and enforce it at runtime. Don't mandate libraries; ship them as an opt-in blueprint.Why it's cited here: Why the boundary stayed expensive. On the far side of a contract are teams with their own roadmaps, and no amount of generation speed rewrites their code for them.Open ZFN-47 → / ZFN-62Field Note · currentZFN-62 — Expand, migrate, contract: schema changes in three movesEvery deploy runs two code versions against one database — and rollback runs yesterday's code on today's schema. No schema change may break either. So every migration is three shippable moves: expand (additive), migrate (backfill, verify), contract (remove, later, deliberately).Why it's cited here: The other reason boundaries stay expensive: data already written under a schema cannot be regenerated, so a shape change is three deploys and a backfill rather than an afternoon.Open ZFN-62 → — why the boundary stayed expensive: other teams, and data already written.
  • ZFN-20Field Note · currentZFN-20 — The simplest-looking system is often the most complex to live withThe system that's simplest to stand up often isn't simplest to live with — it skips the correctness edge cases, so bugs and inconsistency surface fast. A more deliberate design has more parts but fewer surprises, and is often the simpler one over time.Open ZFN-20 → — the data model is a boundary even when it looks like an internal detail.

Changelog

  • 2026-08-24: First published as a Field Note.