DecisionsGENERALSCALE-SPECIFICCONTESTED

Reversible and Irreversible Decisions

Sort decisions by what it costs to undo them, then spend evidence, meetings and caution in proportion. Most decisions are cheap to reverse and are treated as though they were not; a few are permanent and get decided in a chat thread.

The requirement, the obvious build, and why it breaks

Every lesson starts where the work starts: someone asked for something, and the first implementation that comes to mind survives until the requirement changes.

The question

How much evidence does this decision deserve — and is that proportional to what it costs to be wrong?

The requirement

A team has spent three meetings on which HTTP client library to use. In the same week, someone chose a customer-facing identifier scheme in a pull request comment, and it is now in the URLs of an API that customers have integrated with.

The obvious build

Important decisions get a design review; small ones get made by whoever is doing the work. Everyone knows which is which.

Why it breaks

"Important" is not the axis. Choosing an HTTP client feels important and is undoable in an afternoon; choosing what an id looks like feels trivial and is permanent the moment it appears in a customer's database.

How it breaks as requirements change
  • "Important" is not the axis. Choosing an HTTP client feels important and is undoable in an afternoon; choosing what an id looks like feels trivial and is permanent the moment it appears in a customer's database.
  • The two are inversely correlated in practice, because the decisions that are expensive to reverse are the ones that leak into other people's systems — ids, URLs, data formats, event schemas — and those rarely feel like architecture (Design, Architecture and System Design is precisely this distinction: an architectural decision is one that is expensive to reverse).
  • The default is also a decision. An id scheme nobody discussed is one that got chosen by the ORM, and it is exactly as permanent as one that was argued about.
  • And treating everything as important has a cost of its own: meetings for reversible choices, which trains people to route around the process for the ones that matter (Design Review).
RequirementConstraintsInvariantsResponsibilitiesBoundariesInterfacesStateDependenciesFailureImplementationTestsFeedbackEvolution

What limits the solution, and what must never stop being true

This domain leads with these two. A design that ignores its constraints is not a design, and an invariant nobody named is one nothing is protecting.

Constraints
  • Meeting time is the scarcest resource the team has and is not elastic.
  • The team cannot tell in advance which decisions will turn out to matter — only how expensive each is to undo.
  • Some irreversible decisions do not look like decisions at all: a default that was never questioned, a format that leaked into a URL.
Invariants
  • The amount of process applied to a decision is proportional to the cost of undoing it, not to how interesting it is to argue about.

Who owns what, and where the seams fall

Responsibilities decide boundaries; boundaries decide what an interface has to say.

Responsibilities
  • Whoever notices that a decision is irreversible owns saying so before it is merged. That is the entire practice and it usually costs one comment.
  • The team owns keeping a short list of the decision types that are one-way in their system — ids, URLs, event schemas, stored formats, anything a customer can see.
  • Whoever makes a reversible decision owns making it quickly. Deliberating a two-way door is a real cost with no return (When Design Does Not Pay).
Boundaries
  • The line is where a decision escapes the boundary of code you control. Inside a module, almost everything is reversible; the moment it is in a customer's URL, another team's database or a stored record, it is not (Stable Boundaries).
  • This is why boundary design and reversibility are the same subject: a decision hidden behind an interface can be changed, and one exposed through it cannot (Information Hiding).

A ladder of cost-to-undo

Sorting by reversal cost produces an order that does not match how much attention these decisions usually get. The bottom of this ladder is where the meetings go; the top is where the incidents come from.

The evidence column is the practical output. It says how much you should be willing to spend on being right, and for most rows the honest answer is "very little, decide today".

  • The top three rows share one property: someone outside the team can see the decision. That is the strongest single predictor of irreversibility (Stable Boundaries).
  • The bottom rows are where teams spend their deliberation, because they are the ones that feel technical and are fun to argue about.
  • Nothing here is about how hard the decision is to make. Reversal cost and difficulty are unrelated (Design, Architecture and System Design).
DecisionWhat undoing it costsEvidence it deserves
Public id format in URLs (sequential integer vs opaque)A versioned API, a mapping table, a deprecation window, and customers who stored the old ids forever. Effectively permanentThe full apparatus: options, a record, and a default towards opaque even without evidence, because the asymmetry is severe (Stable Identifiers)
Event schema published to other teamsDual publishing, consumer migration on their schedule, and a long tail of stragglersA written contract and a versioning strategy before the first consumer, not after (Versioned Interfaces)
Stored data format or primary key typeA data migration across every historical row, usually online, usually with a backfillA record and a trigger. Cheap to get right on day one and expensive on every later day (Data Migration)
Which databaseA migration project measured in quarters — but internal, and nobody outside has to actA comparison and a record. Serious, and one rung below the customer-visible rows above it (The Trade-off Matrix)
FrameworkExpensive and internal: a rewrite of everything inside its inversion, on your own scheduleA comparison, and a design decision about how much sits inside the inversion — which matters more than the choice (What a Framework Charges)
Module boundaries inside one serviceA refactor, contained, with tests. Days to weeksA conversation and a pull request. Get it wrong and move it (Extract Module)
HTTP client libraryAn afternoon, behind an adapter, and nobody outside the module noticesOne person decides in the pull request. Three meetings on this is the misallocation this lesson is about

