Write down the bet
When requirements are unclear, I record the assumption, the consequence of being wrong, and the signal that would change the decision. That turns a vague disagreement into something the team can revisit.
Prefer reversible moves
A thin adapter, a feature flag, or a small migration can buy information without committing the whole system. Irreversible choices deserve more design time because they reduce future options.
Make trade-offs legible
Every design optimizes something: speed of delivery, operating cost, correctness, flexibility, or user experience. Naming the priority prevents a technical preference from masquerading as an objective truth.
The goal is not to predict perfectly. It is to learn quickly without creating avoidable damage.
Turn uncertainty into a decision record
For a consequential choice, I write the decision, the context, the options rejected, the assumptions, and the signal that would cause a revisit. This is short enough to maintain and specific enough to prevent the team from repeating the same debate without new information.
flowchart TD
A[Unclear problem] --> B[State assumptions]
B --> C[Compare reversible options]
C --> D[Choose and record trade-offs]
D --> E[Ship a measurable slice]
E --> F[Review evidence]
F -->|Assumption still valid| G[Continue]
F -->|Assumption changed| A
Rank reversibility
Changing a component library is usually easier than changing a data model that has already been exported to customers. A feature flag, adapter, shadow read, or dual-write period can buy evidence before an irreversible migration.
type Decision = {
choice: string;
assumptions: string[];
reversibleUntil: string;
revisitWhen: string[];
};
Make trade-offs legible
Every design optimizes something: speed of delivery, operating cost, correctness, flexibility, or user experience. Naming the priority prevents a technical preference from masquerading as an objective truth. The team can disagree productively when it is debating the trade-off rather than guessing each other's motives.
