Trade-offsGENERALSIMPLIFIEDILLUSTRATIVE

Trade-Off Dimensions

Simplicity, performance, reliability, cost, security, time, maintainability — each is a question you can ask of a design, with an observation that would answer it. The move is turning the axis names into questions for your system, and noticing which questions this decision does not change.

The moveWorked exampleNext questions

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.

The question

The seven trade-off axes are just words until they are questions about your system — what does each one actually ask, and how do you tell which ones a given decision moves?

The situation

You have learned to say "it is a trade-off" and it has stopped helping. Asked to choose between computing order totals on the fly and storing them on the order, you can list the seven axes and you cannot say what any of them means for this decision. "Performance" — of what? "Maintainability" — measured how?

The reflex

Score everything. Draw a table with the seven axes and both options, fill in a number for each cell from feel, add the columns, and pick the higher total. It looks rigorous and it produces an answer.

Why it stalls

The cells are filled from vibes because no axis was ever turned into a question. "Performance: 3" means nothing when nobody said which request, under what load, measured how.

What the reflex produces — and fails to produce
  • The cells are filled from vibes because no axis was ever turned into a question. "Performance: 3" means nothing when nobody said which request, under what load, measured how.
  • Every axis gets a score, including the ones the decision does not move — and equal-weight totals let the irrelevant axes decide. The stored total "wins" on security because someone gave it a 4 for no reason either option can be distinguished on.
  • The number hides the argument that mattered. The real question — "can a stored total go stale when a price changes?" — is one cell in a grid of fourteen, weighted the same as "cost", which does not move at all.
  • The table is presented as the decision, so when the requirement changes nobody knows which cell to update, and the table is thrown away and redrawn from feel again.
ProblemUnderstandRequirementsConstraintsUnknownsDecompositionSmallest StepModelExperimentObserveDebugLearnIterate

The move

Precisely enough to apply it to a problem you have never seen — not a slogan.

  • Turn each axis into a question about *this* system and this decision, with an observation that would answer it. Simplicity: how many parts, and how many of them does someone have to understand to change this? Performance: which request or job gets faster or slower, under which load, and by how much would anyone notice? Reliability: what fails, how often, and what does the customer see when it does? Cost: what is paid for, and does it scale with users or with time? Security: what new thing can now be attacked or trusted wrongly? Time: how long until this is in a customer's hands? Maintainability: what will the next change to this area have to touch, and will it be obvious?
  • Ask each question of both options. Where the answers are the same, the axis is not moved by this decision — cross it out. Where they differ, write the difference as a sentence, not a number: "a stored total can disagree with the item prices after a price change; a computed total cannot, but changes retroactively when a price does."
  • Only the axes that remain, and the requirements that weight them, enter the comparison. Most decisions move two or three axes; a decision that moves all seven is probably several decisions.
  • Attach an observation to each surviving axis so the trade can be checked later, not just believed: a query timing, a count of places that compute totals, a failure the test suite can inject.

Each axis, as a question and an observation

The table is the move in one place: the axis, the question it asks in the nouns of a system, and the kind of observation that would answer it. The third column is the difference between an axis and a vibe.

Read the middle column as a template with blanks — "which request", "what fails" — and refuse to score an axis until the blanks are filled with something from your system.

AxisThe question, with blanks to fillThe observation that answers it
SimplicityHow many parts, and how many must someone understand to change this?A count of components, tables and places the logic lives
PerformanceWhich request or job gets faster or slower, under which load, and would anyone notice?A timing of that request at the load you actually have
ReliabilityWhat fails, how often, and what does the customer see?An injected failure and the observed result
CostWhat is paid for, and does it grow with users, data or time?A bill line and the variable it scales with
SecurityWhat new thing can be attacked, or trusted wrongly?A new input, boundary or credential that did not exist before
TimeHow long until a customer can use it?The first slice that reaches a customer, and what it needs
MaintainabilityWhat will the next change here have to touch, and will it be obvious?The set of files or tables a plausible next change edits

A decision, decomposed into its axes

The order-total decision as a tree. Each leaf is an axis turned into a testable observation on the store; the crossed-out axes are present as branches whose leaf says why they do not distinguish the options. A tree whose every leaf is testable is what a filled-in table should have been.

Order total: computed or stored?
Should an order's total be computed from items and current prices, or stored at checkout?
  • Reliabilitythe axis with a requirement behind it
    • Total unchanged after a price changetestable Change a product price after checkout; the order's total, invoice and refund amount are unchanged. Computed fails this; stored passes.
    • Stored total agrees with itemstestable For every order, the stored total equals the sum of its stored item prices times quantities — checkable as a constraint or a nightly query.
  • Maintainabilityrefunds, invoices and reports all ask "what was paid"
    • One place answers "what was paid"testable A count of code paths that compute an order total; the target is one, and the refund and invoice code read it rather than re-deriving.
  • Simplicity and performancemoved slightly, in the other direction
    • One extra column and writetestable The checkout code path writes the total once; the order page reads one column instead of running a join — a timing shows no customer-visible difference either way.
  • Cost, security, timenot moved
    • Same answer for both optionstestable No new bill line, no new trusted input, and the first customer-visible slice is the same size — so these axes are crossed out with a reason rather than scored.

The decision lives in the first branch: an order is a record of what happened. The other branches confirm it is cheap, not that it is right.

Which axes to weight, when

The axes are weighted by requirements, and requirements differ by what is being built. The decision below is not a rule; it is the question "which axis wins a tie here?" asked of the cases this domain uses, with the cost of each answer.

Which axis breaks a tie?

When two surviving axes point in opposite directions, which one does this kind of system let win?

Reliability and security first (payments, orders, anything about money)