Turning a one-way door into a two-way door

Often the best available move is not to decide correctly but to make the decision cheaper to undo, and that is usually a smaller piece of work than getting it right.

Each step below buys reversibility with a specific, honest cost — a lookup, a version field, an adapter. Whether that cost is worth paying is exactly the question, and it is a much easier question than predicting the future.

Converting an irreversible decision, using the customer-facing id as the example
  1. 1
    Find the escape point

    Where does this decision become visible to someone who is not us — a URL, a payload, a stored row, another team's code?

    fails by Missing an indirect escape: an internal id that appears in a webhook or an export nobody thought of as an interface (API Stability).

  2. 2
    Interpose something you own

    Publish an opaque identifier and keep the internal one behind a lookup, so the internal scheme stays yours to change.

    fails by Making the opaque id a reversible encoding of the internal one, which leaks the same information and provides none of the freedom (Information Hiding).

  3. 3
    Version what you publish

    A version on the payload or in the URL, from the first release, so a change is an addition rather than a break.

    fails by Adding versioning after consumers exist, which is the one-way door it was meant to prevent (Backward Compatibility as a Constraint).

  4. 4
    Keep the blast radius small

    Roll the decision out behind a flag or to one tenant first, so reversal is a config change rather than a deploy (Feature Flags and What They Cost).

    fails by Flags that are never removed, which converts a reversibility mechanism into a permanent state-space cost (The Complexity Budget).

  5. 5
    Say what makes it permanent

    One line: "this becomes irreversible when an external client stores it". Then the trigger is observable by someone else.

    fails by Being written in a record nobody reads instead of in the review checklist where the decision recurs (Revisit Triggers).

Every step costs something concrete — a lookup, a version field, a flag, an adapter — and none of them is free. The reason they are usually worth it is that they convert an unbounded future cost into a small present one, which is the same trade this domain makes everywhere (The Cost of Change).

Choosing how much process to spend

The practical output of all this is a routing decision made in about ten seconds, before any discussion of the merits. It is worth making explicit because the default routing — by how interesting the decision is — is close to backwards.

Note that two of the five options below involve deciding immediately. That is the intended distribution: most decisions should be made by one person, quickly, with a line of explanation.

Before the discussion starts

What would it cost to undo this in six months, and who outside the team would have to act?

Nobody outside notices; hours to undo

when A library behind an adapter, an internal module layout, a naming choice inside one package.

cost Decide in the pull request, one line of reasoning. The cost of deliberation exceeds the cost of being wrong (When Design Does Not Pay).

Internal, weeks to undo

when A module boundary, a shared internal interface, a background-job mechanism.

cost One conversation and a short record. Enough to be revisitable, not enough to be a project (Decision Records).

Internal, quarters to undo

when A database, a framework, a persistence model.

cost The full comparison with a caveat and a trigger. This is what the trade-off matrix is for (The Trade-off Matrix).

Visible outside the team, effectively permanent

when Ids in URLs, event schemas, stored formats, anything a customer or another team can store.

cost Slow down, and prefer the option that keeps the decision changeable — opaque, versioned, behind a lookup — even at a real cost in indirection (Versioned Interfaces).

Nobody framed it as a decision at all

when The ORM chose the id type; the framework chose the URL shape; the default was accepted.

cost The most dangerous row, and the reason the one-way-door list belongs in the review checklist rather than in someone's head (A Review Checklist Worth Reading).

How to build it

Most important first.

  • Classify before deliberating: ask "what would it cost to undo this in six months?" and let the answer set the process.
  • For two-way doors, decide fast, write one line, and move. Speed is the correct optimisation and reversibility is the licence for it.
  • For one-way doors, slow down deliberately: options, a written record, and a trigger — the full apparatus, reserved for the small number of decisions that warrant it (Decision Records).
  • Convert one-way doors into two-way doors where you can, because it is usually cheaper than getting them right. An opaque id behind a lookup, a version in the event schema, a feature flag around the rollout (Expand and Contract).
  • Keep the list of one-way door types visible where the decisions happen — in the review checklist, not in a handbook (A Review Checklist Worth Reading).

What the next change costs

The field this whole domain exists for. A structure is only better if it makes the change after this one cheaper — and it is worth saying which changes it does not help.

