The four-step framework
Run a 45-minute design interview on a clock: scope it with numbers, size those numbers, sketch API before boxes, then attack the bottleneck you predicted.
A 45-minute design interview has room for exactly four things, and candidates lose it by spending twenty minutes on the first one. Each step gets a slice of the clock and hands the next one something it cannot start without: scope produces numbers, numbers produce a shape, the shape produces a bottleneck, and the bottleneck produces the trade-off conversation being graded.
| Step | Minutes | Output |
|---|---|---|
| 1. Requirements and scope | ~8 | Verb list, out-of-scope list, 4 numbers |
| 2. Estimate | ~5 | Peak QPS, storage/year, bandwidth |
| 3. High-level design | ~15 | API, data model, boxes |
| 4. Deep dive and trade-offs | ~15 | One component designed, one alternative rejected |
The dotted edges matter more than the solid ones: a Step 4 bottleneck the boxes cannot absorb is normal — go back to Step 3, change one box, say why.
Step 1 — Requirements and scope, ~8 minutes
Write functional requirements as a short list of verbs, five at most: "create a paste, read a paste, expire a paste." Verbs keep the list honest; nouns smuggle in features nobody asked for. Everything else goes on a visible out-of-scope line — accounts, search, moderation — said out loud: "I am not designing auth or search; tell me if either is the point."
Then the non-functional requirements, as numbers rather than adjectives — the distinction itself is covered separately. Four questions extract them:
- Scale — "How many daily active users, and how many actions each per day?"
- Latency — "Read latency target, at what percentile?" Insist on p99; the mean hides the tail, and the tail is what users feel.
- Consistency — "After a write, must the next read see it, or is a few seconds of staleness fine?" CAP belongs here: when a partition occurs, this system chooses consistency or availability. Then PACELC's else-branch — with no partition, latency or consistency? See data consistency.
- Availability — "Three nines or four?" 99.9% is 43 minutes down a month, 99.99% is 4.3 minutes — that gap is the redundancy budget.
Leave Step 1 holding four numbers: DAU, actions per user per day, read/write ratio, payload size. Without them Step 2 has nothing to multiply, and you are about to guess at a shape.
Step 2 — Estimate, ~5 minutes
Three conversions, out loud, with the arithmetic visible:
QPS = DAU × actions/user/day ÷ 86,400 s (peak ≈ 2–5× average)
Storage = writes/day × payload × 365
Bandwidth = read QPS × payload
Two anchors remove the mental arithmetic: 1M requests/day ≈ 12 QPS, 1B/day ≈ 12,000 QPS. Scale linearly between them.
This is not busywork, because of one threshold: a commodity Postgres box handles roughly 5,000 simple QPS. Under it, the answer is one database with a follower, and a sharded fleet is over-engineering. Over it, you owe a partitioning key before drawing anything — see database scaling. Storage does the same on the other axis: 100 GB/year fits on one disk, 40 TB/year does not.
Step 3 — High-level design, ~15 minutes
API first, then the data model, then the boxes, and the order is not stylistic. The API is the contract: it fixes what a client can ask for, what comes back, and what is expensive. The data model follows from the access patterns the API declared. Boxes drawn before a contract are decoration: a queue can go anywhere on a whiteboard, but nothing justifies one until an API call may be asynchronous.
Three to five endpoints, with signatures:
POST /pastes {content, ttl_seconds} -> 201 {id, url, expires_at}
GET /pastes/:id -> 200 {content, created_at} | 404
DELETE /pastes/:id -> 204
GET /pastes/:id/meta -> 200 {size, views, expires_at}
Then the data model: table, primary key, one index per read path. Then the boxes — client, load balancer, app tier, datastore, cache — each tracing to a line in the API or a number from Step 2. If caching appears, say what hit rate earns it a place.
Step 4 — Deep dive and trade-offs, ~15 minutes
The Step 2 numbers already said where this breaks; go there. Reads 10x writes means read scaling and invalidation. Megabyte payloads mean storage and egress. Writes contending on one row mean locking and idempotency.
Little's Law turns a slow dependency into a concrete failure: concurrency = arrival rate × latency. 350 QPS against a store answering in 200 ms at p99 puts 350 × 0.2 = 70 requests in flight, so a 20-connection pool queues and times out. The fix is then specific: bigger pool, lower latency, shed load.
Close by naming the alternative you rejected: "cache-aside rather than write-through, because writes are 1 in 11 here and write-through pays on every one to protect a cache we rebuild in seconds." One sentence rejecting an option is the highest-signal thing you say all hour.
The whole shape, compressed
A paste service. Scope: create a paste, read by id, expire on TTL. Out of scope: accounts, search, edit. Assume 2M DAU, 0.5 pastes per user per day, read/write ratio 10:1, average paste 10 KB, p99 read under 200 ms, 99.9% availability, staleness of seconds acceptable.
Estimate: 2M × 0.5 = 1M writes/day ÷ 86,400 ≈ 12 write QPS. Reads 10M/day ≈ 120 QPS average, ~350 QPS at 3x peak. Storage 1M × 10 KB = 10 GB/day, ×365 ≈ 3.6 TB/year. Read bandwidth 120 × 10 KB ≈ 1.2 MB/s, ~3.5 MB/s at peak.
Design: the endpoints above. 350 QPS sits under the 5,000 QPS single-box threshold, so metadata lives in one Postgres leader with a follower — no sharding. But 3.6 TB/year of blobs does not belong in that row, so bodies go to object storage and the row keeps {id, blob_key, size, expires_at}.
Deep dive: the predicted bottleneck is object-store latency on the read path — 200 ms at p99 against a 200 ms budget leaves nothing. Cache by id; reads are Zipfian, so a few GB buys 80%+ hit rate, and pastes are immutable, so invalidation is just TTL. Rejected: serving bodies from Postgres, simpler but pushing 3.6 TB/year through the one component a replica cannot scale.
In an interview
What is being tested is whether you can drive an underspecified problem to a defensible design under time pressure. Announce the framework once — "scope, estimate, API and data model before boxes, then deep dive on whatever breaks first" — then follow it, watching the clock. Derive each number out loud and say what it rules out. "350 QPS peak, so one database, no sharding" beats a correct diagram delivered silently.
The mistake that loses the most points is spending twenty of the 45 minutes on requirements because clarifying feels safe. It burns the deep dive, the only part separating a senior candidate from a mid-level one. Next: boxes before API, a diagram nobody can critique because nothing has a contract. Third: designing for 100x the given scale, which reads as inexperience.
Check yourself
1. The interviewer says 50M DAU, 4 requests per user per day, read/write ratio 9:1. Do you shard the primary datastore?
50M × 4 = 200M requests/day ÷ 86,400 ≈ 2,300 QPS average, ~7,000 QPS at 3x peak. Writes are 1 in 10, so ~700 write QPS against the ~5,000 QPS single-box threshold — the leader holds. The 6,300 read QPS do not, but followers and a cache absorb them without partitioning. No shard yet; name the write rate that would change the answer. State the cost: follower reads lag, so read-your-writes breaks and a user watches their own update vanish.
2. You are 24 minutes in, the boxes are drawn, and the interviewer asks about the write path. What fills the remaining 21 minutes?
Not a tour of every box. Pick the component the Step 2 numbers predicted would break and spend 12–15 minutes on it properly — data structure, failure mode, behaviour on retry — keeping the last minutes for one rejected alternative and why. Breadth was Step 3; repeating it is how candidates run out of clock.
3. Payload is 2 MB, not 10 KB, and read traffic is 300 QPS. What changes before you draw anything?
300 × 2 MB = 600 MB/s of egress, roughly 5 Gbps sustained — bandwidth is the binding constraint now, not QPS. Bytes leave the application path entirely: object storage plus a CDN, the app serving signed URLs and metadata. One input changed and the shape changed with it, which is the argument for doing Step 2 before Step 3.
Memorise it as four verbs: scope it, size it, sketch it, stress it.