الدرس 3 من 4
Deciding Under Uncertainty
You will never have enough information. Reversibility, the last responsible moment, and keeping options open are how you decide anyway.
Every architectural decision is made with less information than you would like, about a future you cannot see, for requirements that will change. Waiting for certainty is not caution — it is a decision to let circumstances decide for you, and circumstances have no stake in the outcome.
Sort by reversibility first
The reversibility test from the first lesson is not only a definition — it is a routing rule. It tells you how much analysis a decision deserves, which is the difference between an organisation that moves and one that deliberates.
| Reversibility | How to decide | Example |
|---|---|---|
| Cheap to reverse | Decide fast, alone, and move. Being wrong costs a day. | Internal module layout, a logging library |
| Moderate | Decide with the team, write a short note, set a review date. | Internal API shape, caching strategy |
| Expensive to reverse | Full trade-off analysis, ADR, and a named trigger for revisiting. | Service boundaries, tenancy model, public contracts |
| Effectively permanent | Defer to the last responsible moment; buy information first with a spike or a pilot. | Money representation, primary datastore, identity provider |
Buying information instead of guessing
- 1Run a timeboxed spike against the specific uncertainty. Not "evaluate Kafka" — "can our message volume sustain 40k/sec on three brokers with our message size, in four days of work?". A spike without a question is a holiday.
- 2Ship a thin slice to real users. The most reliable information about whether a design holds comes from production traffic, and it arrives faster than any analysis.
- 3Find someone who has already done it. Thirty minutes with an engineer who ran the thing you are considering, at your scale, is worth a week of reading vendor material.
- 4Instrument what you already have. Most uncertainty about future load is answerable from current data that nobody has looked at.
Keeping options open costs something too
The standard advice is to preserve optionality — abstract the database, hide the provider, keep everything swappable. This is good advice with a limit. Every option you keep open is an abstraction someone maintains, an indirection someone traces through, and a decision someone still has to make later. Optionality is insurance, and insurance has a premium.
When to buy the option and when to commit
Keep the option open
Abstract behind an interface so the choice can change later.
- Cheap reversal if the decision proves wrong
- The domain becomes testable without the dependency
- Forces you to articulate what you actually need from it
- An abstraction to maintain and explain forever
- Often constrains you to the lowest common denominator of the things it abstracts
- The decision is deferred, not removed — someone still makes it later
Choose when: The dependency is genuinely likely to change, or the abstraction pays for itself in testability regardless — payment providers, notification channels, storage backends.
Commit fully
Use the chosen technology directly and depend on its specific strengths.
- Full access to what makes that technology worth choosing
- Less code, fewer layers, faster to read and to change
- No pretence that a swap is easy when it never would be
- Reversal is expensive and touches many call sites
- Testing may require the real dependency
Choose when: The choice is effectively permanent anyway. Abstracting PostgreSQL behind a generic repository to keep the option of switching databases mostly means giving up PostgreSQL's best features to preserve a swap nobody will ever perform.
Facing a decision with genuinely insufficient information
As a developer
Ask for the requirement to be clarified, and wait. This is correct and responsible at the feature level — someone knows the answer, and guessing wastes work.
As an architect
Recognise that for many architectural questions nobody knows the answer, and no amount of asking will produce one. Decide anyway: choose the option that fails least badly across the plausible futures, write down the assumption you are betting on, and name the observation that would prove it wrong. Then design so that observation arrives early and cheaply.
In practice
Deferring one decision, committing to another
A team building a marketplace had two open questions: which search technology to use, and how to represent money. Both were flagged as significant, and there was pressure to settle both before development started.
Constraints
- No production traffic yet, so no data on query patterns
- Multi-currency from launch, including JPY
- Six-month runway
- Four engineers
Decision
Commit immediately and fully on money representation — integer minor units plus a currency code, no floats anywhere. Defer search entirely: launch with PostgreSQL full-text behind a narrow `SearchIndex` port, and revisit once there were three months of real query logs.
Why
The two decisions have opposite reversibility profiles. Money representation touches every table, every API contract and every historical row — reversing it later means a migration and a reconciliation exercise, and no amount of waiting produces better information because the right answer is already known. Search is the opposite: the right choice depends entirely on query patterns that do not exist yet, and it sits behind one interface with a handful of call sites.
What it cost
PostgreSQL full-text search was noticeably worse than a dedicated engine for the first eight months, and the team took some criticism for it. When they did migrate, the query logs showed their real need was faceted filtering rather than relevance ranking — which would have pointed them at a different technology than the one they would have picked on day one. Committing early on money cost them nothing and saved a migration; deferring on search cost eight months of mediocre search and saved them from building the wrong thing well.
How do you tell the last responsible moment from procrastination?RevealHide
Ask what specific information you are waiting for, and when it will arrive. If you can name it — "three months of query logs", "the outcome of the compliance review on the 14th" — you are deferring responsibly, and you should also write down that trigger so the decision actually gets made when it arrives. If you cannot name it, or the information will never arrive, you are procrastinating and the cost is that your options are quietly narrowing while you wait.
Key takeaways
- Waiting for certainty is a decision to let circumstances decide instead of you.
- Route decisions by reversibility: cheap ones fast and alone, permanent ones deferred and analysed.
- Buy information with targeted spikes, thin production slices, and people who have done it — not with more discussion.
- Optionality is insurance with a real premium; abstracting something you will never swap costs more than it saves.
- Deferring responsibly means naming the information you are waiting for and when it arrives.