Ch 1 / 24 The Tradeoffs You Are Already Making 0/0 exercises Exercises ↓

AmouAI Hub/Courses/Software Engineering for AI Engineers/Chapter 1

Part 1 · Building Full-Stack Applications · Chapter 1

The Tradeoffs You Are Already Making

A coding agent will produce a working implementation of almost anything you describe. What it will not do is tell you that the implementation just traded away your ability to add a second region, or that it chose consistency over availability on a screen where nobody would have noticed either way. Those decisions got made. The only question is whether you made them.

Reading
Ng, Software engineering fundamentals
Focus
Naming what a design sold
Instruments
Tradeoff board · spec diff
Exercises
12 · JavaScript + design

By the end of this chapter you can

  1. Name the seven properties every system design trades between, and give an example of each in conflict
  2. Read a product requirement as a ranking of those properties rather than a list of features
  3. State what a technical decision cost, not only what it bought
  4. Compute the availability of a system from its parts, in series and in parallel
  5. Recognise the defaults a coding agent applies when your prompt is silent
  6. Write a constraint ranking short enough that a colleague, or an agent, will actually read it

1Seven properties, one system

Andrew Ng lists them almost in passing: latency, availability, consistency, reliability, maintainability, simplicity and cost. They are not a checklist. They are seven forces pulling in different directions, and every line of infrastructure you add moves several of them at once.

Here is the uncomfortable part. None of these properties is a thing you can simply have more of. Each one is bought with something else, and usually the currency is one of the other six.

PropertyWhat it means concretelyWhat it is usually bought with
LatencyHow long one operation takes, measured at p95 or p99 rather than the meanCost (more caches, more regions) and consistency (serving a copy that may be stale)
AvailabilityThe share of requests that get an answer at allCost (redundancy) and consistency (accepting writes you cannot immediately reconcile)
ConsistencyWhether every reader sees the same value at the same momentLatency (coordination takes round trips) and availability (refusing to answer beats answering wrongly)
ReliabilityWhether the system does the right thing under failure, not just under loadSimplicity (retries, breakers, fallbacks are all extra machinery) and cost
MaintainabilityHow cheaply the next person can change it correctlyLatency and cost (abstraction layers are not free) and sometimes raw performance
SimplicityHow much of the system fits in one person’s headAlmost everything else, which is why it is the first thing quietly spent
CostMoney per month, and engineer-hours per month, which is the larger numberAll six of the above, in both directions
The idea to keep

A design decision is never “better”. It is better on some axes and worse on others. An engineer who can only say what a choice improves has not finished thinking about it. The sentence you are learning to finish in this course is: this buys us X, and it costs us Y, and Y is acceptable because of Z.

The instrument below is the course in miniature. Five ordinary decisions, seven meters. Move anything and watch what else moves. There is no configuration where all seven read green, and looking for one is the specific mistake this chapter exists to prevent.

Notice what happens when you pick the strongest option in every row. Reliability and availability go up, and simplicity collapses. You have built something that survives almost anything, that nobody on a four-person team can hold in their head, and that costs more than the revenue of the catalogue it serves. That configuration is not wrong in the abstract. It is wrong for this scenario, and knowing which is the skill.

2What the agent optimises when you do not say

A coding agent is not neutral. Asked for a feature with no constraints attached, it produces the shape that dominates its training data: the tutorial shape. That shape has a consistent bias, and once you can name the bias you can correct for it in one sentence of prompt.

The tutorial shape optimises for plausibility on first read. It is simple, synchronous, unpaginated, unversioned, single-region, and it assumes the happy path. That is genuinely the right default for a prototype, which is why it is so hard to notice when it is wrong. It becomes wrong the moment the thing goes in front of users, and by then it is load-bearing.

The specific mistake

Reviewing generated code by reading it top to bottom and asking “does this look right?”. It always looks right; that is what the model is good at. The review that finds things asks a different question: what decision does each line encode, and did anyone decide it? An unpaginated list is not a missing feature, it is an availability decision made silently.

This is what Ng means when he writes that a novice who vibe codes “did not know such tradeoffs even existed and therefore did not steer the agent”. The failure is not that the agent chose badly. The agent chose the way a reasonable stranger would choose with no information. The failure is that nobody supplied the information.

3A requirement is a ranking, not a list

Product requirements arrive as features. Architectures are decided by the properties nobody wrote down. The translation between the two is a skill, and it is mostly a matter of asking three questions of every requirement.

Take a real sentence: “Users should be able to see their order history.” As written, this constrains nothing. Now ask:

  1. What is the cost of being slow? A shopper waiting three seconds on an order history page is irritated. A trader waiting three seconds on a position page has lost money. Same feature, two orders of magnitude between the latency budgets.
  2. What is the cost of being wrong? Showing an order that was cancelled two seconds ago is a support ticket. Showing a bank balance that is two seconds stale is a regulatory problem. This question is the one that decides your consistency model, and almost nobody asks it explicitly.
  3. What is the cost of being down? If the page is unavailable for ten minutes on a Tuesday, does anyone lose anything? For a lot of internal tooling the honest answer is no, and that answer should save you a five-figure infrastructure bill.

The answers give you a ranking. The ranking gives you an architecture. Skipping to the architecture is how teams end up running multi-region active-active for an admin dashboard used by eleven people.

A prompt you can steal

Before asking an agent to build anything non-trivial, give it the ranking: “Constraints in priority order: (1) … (2) … (3) …. The following are explicitly not constraints: …”. The second half matters as much as the first. Telling an agent that cost does not matter at this scale stops it inventing an optimisation you will have to maintain.

4The arithmetic of availability

Availability is the one property in the list with real arithmetic behind it, and the arithmetic is unintuitive enough that people get it wrong in both directions. Ten minutes here will save you from two expensive mistakes.