when The system records facts that must not change or be forged after the fact — an order, a payment, a balance.

cost Simplicity and time lose ties, and the system is slower to build and to change; a stored total, a webhook signature check and an idempotency key all cost code that an internal tool would skip.

Time and simplicity first (an internal dashboard, a prototype answering a question)

when The output is looked at by people who can tell when it is wrong, and being wrong for an hour costs little.

cost Reliability debt is real and arrives when the dashboard becomes the thing a decision is made on; the trade has to be revisited when the audience changes.

Performance first (search, the product page, anything a customer waits on)

when A measured wait is on the path to a purchase, and the measurement exists.

cost Simplicity and maintainability pay: a cache, a denormalised column, a second store — each a component with a complexity-ledger entry (The Complexity Ledger).

Maintainability first (the core model everyone touches)

when The next change is more certain than the current requirement — the order and product models of a store that will exist for years.

cost Time pays now for changes that may not come; the risk is design for a future that does not arrive (Essential vs Accidental Complexity).

How to do it

Most important first.

  • Write the seven questions out for your decision before writing any option. If a question has no meaningful form for this decision — "security" for a variable name — cross it out immediately.
  • Answer each question for each option in one sentence with a noun from your system in it. A sentence without a component, a request or a table is a vibe.
  • Cross out every axis where both sentences say the same thing (What Can I Ignore for Now?).
  • For each surviving axis, name the observation that would show the answer was right: a measurement, a count, an injected failure (Invariants as Tests).
  • Weight the survivors by requirement, not by gut. The requirement has a source; write it beside the axis.

Worked on a concrete problem

The move has to produce something. This is what it produced.

  • Order totals: computed on the fly from items and current prices, or stored on the order at checkout. Simplicity: computed has fewer moving parts (no column to keep right); stored has one more column and one more write. Performance: computed re-runs a small join on every order view — nobody would notice at store scale. Reliability: stored can disagree with the items if written wrongly, once; computed changes its answer whenever a price changes, which for a historical order is a wrong answer every time. Cost: unchanged. Security: unchanged. Time: nearly the same. Maintainability: refunds, invoices and reports all need "what did the customer pay", and computed makes every one of them re-derive it from prices that may have moved.
  • Crossed out: cost, security, time. Surviving: simplicity (computed, slightly), performance (computed pays a little, nobody notices), reliability and maintainability (stored, decisively, because "what the customer paid" must not change after the fact — an invariant with a source in the refunds requirement). The decision is stored, and the reason is one sentence: an order is a record of what happened, not a view over current prices (Snapshots vs References).
  • Observations attached: a test that changes a product price after checkout and asserts the order total is unchanged; a count of places that compute totals (must be one); a query timing on the order page that would flag if the stored column were ever replaced by a join.

How you know it worked

What now exists that did not before, and what question you can now ask.

  • Each axis is a sentence about your system, with a noun in it, for each option.
  • At least three of the seven are crossed out, and you can say why the decision does not move them.
  • The surviving axes each have an observation — a test, a timing, a count — that could later show the trade was wrong.
  • The decision is a sentence naming the requirement that weighted the surviving axes, not a column total.

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.

Next questions
  • ?For each axis — what is the question, in the nouns of my system, and what is the answer for each option?
  • ?Which axes give the same answer for every option, and can I cross them out?
  • ?What observation would show, later, that the trade on each surviving axis was right?
  • ?Which requirement, with which source, weights the surviving axes?

What can go wrong

How the move itself fails
  • Turning axes into questions and then not answering them for your system — the questions are recited generically and the cells filled from feel anyway.
  • Never crossing anything out, because every axis "matters a bit". The move exists to find the axes that matter *here*; a decision on which all seven survive has not been asked precisely enough.
  • Observations promised and never attached. The trade is believed rather than checked, and when a stored total does go stale nobody has the test that would have caught it.
  • Confusing an axis with a requirement. "Performance" is an axis; "the order page loads without a noticeable wait" is a requirement; the axis without a requirement cannot be weighted, only admired.
What the move costs
  • Seven questions per decision is slower than one table filled from feel, and on a decision that is easy to reverse the table-from-feel plus a note is the right trade.
  • Crossing out an axis is a bet that the decision does not move it; the bet is occasionally wrong and the crossed-out axis is exactly where nobody is looking.
  • Attached observations are tests and timings someone has to write and keep; a decision with four observations attached has bought accountability at the price of upkeep.
Misreads
  • "The seven axes are the complete list." They are the usual list. Auditability, portability, learnability for a new hire, and time-to-first-release all show up as axes in real decisions; the move is the same for an eighth.
  • "Crossing out an axis means it is unimportant." It means this decision does not move it. Security is never unimportant in a store; it is simply the same for both total designs, so it cannot decide between them.
  • "Once the axes are questions, the decision is mechanical." The questions produce sentences; the requirements weight them; and the requirements come from people. The move makes the human choice legible, not absent.

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.

  • GENERALTurning axes into system-specific questions with observations applies to any design decision; the questions change their nouns — a request, a tensor, a cache line — and keep their shape.
  • SIMPLIFIEDSeven axes with one question each is a teaching model; real decisions have axes that interact (a simpler design is often more reliable because there is less to fail) and the sentences for each option are not independent. Treat the list as a way to find the axes that matter, not as orthogonal dimensions.
  • ILLUSTRATIVEThe order-total decision and its answers are invented for the shape of the argument; a store with real-time price negotiation or a subscription model would answer the reliability question differently.

Where the depth lives

This domain asks the question and hands the answer off by name.

Observability & Performancemeasure-before-optimizing
Further
  • The Testing & Reliability domain does not exist yet; the "observation that answers it" column is where its lessons would attach — an injected failure, a property test on the stored total.