core idea
A design-drill question is not testing whether you know the “right” architecture for a URL shortener — there isn’t one. It’s testing whether you can get to an architecture the same way every time: state your scope out loud, size it before you draw it, defend the box you drew, and know what would fall over first. The four drills below are different systems on the surface and the same exercise underneath.
the method
Five moves, always in this order.
clarify first → the numbers → the sketch → the tradeoffs → how it fails
(scope) (assumptions) (boxes) (what you buy) (what breaks)
clarify first
The most-skipped and highest-scoring part of the interview. A strong engineer who starts sketching boxes in the first thirty seconds is optimizing for the wrong signal — the interviewer already knows you can draw boxes. What they’re checking is whether you know which questions change the design, because each of these four drills genuinely turns on a different one: read:write ratio for the URL shortener, where a counter lives once there’s more than one instance for the rate limiter, the shape of the follow graph for the news feed, ordering scope for chat. Ask before you assume.
the numbers
State your assumptions explicitly — daily actives, an average fan-out, a row size — then do the arithmetic in full: requests per second from daily actives, bytes per day from bytes per row, instances from a connection ceiling. The number itself is rarely the point; what it’s for is telling you which side of the system is actually expensive, so you don’t spend the rest of the interview optimizing the side that was never the bottleneck. Back-of-envelope estimation is the fuller version of this arithmetic, done once, for its own sake.
the sketch
Boxes only after the first two moves are done, and drawn as two separate paths — write and read — because in every one of these drills they’re asymmetric, and the interesting design decision usually lives in only one of them.
the tradeoffs
Pick a default, say why it’s right for the assumptions you stated, and say what would make you change it. “It depends” is a non-answer unless you finish the sentence with on what. This is also where most of the real content lives — a cache, a queue, a partitioning scheme (caching and partitioning show up in some form in every drill below).
how it fails
Name the failure mode in production terms — the symptom on a dashboard, the shape of the support ticket — not just the mechanism. Anyone can say “the queue could back up.” Saying what that looks like from the outside is what separates having read about the system from having run one.
problems
Same five moves, four different systems, each pushing on a different part of the method.
The classic opener: key generation, the read-heavy access pattern, and why the interesting part is not the hashing.
Token bucket versus sliding window, where the counter lives, and what happens when the limiter itself is distributed.
Fan-out on write versus fan-out on read, the celebrity problem, and the hybrid every real system ends up with.
Long-lived connections, delivery and read receipts, ordering within a conversation, and where the messages actually rest.
cheat sheet — drills
recognize it
- the interviewer says "design X" and starts sketching before you've asked a single question — that's the tell to slow down, not speed up
- you're asked what happens "at ten times the load" — they're checking whether your bottleneck analysis was ever real or just decorative
- you're asked to defend a specific number choice (why 100 followers not 10,000; why 6 chars not 4) — they want to see the arithmetic, not the answer
- you're asked "what would you page on" — this is the how-it-fails section, graded on whether your failure modes map to real symptoms
- the follow-up abandons your first design entirely ("now assume it's global") — they're testing whether your defaults were principled or accidental
key tricks
- always ask read:write ratio, consistency requirement, and scale before drawing a single box — it changes which half of the design matters
- work every capacity number from a stated assumption, out loud —
daily actives × action/day / 86,400for QPS,rows × row-sizefor storage, and say which number you assumed - draw the write path and read path as two separate diagrams — in every one of these four drills they're asymmetric, and that asymmetry is the design
- when defending a tradeoff, finish with "and here's what would make me switch" — a bare default with no exit condition reads as dogma, not judgment
- state delivery/consistency guarantees precisely: at-least-once + idempotency key, not "exactly-once"; per-conversation order, not global order — precise language is itself a signal
common bugs
- jumping straight to the sketch and skipping clarify first — the single most common way a strong candidate loses points early
- claiming "exactly-once delivery" as a feature you'll just enable, rather than at-least-once plus idempotent processing
- sizing a design around storage bytes when the real constraint was QPS (or vice versa) — always work both and see which one actually binds
- treating fan-out-on-write as strictly better because reads are cheap — ignoring the celebrity write-amplification blowup it creates
- assuming a local atomic (
Interlocked.Increment, an in-process counter) stays correct once there's more than one instance — it silently multiplies the effective limit by the instance count