An availability figure is a probability: the share of requests that get a successful answer over some window. Write 99.9% as 0.999 and the arithmetic works out like this.

Components in series multiply. If your request must pass through a load balancer, an application server and a database, and each is independently available 99.9% of the time, the path is available 0.999 × 0.999 × 0.999 = 99.7% of the time. You did not build a 99.9% system. You built a 99.7% system out of 99.9% parts, and you tripled your downtime budget without adding a single feature.

series.js
// three dependencies, each "three nines"
const path = [0.999, 0.999, 0.999];
const available = path.reduce((a, b) => a * b, 1);
console.log(available);            // 0.997002999 -> 99.70%
console.log((1 - available) * 43200);  // 129 minutes down per 30-day month

Redundant components in parallel add nines. Two instances of a 99% service, where either one can serve the request, fail only when both fail: 1 − (0.01 × 0.01) = 99.99%. This is why redundancy is such a powerful lever, and also why it is oversold — the arithmetic assumes the failures are independent. Two instances in the same rack, on the same deploy, running the same bug are not independent at all, and the formula quietly becomes a lie.

Where the formula breaks

Independence is an assumption, not a property. Correlated failure is the normal case: a bad deploy hits every replica, a certificate expires everywhere at once, a poison message crashes every consumer in the pool. When you claim four nines from redundancy, the honest question is what single event takes out both copies — and there is almost always one.

The last piece of arithmetic is the one that governs behaviour rather than design. Convert the target into a downtime budget and it stops being an abstraction.

TargetDown per monthDown per yearWhat that buys in practice
99%7h 18m3.65 daysAn internal tool. One person can restart it in the morning.
99.9%43m8h 46mA normal web product. Single region, good pipeline, someone on call.
99.95%21m4h 23mAutomated failover is now mandatory; a human cannot respond fast enough.
99.99%4m 19s52mMulti-region, no manual steps in recovery, and a real on-call rota.
99.999%26s5m 15sRarely justified outside infrastructure. A single bad deploy exceeds the annual budget.

Read the bottom row again. Five nines allows five minutes of unavailability per year. One botched release spends the whole budget. If your product does not require that, asking for it is not ambition; it is an expensive way to make every future deploy frightening.

5One feature, three products

The clearest way to feel that there is no universal right answer is to build the same thing three times under three different rankings. Here is one feature — a counter of how many people are currently viewing an item — in three products.

A news site

Ranking: latency, then cost, then everything else. Nobody is harmed by a wrong number.

Design: increment a counter in a shared cache, read it from the edge, refresh every 30 seconds. No database involvement at all. If the cache is lost, the number resets and nothing bad happens.

A ticketing site

Ranking: consistency, then availability, then latency. The number drives a scarcity message that has legal consequences if it is false.

Design: a real count against a transactional store, with the reservation and the count in one transaction. Slower, more expensive, and correct — because “only 2 left!” when there are 40 is a regulator’s problem, not an engineer’s.

An internal dashboard

Ranking: simplicity, then cost. Eleven users, all colleagues.

Design: a COUNT(*) against the database on every page load. It is the wrong answer at scale and exactly the right answer here, because the alternative costs a week of somebody’s life to save 40ms for eleven people.

Three defensible designs, three rankings, one feature. An engineer who has memorised “use a cache for counters” gets the ticketing site wrong. An engineer who has memorised “always be correct” gets the news site wrong and the dashboard very wrong.

6Writing the ranking down

Everything above collapses into one short artefact. It goes at the top of the design document, in the pull request description, and in the prompt. It is four to six lines long, and if it is longer than that nobody will read it, including the agent.

The shape that works:

constraints.md
# Order history page

Ranked constraints
1. A customer must never see another customer's data.        (non-negotiable)
2. Refund status must be current within 5s.                   (regulatory)
3. p95 under 400ms for the shopper path.                      (measured, not felt)
4. Correct under concurrent inserts.                          (no skipped rows)

Explicitly not constraints
- Availability beyond 99.9%. Down is a support cost, not a revenue loss.
- Cost at current scale. Under $200/month either way.
- The admin view's latency. Staff will wait.

Three properties of this document make it work. It is ranked, so conflicts have an answer. It has numbers, so “fast” cannot drift. And it says what is not a constraint, which is the half that stops both humans and agents from gold-plating.

The idea to keep

You are not being asked to predict the future. You are being asked to make the decisions visible, so that when the situation changes — and it will — somebody can find the sentence that is no longer true and change it deliberately. An architecture without a written ranking cannot be revised; it can only be rewritten.

The playground below is the exercise you will repeat in most chapters of this course: a scenario, its stated constraints, and a set of decisions that have to answer to them. Nothing scores you. The board only reflects your own ranking back at you, which turns out to be enough.

Tonight

Take something you have built or are building and write its constraints.md. Four ranked lines, three non-constraints, numbers where you can. Then read the code and find one place where it contradicts the document. There is always one, and it is the most useful thing you will learn about that system this week.

Checkpoint

Five questions. Answer before you scroll — the explanation is worth more when you have committed to something.

Playground

A real brief with a real ranking. Configure it, then open the defensible answer and see where you differ — and, more importantly, whether your reason was better than the one written down.

Exercise set

Twelve problems. The JavaScript ones run in a sandboxed frame and are checked against what your code actually does, so there is usually more than one right answer. The design ones are graded against the scenario’s stated constraints, and they require a written justification — naming the tradeoff out loud is the skill being assessed. Your work is saved in this browser.

All Warm-up Core Challenge Reset chapter

Chapter 2 — The Request Path, End to End

Every performance argument you will ever have is really an argument about which hop owns the milliseconds. Next chapter you draw the path and attribute the time.

Continue →