What Cannot Be Simplified
Most of a system can be simplified in V1; a few things can only be done or not done — money, identity, and data that cannot be recreated. Knowing which is which is the whole skill of scoping an MVP.
The situation, the reflex, and why it stalls
Every lesson starts where being stuck starts: someone has a problem, and the first move that comes to mind feels like progress.
Of everything in this system, which parts can I make smaller without making them wrong — and which parts have no smaller version?
Every time I propose a simplification someone says "but what about…", and every time someone proposes one I have the same worry. I do not have a way of telling a safe simplification from a dangerous one, so we argue about each one from scratch.
Simplify by size: anything small is allowed to be rough, anything large gets done properly. Password storage is one function, so it is small, so it can be rough; the admin panel is large, so it gets the careful treatment.
Size is the wrong axis. The smallest functions in a store — the one that hashes a password, the one that computes a total, the one that decrements stock — carry the invariants the whole system depends on, and the largest screens carry almost none.
- Size is the wrong axis. The smallest functions in a store — the one that hashes a password, the one that computes a total, the one that decrements stock — carry the invariants the whole system depends on, and the largest screens carry almost none.
- Each simplification is argued on instinct, so the outcome depends on who was in the room. A team that has been burned by money bugs protects money; a team that has been burned by data loss protects the database; neither has a rule the other could apply.
- The dangerous simplifications are the quietest. "Store prices as a float", "skip the unique constraint for now", "we will add backups when we go live" produce no visible symptom in development, so they never come up for argument at all.
The move
Precisely enough to apply it to a problem you have never seen — not a slogan.
- Ask of each part: *can it be smaller and still true, or only smaller and wrong?* A shipping calculator can become a fixed fee and still be true — the customer is charged what they were told. A stock count cannot become "approximately right"; it is either the number of units you can sell or it is a lie. The first kind is simplified; the second kind is done or excluded.
- The parts with no smaller version cluster in three places: money (amounts, totals, what was charged, refunds), identity (who this is, what they may do, what they can see), and irrecoverable data (an order that happened, a message that was sent, a file that was uploaded — anything you cannot regenerate from something else). Everything else is usually a scope decision.
- For each untouchable, the choices are: do it properly, have someone else do it (a provider, the database's constraints), or leave the capability out entirely. "Do it roughly" is not on the list. Leaving it out is often fine — a store with no accounts at all, guest checkout only, has no identity problem to get wrong.
- Turn "properly" into a specific invariant and a specific mechanism, so the discussion is about something checkable. "Money is done properly" means: amounts are integers in minor units, the total is recomputed server-side from stored prices, and the order records what was actually charged (Invariants in an Online Store).
Simplify, do properly, delegate, or exclude
The matrix is the store's V1 sorted by the question "smaller and still true?". The interesting rows are the ones where the answer is no: each names the invariant and where it is enforced, because "done properly" without a mechanism is a wish.
| Part | Smaller and still true? | Decision | Invariant / mechanism |
|---|---|---|---|
| Shipping cost | Yes — a fixed fee | Simplify | Customer pays what was displayed; the fee is a constant in one place |
| Search | Yes — filter by name | Simplify | None needed |
| Admin screens | Yes — a database client | Exclude | None needed in V1 |
| Order total, amount charged | No | Do properly | Integer minor units; recomputed from stored OrderItem prices; the charge amount is stored on the Payment |
| Stock | No | Do properly | Decrement in the order transaction; CHECK (stock >= 0) |
| Card handling | No | Delegate | Hosted payment page; the backend learns the outcome from the provider callback |
| Accounts and passwords | No | Exclude | Guest checkout; order link with an unguessable token |
| An order that was paid | No | Do properly | Written before the customer is told; never only in memory |
What I do not yet know about the untouchables
Deciding that money is untouchable does not tell you how to keep it true. Each untouchable usually hides an unknown, and the board turns those into questions small enough to answer before the code depends on the answer.
- ✓Amounts will be integers in the smallest unit of one currency.
- ✓The order is created in the same transaction that decrements stock.
- ✓The provider hosts the card form; we never see card numbers.
- ~The provider will call us back exactly once per payment. Almost certainly false; to be verified before the handler is written.
? Money is hard.
becomes When the provider says the payment succeeded but our database write of "paid" fails, what state is the order in, and how does it recover?
experiment Simulate the callback with the database unavailable; see whether a retry of the callback repairs the order or creates a second one.
? Idempotency.
becomes If the same checkout request arrives twice with the same idempotency key, does the second one return the first order, and what if the first is still in flight?
experiment Fire two identical requests concurrently against a local server and inspect the orders table afterwards.
? Guest orders.
becomes How does a guest find their order again, and can anyone else find it by guessing?
experiment Generate the order link token; try to enumerate it; decide on its length and whether it expires.
Choosing the mechanism
For an untouchable, the question is never "how careful should we be" but "which mechanism keeps it true with the least of our own code". The options have different costs; the criteria, not a winner, are the lesson.
This part cannot be smaller and true. Which mechanism keeps it true in V1?
when The invariant is about stored data — stock not negative, one order per checkout key, a price on every item.
cost Must be designed into the schema now; a later migration is harder than the constraint would have been.
when The invariant needs infrastructure you should not build — card handling, sign-in, durable file storage.
cost A dependency that can fail, a contract to learn, and the boundary between their guarantee and yours to get right.
when The capability is not on the V1 path and the invariant only exists because of it — accounts, refunds, editing orders.
cost A visible gap that stakeholders will notice, and a trigger to write down.
when None of the above can express it — a business rule about which orders a warehouse may see.
cost The one option that needs tests you write, and the one most likely to be "simplified" by the next person.
How to do it
Most important first.
- Walk the V1 path and, at each step, ask what would happen if this step were wrong once for one user. If the answer involves a refund, an apology about their data, or a breach, the step is untouchable.
- For each untouchable, write the invariant in one sentence and pick the mechanism: database constraint, transaction, provider, or exclusion (Finding Invariants From Examples).
- For everything else, write the simplification and the trigger for undoing it — the same three sentences as What Is Not V1.
- Prefer exclusion over roughness. If identity cannot be done properly this week, guest checkout with an emailed order link has no accounts to leak.
- Look for the quiet ones: number types for money, missing unique constraints, no backup, no idempotency on anything that charges or sends. None of these will complain in development.
Worked on a concrete problem
The move has to produce something. This is what it produced.
- The store, sorted. Simplifiable: shipping (fixed fee), tax (single rate, or none in a market without it), search (filter by name), catalog images (a URL field, no upload), admin (a database client, no screen). Untouchable: the order total and what was charged (money), whether an order exists after a paid checkout (irrecoverable data), stock never below zero (money, in the end, because oversold units are refunds), who can see which orders (identity).
- Identity handled by exclusion: V1 has guest checkout only. No password table, no reset flow, no session hijacking to worry about. The order confirmation is a link with an unguessable token, emailed. Accounts arrive when the trigger fires — customers asking to see past orders — and arrive via a managed provider.
- The file-upload service. Simplifiable: file-type restrictions (a short allowlist), thumbnails (none), quotas (one hard limit). Untouchable: the file, once the upload has been acknowledged, exists and can be retrieved — which means the acknowledgement is sent after durable storage confirms, not before, and never from memory.
How you know it worked
What now exists that did not before, and what question you can now ask.
- Every part of V1 is labelled simplified, done properly, delegated, or excluded — and nothing is labelled "rough".
- The untouchables are a short list, each with an invariant and a mechanism, and each has a test.
- Someone proposes a simplification and the answer comes from the rule, not from who is in the room.
- The quiet dangers — money as floats, missing constraints, no backup — were found by looking, not by an incident.
The questions you can now ask
The field this whole domain exists for. After this lesson, these are the questions to put to an unfamiliar problem.
- ?Can this part be smaller and still true, or only smaller and wrong?
- ?Is this money, identity, or data that cannot be regenerated — and if so, what is the invariant and what mechanism keeps it?
- ?Can I exclude this capability entirely instead of doing it roughly?
- ?Which simplifications in this design would never complain in development, and have I gone looking for them?
What can go wrong
- Everything is untouchable. The list grows until the MVP is the full product built carefully, which is a fine product and a failed MVP. The rule is *smaller and wrong*, and most parts can be smaller and true.
- Untouchables are protected in the code and not in the data. A careful total function over a
price FLOATcolumn protects nothing; the mechanism has to be where the truth lives (Source of Truth). - Delegation without understanding: the provider handles the card, so money is "done", and nobody asks how the backend learns the outcome or what happens if the callback arrives twice.
- Doing the untouchables properly is the slowest part of a fast V1, and it is invisible in the demo.
- Exclusion trades a hard problem now for a missing capability that a stakeholder can see, and they will ask about it.
- Delegation trades code for a provider dependency, a contract to understand and a failure mode you do not control.
- "Untouchable means gold-plated." It means true. An integer column and a check constraint are not gold-plating; they are the cheapest way to be right.
- "Guest checkout is a hack." It is an exclusion that removes an entire class of invariants from V1. That is the move working, not a workaround.
- "The provider handles money." The provider handles the charge. What was charged, for which order, learned from whom, and never twice — that is still yours.
Where this applies
Problem-solving advice is stated as universal far more often than it is. These labels say what each method is specific to — and where CONTESTED appears, the note gives the strongest form of the opposing view.
- GENERALMoney, identity and irrecoverable data are the untouchables in almost any system; the move is to ask "smaller and still true?" of everything else.
- DOMAIN-SPECIFICA store's untouchables are money, stock, orders and who sees what. A chat app adds "a sent message is delivered or the sender knows it was not". An analytics dashboard over data that can be recomputed may have no untouchables at all in V1, and can be as rough as it likes.
- ILLUSTRATIVEThe store and the file-upload service are invented; quantities are for the shape of the argument.
Where the depth lives
This domain asks the question and hands the answer off by name.