What Is Actually Being Tested
The interview scores structured thinking under ambiguity: scoping a vague ask, choosing under a constraint, defending the choice.
A system design interview hands you one line — "design Twitter" — and 45 minutes. The line is underspecified on purpose. What is scored is what you do with an underspecified ask, not whether you can name a message broker.
The signal
- Scoping. Cutting a vague ask down to something buildable in the time, and saying out loud what you cut.
- Choosing under constraints. Two options, the one constraint that decides between them, and the cost you accept.
- Depth on demand. One component taken down to data model, failure and recovery, when the interviewer picks it.
- Communication. A design the interviewer cannot follow scores as a design that does not exist.
Why strong engineers still fail
They answer the question they recognise instead of the one they were asked. Kleppmann's Twitter example in Designing Data-Intensive Applications is the standard case: posting ran at roughly 4.6k requests/sec on average and over 12k at peak, while home timeline reads ran around 300k/sec. Those two numbers are what decide between fanning out on write and fanning out on read. A candidate who announces "fan out on write" before asking which number dominates has the right answer with no reasoning attached, and that scores below a candidate who derived a worse answer from the numbers in front of them.
Knowing more architecture than the interviewer is no advantage if the clock goes on proving it. Listing five technologies without naming the constraint that selects one of them reads as recall, and recall is the one thing this format is built not to reward.
Example
// What a scoped answer looks like BEFORE any boxes are drawn.
// In a real interview this lives in the top-left of the board and stays there.
const dau = 200_000_000; // 200_000_000 === 200000000 (numeric separators, ES2021)
const readsPerUserPerDay = 50;
const writesPerUserPerDay = 2;
const readQps = Math.round((dau * readsPerUserPerDay) / 86_400); // ~115,700
const writeQps = Math.round((dau * writesPerUserPerDay) / 86_400); // ~4,600
// Longhand: { readQps: readQps, writeQps: writeQps }
// Shorthand: { readQps, writeQps } — the same object (property shorthand, ES2015).
const load = { readQps, writeQps, ratio: Math.round(readQps / writeQps) }; // ratio 25
const scope = {
inScope: ['post', 'home timeline', 'follow'],
outOfScope: ['search', 'ads', 'direct messages', 'trends'], // said out loud, not dropped quietly
// The decision is written next to the number that forced it. This sentence,
// not the diagram, is what the interview is scoring.
decision: 'reads outnumber writes ~25:1, so timelines are precomputed on write',
knownCost: 'an account with millions of followers turns one post into millions of cache writes',
load,
};When to use it
- Deciding whether to spend interview time on breadth or on one deep dive
- Working out why a design you know is good scored weakly in a mock round
- Preparing for a round on a system you already run in production and keep over-answering
- Scoring a peer's mock interview on reasoning rather than on component names
More examples
The same ask, two correct answers
The interviewer is watching whether your design is a function of the inputs or a constant. Reach for this framing in practice: write the answer as a function of scale, then notice which branch you would have produced from memory.
// "Design a link shortener" has two different right answers, and the thing
// that picks between them is a number you have to ask for.
const designFor = ({ dau, readQps }) => {
if (dau < 10_000) {
return {
tier: 'one stateless service behind one load balancer',
store: 'one relational primary, daily backups',
cache: 'none — the working set fits in the database buffer pool',
shards: 1,
};
}
return {
tier: 'stateless service, autoscaled on CPU',
store: 'primary plus read replicas; shard once one primary stops absorbing the write rate',
cache: readQps > 10_000 ? 'read-through cache in front of the hot keys' : 'not yet justified',
shards: 'decided by write rate, not by user count',
};
};
designFor({ dau: 5_000, readQps: 20 }); // the small design is the correct one here
designFor({ dau: 200_000_000, readQps: 115_000 }); // and only here is the big oneBreadth with and without a deciding constraint
Both objects contain the same knowledge; only one of them demonstrates judgement. Use this as a rewrite exercise on your own mock answers — if a line names a product without naming what forced it, it is not yet an answer.
// Scores poorly: a list of technologies with nothing selecting between them.
const weak = {
storage: ['PostgreSQL', 'Cassandra', 'DynamoDB', 'MongoDB'],
queue: ['Kafka', 'SQS', 'RabbitMQ'],
};
// Same breadth, scored well: one constraint per decision, and the exit condition.
const strong = {
storage: {
choice: 'a single relational primary',
because: 'the access pattern is a keyed lookup plus one range scan, and writes average ~4.6k/sec with peaks over 12k/sec',
wouldChangeTo: 'a partitioned key-value store once one primary stops absorbing the write rate',
},
queue: {
choice: 'a managed at-least-once queue (SQS)',
because: 'consumers are already idempotent on the job id, so duplicates are harmless',
// SQS deletes a message once it is acknowledged, so it cannot replay history.
wouldChangeTo: 'a retained log (Kafka) if consumed events must be re-read later',
},
};
Discussion