Interview framework: applied numbers and config
Read the artifacts of a real interview — an estimation helper, a requirements note, a capacity calc, a config that encodes a tradeoff — and do the reasoning a senior engineer would: which number changes the design, what the config gives up, where the bottleneck moves.
The framework lives in the numbers and the config, not the prose. An estimate that converts to a server count, a requirements note that hides a missing target, a config that silently encodes a tradeoff. Read each artifact, do the arithmetic and the reasoning in your head, and pick the answer a senior engineer would commit to at the whiteboard.
Practise the loop you run at the whiteboard: find the design-changing number, spot the missing requirement, convert load to capacity, and read what a config gives up — choosing the move the arithmetic and the tradeoff support.
Snippet 1 — the estimation helper
def design_changing_numbers(dau, posts_per_day, read_write_ratio):
writes_per_sec = dau * posts_per_day / 86_400
reads_per_sec = writes_per_sec * read_write_ratio
peak = lambda x: round(x * 3) # 3x peak multiplier
return {"write_avg": round(writes_per_sec), "read_avg": round(reads_per_sec),
"write_peak": peak(writes_per_sec), "read_peak": peak(reads_per_sec)}
# 50M DAU, 2 posts/day, reads 50x writes
print(design_changing_numbers(50_000_000, 2, 50))Reading to one significant figure, which output number first changes the design, and to what?
Snippet 2 — the requirements note
# requirements captured before drawing
functional:
- users post messages
- users read a timeline
non_functional:
scale: 50M DAU
latency_p99_read_ms: 150
# consistency: <-- not captured
availability_slo: "99.9%"What's the most consequential gap in this requirements note, and why does it matter before you draw?
Snippet 3 — the capacity calc
peak_read_qps = 200_000
per_node_qps = 8_000 # bend point of the queueing curve
cache_hit_rate = 0.90
origin_qps = peak_read_qps * (1 - cache_hit_rate)
nodes = -(-origin_qps // per_node_qps) # ceil division
print(origin_qps, nodes) # what prints, and what does it justify?What does this print, and what design decision does it justify?
Snippet 4 — the config that encodes a tradeoff
# timeline read path
read_from: cache
cache_ttl_seconds: 30
on_cache_miss: read_replica # async-replicated, may lag primary
write_path: fan_out_on_write_asyncWhat tradeoff does this config encode, and how should you state it to the interviewer?
- 01Given an estimation helper's output, how do you spot the number that changes the design?
- 02How do you convert a cache hit rate into an origin node count, and what does the result justify?
- 03How do you read a tradeoff out of a config, and how do you state it?
Every step of the framework shows up in the artifacts you read at the whiteboard. The estimation helper outputs a number that either crosses a threshold (a ~150–200K peak read QPS forces a cache/fan-out path) or doesn’t (a modest write rate changes nothing) — read to one significant figure and find the one that moves the design. The requirements note is judged by what’s missing: a dropped consistency target is load-bearing, because staleness-tolerance decides fan-out-and-cache vs coordinate. The capacity calc converts load to capacity — a 90% cache hit rate turns a ~25-node origin fleet into ~3, which is exactly what justifies the cache — and you still size the cache’s RAM and guard against it becoming a SPOF. The config silently encodes a tradeoff (a TTL + async replica + async fan-out is eventual consistency), and the senior move is to name the price (a staleness window) and the boundary where you’d flip it (transactional data). Read the numbers, do the math, name the decision and its cost — that’s the framework made operational.
Something unclear?
Ask a question about this lesson. Questions are anonymous and go straight to the author to make the lesson better.