Skip to main content

Reversibility: One-Way vs Two-Way Doors

What This Concept Is

Some decisions are easy to undo. Some are expensive, slow, or impossible. The Amazon-style framing: decisions are either

  • Two-way doors -- if wrong, you notice and walk back. Internal naming, class layout, which file hosts a helper, how a module is split.
  • One-way doors -- reversing requires heavy cost: migrations, rewrites, external communication. Database choice, public API shape, authentication model, language / framework, cross-team integration contracts, persisted data format.

The design-review question is: how reversible is this decision? The answer should drive how much time, how many reviewers, and how much documentation the decision deserves.

Why It Matters Here

Most engineers spend the same energy on every decision, which over-invests in two-way doors and under-invests in one-way doors. Over-investing in two-way doors is not free -- it slows shipping, it centers opinions that will not matter in a week, and it teaches teams that every PR needs a meeting.

Under-investing in one-way doors is worse. An under-reviewed database migration, a poorly thought-through API shape, or a hurried auth choice can shape the codebase's work for years.

Concrete Example

Decision A: What do I name the internal helper that converts line items to tax?

  • Two-way door. You can rename anytime. Ship, move on.

Decision B: Should our public API return ISO 8601 strings or Unix timestamps?

  • One-way door (mostly). Once customers integrate, reversing is a version bump and a deprecation window. Worth 30 minutes of deliberate thought and an ADR. Not worth two weeks.

Decision C: Should we run this service on Postgres or DynamoDB?

  • Firmly one-way door. Data migration plus operational retraining plus a rewrite of querying code. Worth a design doc, an ADR, and at least two senior reviewers.

Decision D: Should I use an enum or a string constant for the order status?

  • Two-way door. A targeted refactor covers it.

Decision E: Put retry logic in the client library or in the service?

  • One-way-ish. Reversing means cascading changes in every client. Deserves an ADR.

Common Confusion / Misconception

"If in doubt, treat as one-way." Sounds safe, but the cost is every decision becoming heavyweight. Teams that do this ship slowly and decide badly on the few real one-way doors, because the review muscle is exhausted.

"If in doubt, treat as two-way." Also wrong, because the failures from a missed one-way door are exactly the catastrophic kind.

"Reversibility = code difficulty." Reversibility is about total cost to change, not code lines. A database choice is one config line but enormous to reverse. A 400-line refactor of a private module is reversible by one PR.

"Old decisions become two-way doors over time." The opposite is true. The more callers, integrations, or persisted data depend on a decision, the more one-way it becomes. Revisit sooner, not later, when you suspect a decision was wrong.

"Reversibility replaces judgment." It does not. It reframes it. You still have to decide. You are calibrating how much effort the decision deserves.

How To Use It

Before starting on a design:

  1. List the decisions inside it.
  2. Label each as two-way, one-way, or one-way-ish.
  3. Route effort accordingly:
    • Two-way: ship, iterate.
    • One-way-ish: write a short section in the design doc or a lightweight ADR.
    • One-way: full ADR, two senior reviewers, explicit alternatives considered.

In review, when you push back on a decision, say which category it is in:

This is a one-way door (public API shape). Worth a longer discussion before merge.

or

This is a two-way door (internal naming). I have a suggestion below but do not treat it as blocking.

That phrase alone saves hours of thread time.

Check Yourself

  1. Give a two-way door inside your current codebase and a one-way door.
  2. Why is labeling every decision as one-way a failure, even though it sounds cautious?
  3. Why do one-way doors get more one-way, not less, as a system ages?

Mini Drill or Application

For each decision, label it and justify. For one-way doors, list two things you would want in an ADR. For two-way doors, note how you would reverse if wrong.

  1. Choice of primary key format (UUID vs auto-increment int) in a customer-facing table.
  2. Function naming convention in a private utility file.
  3. Whether to expose a webhook to customers.
  4. Whether to use a CSS framework internally (React + Tailwind vs React + CSS modules).
  5. Decision to send emails synchronously from a request handler instead of via a queue.

Read This Only If Stuck