{"course":{"slug":"how-software-changed","title":"How Software Development Changed","url":"https://addaly.com/learn/how-software-changed","level":"intermediate","track":"work"},"lesson":{"slug":"one-way-doors","title":"Decisions that do not swing back","url":"https://addaly.com/learn/how-software-changed/one-way-doors","position":80,"of":87,"minutes":9,"answer":"Reversible decisions got much cheaper and irreversible ones did not move at all, so deliberation should now concentrate on the few choices (interface shape, key scheme, time representation, tenancy.","keyIdea":"Reversible decisions got much cheaper and irreversible ones did not move at all, so deliberation should now concentrate on the few choices (interface shape, key scheme, time representation, tenancy, what you collect) whose reversal costs weeks rather than an afternoon."},"body":{"format":"markdown","text":"## The ratio changed, not the doors\n\nSort every decision by what reversing it costs.\n\nA **two-way door** can be undone in an afternoon. The name of an internal function, the structure of a module, which library formats your dates, how a handler is organised. These were never expensive, and generation made them cheaper still: you can now try the alternative rather than argue about it.\n\nA **one-way door** costs weeks or months to reverse, and sometimes cannot be reversed at all because other people depend on it. These did not get cheaper by a single percent.\n\nSo the ratio moved sharply, and the practical consequence is uncomfortable for most teams: you should now spend **more** of your deliberation on fewer decisions. Time argued over a module layout is time taken from the decision that will still be hurting in 2030.\n\n> Figure: Two-way doors and one-way doors. An afternoon to reverse, so decide fast: The name of an internal function; How a module is laid out; Which library formats your dates; How a request handler is organised; Cheaper still now: build both, keep one, keep the knowledge. Weeks or never, so slow down here: A public interface, once a third party calls it; The primary key scheme, on a table with fifty million rows; How you represent time, when a government changes the rules; One database per customer, or one database with a tenant column; What you collect, and what you failed to collect. Reversible decisions got much cheaper and irreversible ones did not move at all. The uncomfortable consequence is that you should now spend more deliberation on fewer decisions.\n\n## What is actually a one-way door\n\n**Your public interface.** Once a third party calls it, the shape is fixed until you can make them all change, which for a paying customer means never. This includes webhook payloads and anything in a URL.\n\n**Your primary key scheme.** Integers, UUIDv4, UUIDv7, ULID: pick wrong and you find out at scale. Random UUIDs as a clustered primary key scatter inserts across the index and fragment it; time-ordered identifiers do not. Reversing this on a table with fifty million rows and eleven foreign keys is a multi-week migration with downtime risk, and every integration that stored your identifiers is now affected.\n\n**How you represent time.** Storing local time without a zone, or storing an instant when you needed a calendar date, or assuming offsets are stable. Timezone rules change by government decree; a stored offset is a fact that expires. Correcting this later means reinterpreting historical data you can no longer interpret.\n\n**Your tenancy model.** One database per customer, or one database with a tenant column, is a decision made in week one that determines what your compliance story, your noisy-neighbour behaviour and your per-customer restore look like for a decade.\n\n**Your authentication and identity model.** Whether a user can belong to two organisations. Whether identity is an email address. These propagate into every table.\n\n**What you collect.** Data you gathered without a basis is a liability that does not go away by deleting the column, and data you failed to collect cannot be recovered retrospectively.\n\n**Synchronous or event-driven.** Changing the fundamental interaction style of a system touches everything.\n\n## The question to ask out loud\n\nBefore a design decision, one sentence:\n\n> If this is wrong, what does it cost to change in eighteen months, when there are four hundred thousand rows, three external integrations and nobody here who wrote it?\n\nAn afternoon means decide fast and move. Six weeks means stop, write it down, get a second reader, and consider whether you can defer the decision until you know more.\n\n## Deferring is a real option\n\nThe strongest move on a one-way door is often not to decide well but to **not walk through it yet**.\n\nDo not publish the API to third parties until the shape has survived two internal consumers. Keep identifiers opaque so that you can change what is behind them. Write the adapter that isolates the choice, so the decision is made in one file rather than in four hundred. Ship the version that has less in it.\n\nThis is cheaper than it used to be, because implementing two candidate designs to see which one is awkward is now an afternoon rather than a fortnight. That is the new option and it is under-used: build both, throw one away, keep the knowledge.\n\n## Why generation makes the one-way doors riskier\n\nOne specific hazard, worth naming.\n\nAn irreversible decision, made implicitly, now propagates much faster than before. The model picks an identifier scheme and a time representation because it must pick something, and it picks whatever is most common. Two weeks later there are ninety files depending on it, and the decision nobody made is now load-bearing.\n\nThe cost of a wrong one-way door was always the same; what changed is how quickly you get through it without noticing. So the check belongs at the start of a piece of work, not at review, and the specification lessons in module four are where it lives: the decisions worth writing down are exactly the ones whose door does not swing back.\n\n## The caveat\n\nThe two-way and one-way distinction is a heuristic, not a taxonomy. Doors vary by context: a public API with three internal consumers is a two-way door; the same API with three thousand paying customers is welded shut. And people over-apply it, classifying everything as irreversible in order to justify delay, which is its own failure mode. The question is not whether reversal is possible. It is what reversal costs, in the situation you will actually be in."},"check":{"question":"Why does faster code generation increase the risk attached to one-way doors, even though it does not change their reversal cost?","options":[{"text":"An implicit choice propagates through dozens of files before anyone notices a decision was made.","correct":true},{"text":"Reviewers focus on correctness rather than design, so architectural choices pass unexamined in review.","correct":false,"tempting":"A real review gap, but the decision has usually already propagated before review begins."},{"text":"Generated code contains more irreversible design choices per line than hand-written code does.","correct":false,"tempting":"Density of decisions is not the issue; the same choices would appear in hand-written code."},{"text":"Models favour uncommon patterns, so the defaults they pick are more likely to be wrong than a human's.","correct":false,"tempting":"Models favour common patterns; the hazard is the speed of propagation, not the quality of the default."}]},"prev":{"slug":"essence-and-accident","title":"The distinction that keeps being right","url":"https://addaly.com/learn/how-software-changed/essence-and-accident"},"next":{"slug":"domain-knowledge-as-the-moat","title":"The facts that exist in no corpus","url":"https://addaly.com/learn/how-software-changed/domain-knowledge-as-the-moat"},"authorship":"Founder and series editor: Dr Mustafa Mun. Written by AI models to a written standard. Exam keys checked blind by a second model: 3,665 of 3,666 agreed. Academic review invited.","review":{"status":"Draft, open for academic review"},"cite":"Addaly (2026) 'Decisions that do not swing back', in How Software Development Changed. Edited by M. Mun. Addaly. Available at: https://addaly.com/learn/how-software-changed/one-way-doors (Accessed: 13 October 2026).","licence":{"name":"CC BY-NC-SA 4.0","url":"https://creativecommons.org/licenses/by-nc-sa/4.0/"},"reader":{"schema":1,"title":"Decisions that do not swing back","courseTitle":"How Software Development Changed","module":{"index":9,"slug":"what-did-not-change","title":"What did not change, and what to do now"},"answer":null,"keyIdea":"Reversible decisions got much cheaper and irreversible ones did not move at all, so deliberation should now concentrate on the few choices (interface shape, key scheme, time representation, tenancy, what you collect) whose reversal costs weeks rather than an afternoon.","hero":{"kind":"figure","figure":{"t":"figure","label":"Figure","figure":{"left":{"title":"An afternoon to reverse, so decide fast","items":["The name of an internal function","How a module is laid out","Which library formats your dates","How a request handler is organised","Cheaper still now: build both, keep one, keep the knowledge"]},"type":"compare","right":{"title":"Weeks or never, so slow down here","items":["A public interface, once a third party calls it","The primary key scheme, on a table with fifty million rows","How you represent time, when a government changes the rules","One database per customer, or one database with a tenant column","What you collect, and what you failed to collect"]},"title":"Two-way doors and one-way doors","caption":"Reversible decisions got much cheaper and irreversible ones did not move at all. The uncomfortable consequence is that you should now spend more deliberation on fewer decisions."},"alt":"Figure: Two-way doors and one-way doors. An afternoon to reverse, so decide fast: The name of an internal function; How a module is laid out; Which library formats your dates; How a request handler is organised; Cheaper still now: build both, keep one, keep the knowledge. Weeks or never, so slow down here: A public interface, once a third party calls it; The primary key scheme, on a table with fifty million rows; How you represent time, when a government changes the rules; One database per customer, or one database with a tenant column; What you collect, and what you failed to collect. Reversible decisions got much cheaper and irreversible ones did not move at all. The uncomfortable consequence is that you should now spend more deliberation on fewer decisions."}},"blocks":[{"t":"h2","id":"the-ratio-changed-not-the-doors","runs":[{"text":"The ratio changed, not the doors"}]},{"t":"p","runs":[{"text":"Sort every decision by what reversing it costs."}]},{"t":"p","runs":[{"text":"A "},{"text":"two-way door","b":true},{"text":" can be undone in an afternoon. The name of an internal function, the structure of a module, which library formats your dates, how a handler is organised. These were never expensive, and generation made them cheaper still: you can now try the alternative rather than argue about it."}]},{"t":"p","runs":[{"text":"A "},{"text":"one-way door","b":true},{"text":" costs weeks or months to reverse, and sometimes cannot be reversed at all because other people depend on it. These did not get cheaper by a single percent."}]},{"t":"p","runs":[{"text":"So the ratio moved sharply, and the practical consequence is uncomfortable for most teams: you should now spend "},{"text":"more","b":true},{"text":" of your deliberation on fewer decisions. Time argued over a module layout is time taken from the decision that will still be hurting in 2030."}]},{"t":"h2","id":"what-is-actually-a-one-way-door","runs":[{"text":"What is actually a one-way door"}]},{"t":"p","runs":[{"text":"Your public interface.","b":true},{"text":" Once a third party calls it, the shape is fixed until you can make them all change, which for a paying customer means never. This includes webhook payloads and anything in a URL."}]},{"t":"p","runs":[{"text":"Your primary key scheme.","b":true},{"text":" Integers, UUIDv4, UUIDv7, ULID: pick wrong and you find out at scale. Random UUIDs as a clustered primary key scatter inserts across the index and fragment it; time-ordered identifiers do not. Reversing this on a table with fifty million rows and eleven foreign keys is a multi-week migration with downtime risk, and every integration that stored your identifiers is now affected."}]},{"t":"p","runs":[{"text":"How you represent time.","b":true},{"text":" Storing local time without a zone, or storing an instant when you needed a calendar date, or assuming offsets are stable. Timezone rules change by government decree; a stored offset is a fact that expires. Correcting this later means reinterpreting historical data you can no longer interpret."}]},{"t":"p","runs":[{"text":"Your tenancy model.","b":true},{"text":" One database per customer, or one database with a tenant column, is a decision made in week one that determines what your compliance story, your noisy-neighbour behaviour and your per-customer restore look like for a decade."}]},{"t":"p","runs":[{"text":"Your authentication and identity model.","b":true},{"text":" Whether a user can belong to two organisations. Whether identity is an email address. These propagate into every table."}]},{"t":"p","runs":[{"text":"What you collect.","b":true},{"text":" Data you gathered without a basis is a liability that does not go away by deleting the column, and data you failed to collect cannot be recovered retrospectively."}]},{"t":"p","runs":[{"text":"Synchronous or event-driven.","b":true},{"text":" Changing the fundamental interaction style of a system touches everything."}]},{"t":"h2","id":"the-question-to-ask-out-loud","runs":[{"text":"The question to ask out loud"}]},{"t":"p","runs":[{"text":"Before a design decision, one sentence:"}]},{"t":"quote","runs":[{"text":"If this is wrong, what does it cost to change in eighteen months, when there are four hundred thousand rows, three external integrations and nobody here who wrote it?"}]},{"t":"p","runs":[{"text":"An afternoon means decide fast and move. Six weeks means stop, write it down, get a second reader, and consider whether you can defer the decision until you know more."}]},{"t":"h2","id":"deferring-is-a-real-option","runs":[{"text":"Deferring is a real option"}]},{"t":"p","runs":[{"text":"The strongest move on a one-way door is often not to decide well but to "},{"text":"not walk through it yet","b":true},{"text":"."}]},{"t":"p","runs":[{"text":"Do not publish the API to third parties until the shape has survived two internal consumers. Keep identifiers opaque so that you can change what is behind them. Write the adapter that isolates the choice, so the decision is made in one file rather than in four hundred. Ship the version that has less in it."}]},{"t":"p","runs":[{"text":"This is cheaper than it used to be, because implementing two candidate designs to see which one is awkward is now an afternoon rather than a fortnight. That is the new option and it is under-used: build both, throw one away, keep the knowledge."}]},{"t":"h2","id":"why-generation-makes-the-one-way-doors-riskier","runs":[{"text":"Why generation makes the one-way doors riskier"}]},{"t":"p","runs":[{"text":"One specific hazard, worth naming."}]},{"t":"p","runs":[{"text":"An irreversible decision, made implicitly, now propagates much faster than before. The model picks an identifier scheme and a time representation because it must pick something, and it picks whatever is most common. Two weeks later there are ninety files depending on it, and the decision nobody made is now load-bearing."}]},{"t":"p","runs":[{"text":"The cost of a wrong one-way door was always the same; what changed is how quickly you get through it without noticing. So the check belongs at the start of a piece of work, not at review, and the specification lessons in module four are where it lives: the decisions worth writing down are exactly the ones whose door does not swing back."}]},{"t":"h2","id":"the-caveat","runs":[{"text":"The caveat"}]},{"t":"p","runs":[{"text":"The two-way and one-way distinction is a heuristic, not a taxonomy. Doors vary by context: a public API with three internal consumers is a two-way door; the same API with three thousand paying customers is welded shut. And people over-apply it, classifying everything as irreversible in order to justify delay, which is its own failure mode. The question is not whether reversal is possible. It is what reversal costs, in the situation you will actually be in."}]}],"check":{"question":[{"text":"Why does faster code generation increase the risk attached to one-way doors, even though it does not change their reversal cost?"}],"options":[{"text":[{"text":"An implicit choice propagates through dozens of files before anyone notices a decision was made."}],"correct":true,"tempting":null},{"text":[{"text":"Reviewers focus on correctness rather than design, so architectural choices pass unexamined in review."}],"correct":false,"tempting":[{"text":"A real review gap, but the decision has usually already propagated before review begins."}]},{"text":[{"text":"Generated code contains more irreversible design choices per line than hand-written code does."}],"correct":false,"tempting":[{"text":"Density of decisions is not the issue; the same choices would appear in hand-written code."}]},{"text":[{"text":"Models favour uncommon patterns, so the defaults they pick are more likely to be wrong than a human’s."}],"correct":false,"tempting":[{"text":"Models favour common patterns; the hazard is the speed of propagation, not the quality of the default."}]}],"order":[2,0,1,3],"why":null},"prev":{"slug":"essence-and-accident","title":"The distinction that keeps being right","minutes":9},"next":{"slug":"domain-knowledge-as-the-moat","title":"The facts that exist in no corpus","minutes":9}}}