Cost of the next change
  • Two-way door decided badly: an afternoon, contained, and the team learns something. This is the normal case and it is why speed is correct there.
  • One-way door decided badly: a versioned API, a migration path, a deprecation window, and a year of supporting both. The id scheme is the archetype — sequential integers in a public URL leak business volume and cannot be withdrawn once customers store them.
  • The cost of the practice itself is one question per decision, asked before the discussion rather than after it.
What the recommended approach costs
  • Making a decision reversible usually costs indirection — an opaque id needs a lookup, a versioned schema needs version handling — and that cost is paid whether or not the reversal ever happens.
  • Deciding two-way doors fast means being wrong more often, and a stream of small wrong decisions is genuinely tiring for a team even when each is cheap.
  • Classifying is itself a judgement that can be wrong, and being wrong about reversibility is worse than not classifying, because it licenses speed on a decision that deserved care.

What can go wrong

Failure modes
  • A decision is classified as reversible and turns out not to be, because someone exposed it — an internal id ending up in a webhook payload.
  • Everything gets classified as one-way by cautious engineers, and the process overhead returns in a new form.
  • The classification is done once at design time and never revisited, so a decision that became irreversible when the first integration partner arrived is still being treated as cheap (Revisit Triggers).
  • Reversibility is used to justify not thinking: "we can always change it later" is true and is not a reason to choose badly, because reversible does not mean free (What Technical Debt Actually Is).
Dependencies, and their direction
  • Reversibility is a function of who depends on the decision. The same choice is reversible on Monday and permanent on Friday because an external consumer arrived in between (API Stability).
  • External consumers are the main source of irreversibility, and they are frequently acquired without anyone noticing (API Stability).
  • Stored data is the other: anything written to disk in a format is a decision you can only undo with a migration (Data Migration).
Misreads
  • "Reversible means unimportant." A reversible decision can be badly wrong and cost weeks of rework. It just does not cost a migration and a deprecation window (The Cost of Change).
  • "Irreversible means permanent." It means undoing it requires a migration, a versioning strategy or a customer conversation. Those are expensive, not impossible (Designing the Migration).
  • "Architecture is the big stuff." Architecture is the stuff that is expensive to reverse, which is often small and unglamorous — an id format, a timezone convention, a primary key type (Design, Architecture and System Design).
  • "We can always add a version later." Adding versioning after clients exist is itself a one-way-door problem, and it is the specific case where "later" is most often quoted and least often true (Backward Compatibility as a Constraint).

Testing it, and how it ages

What to test, and at which boundary
  • For a decision you believe is reversible, name the reversal: which files change, and how long. If nobody can answer, it is not known to be reversible (The Cost of Change).
  • For anything customer-visible, test that it is versioned or opaque — that clients cannot depend on structure you did not promise (Versioned Interfaces).
How this design ages
  • Decisions harden over time as dependents accumulate. Reversibility is a decaying property, and the decay rate is proportional to adoption (Stability and Dependency Direction).
  • A team's list of one-way door types is one of the more valuable artefacts it can maintain, and it is usually written after the first expensive mistake.
  • Systems that are easy to change are the ones where past decisions were kept behind boundaries, which is the same claim as the rest of this domain arriving from a different direction (Changeability Is the Goal).

Where this applies

This domain's advice is contested more than most. These labels say what each claim is specific to — and where CONTESTED appears, the note gives the strongest form of the opposing view rather than a caricature.

  • GENERALThat the cost of undoing a decision should govern how much care it gets is not technology-specific. What varies is which decisions are one-way: in a service with external consumers it is contracts and ids, in a library it is public API shape, and in a data platform it is stored formats and partitioning.
  • SCALE-SPECIFICWith one team and no external consumers, almost everything is reversible and the correct posture is speed on nearly all of it. Once there are external integrators or a second team building on your interfaces, the same decisions become one-way overnight, and teams that keep their startup-era decision speed past that point generate their most expensive mistakes right there (API Stability).
  • CONTESTEDThe strongest opposing view is that the two-way-door framing systematically underestimates how sticky "reversible" decisions become: in a real organisation, undoing a merged decision requires re-opening a settled argument, competing with roadmap, and admitting a mistake, so the technical reversal cost is the smallest part of the real one. Engineers who have watched an "easy to change later" library choice survive a decade are describing something true. The counter is that this is an argument for lowering the organisational cost of reversal — cheap deprecation, small blast radius, easy rollback — rather than for deliberating every decision as if it were permanent.

Where the depth lives

This domain teaches the codebase-level structure and hands the rest off.

Domains that do not exist yet
  • System Design — at system scale the same sort applies with different rows: partition keys, topic schemas and regional placement are the one-way doors, and the instinct that "we can migrate later" is weakest exactly where data has already been written.