A16 · Part 3 · Advanced
Tradeoff thinking
Nobody is grading your architecture. They are grading whether you knew what you were giving up, and said so.
07On this page
- The thing that is actually being scored
- The six axes, and the sentence for each
- The four-beat move that makes a decision defensible
- "It depends" is only half a sentence
- Over-engineering is the most common senior-level failure
- How to disagree with your interviewer well
- What separates a senior/staff performance from a mid-level one
The thing that is actually being scored
The earlier chapters of this topic have been about mechanisms. This one is about the only skill that is graded directly. Interviewers at this level are not comparing your diagram against a reference answer — for most prompts there isn't one, and the interviewer has seen a dozen different designs pass. What they are assessing is narrower and more human: can this person make a decision under incomplete information, explain the cost, and change their mind for a reason rather than for social pressure? That is the job. The system design interview is a forty-five-minute simulation of a design review you will be running for the rest of your career.
Which is why two candidates can draw an almost identical diagram and receive opposite ratings. One says "and then we add Kafka." The other says "I'll add a queue here because the write path is 600k/sec at peak and the consumer can fall behind without hurting the user — the cost is that the feed is now eventually consistent by a few seconds, and I'd revisit if product tells me the write must be read-your-own-write." Same box on the whiteboard. Entirely different signal.
The six axes, and the sentence for each
Almost every decision in system design is one of six tradeoffs wearing a costume. Learning to name the axis out loud is most of the skill — it converts a technology choice into a reasoned position, and it lets the interviewer engage with the reasoning instead of the brand name.
| Axis | Buying more of this… | …costs you this | The sentence |
|---|---|---|---|
| Consistency vs availability | Every reader sees the latest write | During a partition, the side that cannot reach a quorum must fail or block some operations (writes, and often reads too); even with no partition, higher latency (the PACELC refinement of CAP) | "During a partition I'd rather reject the withdrawal than approve it against a possibly stale balance — this is a money path." |
| Latency vs throughput | Fast individual responses | Less batching, less pipelining, worse hardware utilisation, higher cost per request | "If batching to 50 ms windows triples throughput, it also adds 50 ms of latency — for an analytics write path that's free, for a chat send it isn't." (The tripling is an illustrative figure.) |
| Cost vs performance | Headroom, replicas, more cache, more regions | Money, linearly, forever — plus the opportunity cost of the team maintaining it | "A second region roughly doubles infrastructure spend and helps only against regional failures; a single region across availability zones is already, as a rough planning figure and not a guarantee, 99.95-99.99%, and many outages are deploys and config changes that a second region does not fix. Is that worth it for this product?" |
| Complexity vs capability | A feature the simple design can't do | A new failure mode, a new backup story, a new upgrade path, a new page at 3am | "That's a fourth stateful system. Each one is an on-call runbook — I'd want the capability to be worth that." |
| Read-optimised vs write-optimised | Cheap reads: denormalisation, materialised views, fan-out on write, more indexes | Expensive, amplified writes; stale derived data; harder invalidation | "Read:write here is 100:1, so I'll pay on write. If it were 1:1 I'd compute at read time instead." |
| Build vs buy | Control, exact fit, no per-GB bill | Team time forever, and you are now the on-call for a commodity | "I'd buy the CDN and the queue and build the matching engine — that's the only part that's our differentiator." |
A seventh worth keeping in your pocket: flexibility vs optimisation. Every performance win — denormalisation, a chosen shard key, a precomputed index, a cached projection — is a bet on a specific access pattern. If the product pivots, the optimisation becomes the migration. Saying "this shard key assumes we always query by user, and if we later need query-by-region that's a full reshard" is the kind of foresight that reads as staff-level.
Two more pieces of vocabulary make the price tag concrete. Reliability has a currency: the SLO and its error budget. A 99.9% monthly target leaves about 43 minutes of allowed unavailability; a risky launch, a migration or a deploy freeze is a decision about how that budget gets spent, and each extra nine costs more than the last, so the question is whether the revenue it protects justifies it. And price decisions by reversibility: a feature flag, a cache or an index is cheap to be wrong about, while a shard key, a public API field or a choice of primary datastore is a one-way door that deserves the arithmetic. Include how you would roll the change back, and how you would find out within minutes that it was wrong.
The four-beat move that makes a decision defensible
There is a repeatable structure for any decision you announce, and it takes about fifteen seconds. Assumption, choice, cost, trigger. Beats one and two are what most candidates give. Beats three and four are the entire difference in rating.
Say it like this → "Assuming 100:1 reads to writes
and that a two-second delay on the feed is acceptable, I'd fan out on write
into a per-user timeline cache. That costs me write amplification — a
million-follower account generates a million inserts — and it costs me
strict ordering across sources. I'd switch to read-time merge if the
follower distribution turned out to be flatter than I'm assuming, or if
product needs the feed strictly consistent."
Notice the shape: one assumption, one choice, two costs, two triggers. It is four sentences and it is unfalsifiable in the good way — the interviewer can now attack the assumption ("what if it's 10:1?") which is exactly the conversation you want, because you have already told them what you'd do.
"It depends" is only half a sentence
"It depends" is true of every question in this interview, which is precisely why saying it alone scores zero. It is not wrong, it is empty — it transfers the work back to the interviewer. The fix is mechanical: the phrase must always be completed with on what, and then with what you would do in each branch.
| Empty | Complete |
|---|---|
| "It depends on the use case." | "It depends on whether users read their own writes. If they do, I'll route reads to the primary for that user for a few seconds after a write. If they don't, replicas are fine and I save the primary's capacity." |
| "SQL or NoSQL, it depends." | "It depends on whether the access pattern is known and stable. It is — everything is a lookup by conversation id — so I'll take a wide-column store and give up ad-hoc queries. If analysts need ad-hoc access I'd ship a copy to a warehouse rather than compromise the serving store." |
| "Depends how much scale we need." | "At 100 writes/sec one Postgres primary handles this with an order of magnitude of headroom. I'd revisit above about 5,000 writes/sec, which at current growth is roughly three years out." |
The same discipline applies to any comparative you use. "Faster" — than what, by how much? "More scalable" — along which dimension? "More reliable" — measured how? Vague comparatives are the verbal signature of someone reciting rather than reasoning, and experienced interviewers hear them instantly.
Over-engineering is the most common senior-level failure
Mid-level candidates under-design. Senior candidates over-design, and it is the more expensive mistake because it looks like effort. The reflex is understandable: the interview rewards knowledge, knowledge feels like components, so more components must be a better answer. It is not. Every additional stateful system is a permanent operational tax — its own failure modes, its own backup and restore story, its own version upgrades, its own runbook, its own capacity model, its own page at 3am. You do not get to count only the benefit.
| Actual scale | What is genuinely sufficient | What candidates reach for anyway |
|---|---|---|
| 10k DAU, ~10 writes/sec | One Postgres box, one app tier, daily backups. Genuinely. Nothing else. | Microservices, Kafka, Redis, Elasticsearch, Kubernetes |
| 1M DAU, ~500 writes/sec, 20k reads/sec | Postgres primary + 2 replicas, Redis cache, CDN for static, one background worker | Sharding, a service mesh, event sourcing, CQRS |
| 50M DAU, 20k writes/sec | Now sharding, a real queue, a separate read model, multi-AZ. The complexity has been earned. | Multi-region active-active before anyone asked for four nines |
⚠ "We'll need Kafka" is the single most over-used sentence in these interviews
Kafka earns its place when you need durable replay, multiple independent
consumer groups over the same stream, or sustained throughput a database
cannot absorb. It does not earn its place because a request is
asynchronous — a table with a status column and a worker polling it handles
on the order of a thousand or more jobs per second (each job costs at least
three writes: enqueue, claim, complete, so a thousand jobs per second is about
3,000 writes/sec, 60% of a ~5,000 writes/sec planning figure on a shared primary) and can be operated by anyone. If you propose a
queue, say which of the three properties you need. If none apply, say "a
jobs table is enough here, and I'd move to a broker when we need replay or a
second consumer." Also keep your facts current: Kafka 4.x runs on KRaft
only, and since Kafka 4.2 its share groups (KIP-932, "queues for Kafka")
give queue-style consumption, while RabbitMQ Streams offer non-destructive
replay. "Needs replay" no longer points at exactly one product, so name the
property, then the product.
The counterintuitive part: proposing the simple thing is a higher-risk, higher-reward move, and that is exactly why it scores. Anyone can list components. Saying "at this scale a single Postgres box is genuinely fine, and here is the number that tells me so, and here is the threshold where I'd change" requires you to have done the arithmetic and to be willing to be wrong in public. That is what the rating is measuring.
How to disagree with your interviewer well
At some point the interviewer will push back, and often they will be deliberately wrong to see what you do. Both failure modes are common. Folding instantly — "oh, sure, we can do that" — reads as never having had a reason for your original choice. Digging in — repeating your position louder — reads as someone who will be difficult in a design review. The scored behaviour is neither.
The move has three parts. Restate their point in your own words, so they know you actually heard it and so you find out whether you understood it. Locate the disagreement on an axis — you are almost never disagreeing about facts, you are weighting a tradeoff differently or working from a different assumption. Then either update explicitly and say why, or hold with a cost.
Say it like this → "So the concern is that a single
primary is a write bottleneck and a single point of failure — that's fair.
I'm weighting it differently because at 500 writes a second we're at maybe
10% of what one box does, and sharding now costs me cross-shard
transactions on the checkout path. If you're telling me to plan for 10×
growth inside a year, that flips it and I'd shard by customer id from the
start. Which assumption should I be designing against?"
That last question is the highest-value four words available to you. Pushback usually encodes information the interviewer has and you don't — they know the growth curve because they picked the problem. Asking which assumption to design against converts an argument into a requirements clarification, which is a thing you get points for.
And when you are genuinely wrong, be conspicuous about it: "You're right, I had the read-write ratio backwards — that changes my answer, let me redo it." Visibly updating on evidence is a positive signal, not a recovery from a negative one. Correcting yourself cleanly is a positive signal in a design review, not a mark against you.
The whole chapter in one line
You are not being asked for the best design. You are being asked for a
design you can defend, delivered with its price tag attached
and the conditions under which you'd change it. Say the price out
loud and the interview stops being an exam.
Dry run: the four-beat move, then pushback, on one concrete decision
Scenario: 5M DAU, 5 push notifications/user/day. Should the fan-out run on Kafka or a jobs table?
| Step | Applied here | Conclusion |
|---|---|---|
| 1. Assumption | 5M × 5 = 25M/day; at ~12 per second per million per day that is ~300 jobs/sec average, ~900/sec at peak (×3). A jobs table costs at least 3 writes per job, so ~2,700 writes/sec at peak from the jobs alone, under the ~5,000 writes/sec planning figure. Today there is exactly one consumer, the push sender | "Hundreds of jobs per second, one consumer" — none of Kafka's justifying properties are present yet. (At 200M DAU the same arithmetic gives ~12,000/sec average and ~100,000 writes/sec at peak: you would be queueing now, and the answer flips.) |
| 2. Choice | A Postgres jobs table with a status column and a worker pool polling it | Matches the chapter's own claim: a polled jobs table handles on the order of a thousand or more jobs per second and can be operated by anyone, and peak here is under that |
| 3. Cost | No durable replay if a consumer ever needs to reprocess history; polling adds latency a broker's push model wouldn't | Naming the cost, not just the choice, is what separates this from an answer that stops at steps 1 and 2 |
| 4. Trigger | "I'd move to a log or broker the moment we need durable replay, a second independent consumer group on this stream, or throughput a polled table can't absorb — roughly when peak jobs approach 1,000 per second, sooner if the rest of the product already uses much of the primary" | Restates the chapter's exact three conditions for when Kafka earns its place |
| 5. Pushback | Interviewer: "Email digests next quarter will need the same event stream." Restate: "So a second consumer is coming, not hypothetical." | Restating first, per the disagree-well move, confirms what was actually heard |
| 6. Locate the axis | This isn't a new fact — it's beat 4's own trigger condition ("a second independent consumer group") arriving on a known timeline | The disagreement is about timing, not about whether the trigger is real |
| 7. Update or hold | Update explicitly: switch the choice to Kafka (or another log-based broker) now, before the fan-out ships, rather than migrating under load later | "Be conspicuous about it" — the chapter's own guidance for genuinely updating on new information |
Nothing in row 7 contradicts row 2 — the jobs table was the right call given what beat 1 assumed, and beat 4 already named exactly the condition that would reverse it. The revision is the four-beat move working as designed, not a mistake being corrected.
What separates a senior/staff performance from a mid-level one
- Drives the clock. Mid-level waits to be asked what's next. Senior says "I've got requirements and estimates, I'll spend ten minutes on the core data path, then come back to failure handling" — and then does that, watching the time.
- Commits, then qualifies. Mid-level lists three databases and asks which one you want. Senior picks one in a sentence, says what it costs, and moves on. The pick can be wrong; the refusal to pick cannot be recovered from.
- Numbers precede boxes. Mid-level draws the architecture and adds capacity math if prompted. Senior estimates first and lets the numbers force the components — so every box on the board has an arithmetic reason to exist.
- Names the axis, not just the option. "This is a consistency-versus-availability call and I'm taking availability because it's a like counter" beats any amount of correct-but-unexplained choice.
- Volunteers the weakness. Mid-level defends the design. Senior says "the fragile part here is the cross-shard transaction on checkout — if I had more time that's where I'd focus" before being asked. Interviewers have a mental list of your design's flaws; naming them first turns each one from a discovered gap into demonstrated judgement.
- Simplifies on purpose, with a threshold. "One Postgres box, and here's the number at which I'd shard" is a strictly stronger answer than a distributed store nobody needed. Under-engineering with a stated trigger is judgement; over-engineering is anxiety.
- Talks about operating it. Deploys, migrations, backfills, rollback, on-call load, what the dashboard shows, what pages a human. Mid-level designs a system that gets built. Senior designs one that gets run for five years.
- Handles pushback as information. Restates the objection, locates the disagreement in an assumption, updates or holds with a reason — and asks which assumption to design against rather than guessing.
- Scopes to the ask. Recognises that "design a URL shortener for an internal tool" and "design one for 100 M links a day" are different problems, and refuses to answer the second when asked the first.
Before you move on
- Run the four-beat move — assumption, choice, cost, trigger — out loud on a decision you haven't prepared, in under twenty seconds.
- Given a technology choice, name which of the six axes it's actually about, rather than defending the brand name.
- Complete an "it depends" with both the branching condition and what you would do in each branch.
- Apply the three-part disagree-well move to interviewer pushback: restate their point, locate the disagreement on an axis, then update explicitly or hold with a stated cost.
- For a given DAU/QPS number, say whether the bigger risk is under-engineering or over-engineering, and name the specific component you'd cut or add.
- Say what an error budget is, and name one decision you would classify as a reversible two-way door and one as a one-way door.
Sources and further reading
- Problems with CAP, and Yahoo's little known NoSQL system — Daniel Abadi's original statement of PACELC: latency versus consistency when there is no partition
- Google SRE book: embracing risk — error budgets, and weighing the cost of each extra nine against what it protects
- Google SRE book: service level objectives — SLIs, SLOs and how targets are chosen
- PostgreSQL docs: high availability and replication — a synchronous standby delays commits until it confirms
- Apache Kafka 4.2 upgrade notes — KRaft-only since 4.0, and share groups (KIP-932) production-ready in 4.2
- RabbitMQ streams — an append-only log with non-destructive consumption and replay
- OpenAI: scaling PostgreSQL — why "simple, with a stated trigger" can reach very far
- Designing Data-Intensive Applications, second edition — the reference for the consistency, replication and consensus tradeoffs named here
Claims in this chapter were checked against these sources in October 2026. Figures marked "planning figure" are rules of thumb, not guarantees.
5 questions drawn from 7, scored out of 5. This is practice: it runs in your browser, saves nothing and does not change what you have marked read.
Finished reading?
0 of 36 chapters read in this series