1. Interview structure and time budget#

A 45-minute system design interview has a natural structure. The biggest mistake is spending too long on requirements and running out of time for the deep dive — which is where senior judgment is actually demonstrated.

PhaseTimeGoal
Functional requirements3–4 minUnderstand what to build. 3–4 sharp questions, clean summary, move on.
Non-functional requirements2–3 minScale, latency targets, consistency tolerance. Numbers justify later decisions.
Entities3–4 minName the core data structures. Forces clarity before you design anything.
APIs3–4 minDefine the contract. Often skipped by candidates — interviewers notice.
High level design10–12 minA working system that satisfies functional requirements. Don't optimize yet.
Deep dive15–18 minWhere senior judgment shows. Let the interviewer guide the area, but have 2–3 ready to propose.
Buffer / Q&A2–3 minQuestions, wrapping up.

High level design should be a working system on the whiteboard that satisfies functional requirements — not a perfect one. Optimization and edge cases belong in the deep dive. A common failure mode: going deep on one component during high level design and running out of time before covering the full system.

2. Clarification questions as a steering tool#

Clarification questions are not a formality before the "real" interview begins. They are a steering mechanism. Each answer should visibly change something in your design — and the interviewer should be able to see that connection.

The goal isn't to ask many questions. It's to ask questions whose answers determine which branch of the design tree you go down. A sharp clarification question signals that you understand the design space well enough to know what matters.

The test for a good clarification question
If the answer wouldn't change anything about your design, it's not worth asking. Every question should unlock a decision.

Product questions before technical questions. Don't jump straight to scale numbers. Ask about scope, semantics, and model first — because those answers determine which technical questions are even worth asking.

Wrong order:

→ "How many users do we have?"
→ "What's the read/write ratio?"

Right order:

→ "What leaderboard scopes do we need — global, regional, friend?"
→ "Is the social graph symmetric friends or asymmetric follows?"
→ "Staleness tolerance — exact rank or movement signal sufficient?"
→ Then: "How many players are we designing for?"

Use answers to justify tradeoffs out loud. After getting an answer, say what it changes:

"Since scores only increase, most score updates will be no-ops on the leaderboard — that simplifies the write path significantly."

This shows the interviewer you're not just collecting information — you're actively translating requirements into design decisions.

Clarification questions as a pacing tool. If you're unsure how deep to go on a topic, a clarification question buys you thinking time and directs the conversation. "Before I go deeper on the sharding strategy — is approximate rank acceptable, or do we need exact rank?" frames the next 10 minutes of the interview.

3. Scope sizing before diving deep#

Before asking how to build something, ask how big it is. Size determines complexity class, and complexity class determines the right design.

This is especially important for problems with multiple scopes — like a leaderboard with global, regional, and friend variants. Each scope has a different N, and the right design for each scope is different.

Friend leaderboard, 50 friends    → fetch all scores, sort in memory, done
Friend leaderboard, 5000 friends  → fan-out architecture needed
Regional, 5M players              → single sorted set, ZREVRANK fine
Regional, 50M players             → approximate rank treatment
Global, 100M players              → full complexity: sharding, histogram, prefix sum

Stating this out loud in the interview is valuable: "Friend and regional leaderboards are essentially bounded top-k problems — the interesting distributed systems challenges are concentrated in the global leaderboard." That scoping statement signals senior judgment. It says you won't waste time over-engineering the simple cases.

The complexity class mental model. Once you've placed a problem in a complexity class, the design almost follows automatically. Small N → top-k, direct Redis call, done. Large N → you need an approximation layer and a sharding strategy. The design isn't arbitrary — it's the natural solution for that complexity class.

4. Presenting tradeoffs#

Every design decision has a cost. Naming both sides of every tradeoff is the core habit that distinguishes senior answers. Not "I'll use X" but "X gives us Y benefit at the cost of Z — that tradeoff is acceptable because..."

Interviewers aren't grading you on whether you picked the right answer. They're grading you on whether you understand why it's the right answer for this context — and whether you'd pick differently in a different context.

The tradeoff format. Lead with the insight, then the mechanism, then the cost:

"Fan-out on write gives us O(1) friend leaderboard reads, but at the cost of write amplification proportional to friend count. With a hard cap of 500 friends, that's at most 500 cache writes per score update — acceptable. Without a cap, we'd need to fall back to fan-out on read for high-degree users."

Eventual consistency as a chosen tradeoff, not a constraint. When you accept eventual consistency, say so explicitly and say why. "I'm accepting a few seconds of staleness here because rank is approximate by design anyway — there's no point paying for strong consistency to protect an already-approximate value."

Know when consistency actually matters. The flip side: be able to identify the cases where eventual consistency is not acceptable. PostgreSQL as the score source of truth is written synchronously before Kafka — because if that data is lost, you can't recover. Redis is eventually consistent because it's a derived view that can always be recomputed from PostgreSQL.

5. Pushing back on requirements#

When an interviewer changes a requirement — "actually, I need exact real-time rank for every player" — they're often probing. They want to see if you collapse immediately, refuse to budge, or negotiate with tradeoffs.

The right response: acknowledge the requirement, surface the cost, propose a spectrum of options, ask what's driving the requirement.

Wrong pushback — sounds defensive:

"That's really hard to do at scale, I'm not sure that's feasible."

Right pushback — sounds like an engineer:

"We can do exact rank — it changes a few things. We lose the O(1) prefix sum
approximation and go back to ZREVRANK on the full sorted set, which means
cross-shard coordination on every rank query. At 100M players that's O(log N)
per shard plus aggregation — manageable but slower. Is there a specific use
case driving this? Exact rank on a post-match summary screen is much cheaper
than exact rank updated in real-time during gameplay."

The accuracy spectrum. For any consistency requirement, present a spectrum rather than a binary:

OptionMechanismCostGood for
Approximate rankPrefix sum, O(1)±bucket_size errorIn-game feedback, rank movement
Exact rank on demandZREVRANK across shardsO(log N) + latencyPost-match summary, profile page
HybridApproximate in-game, exact async stored on player recordSlight delay on exactBoth surfaces, best of both

The hybrid answer — approximate for real-time, exact async for non-real-time surfaces — is almost always the right senior answer. It reframes the question from "accurate vs approximate" to "which surface needs which level of accuracy."

6. Verifying in your own words#

After working through a complex topic with the interviewer, restate your understanding before moving on. This does three things: forces you to actually process what was said, surfaces misunderstandings immediately, and shows the interviewer your reasoning rather than just your conclusion.

The pattern:

"So if I understand this correctly — range-based sharding lets me compute global rank cheaply because rank is just a sum of shard cardinalities above me, but it risks hot shards if score distribution is uneven. I'd mitigate that with equal-frequency boundaries upfront. Does that match what you're thinking?"

Same conclusion as just saying "I'll use range-based sharding" — but the interviewer sees your reasoning and you've implicitly invited a correction if you're off track.

This habit also serves as a pacing tool. Restating before moving on signals a natural transition point and gives both you and the interviewer a moment to align before going deeper.

7. Dependency-driven topic ordering#

Topics in system design have dependencies — you can't explain adaptive bucket boundaries without first establishing why fixed buckets exist, which requires explaining approximate rank, which requires establishing that exact rank is expensive at scale.

The discipline is: surface each topic at the layer it belongs to. Don't jump layers. The dependency map for leaderboard design looks roughly like this:

Layer 0 — Clarification:
  scope sizing → score semantics → social model → staleness tolerance

Layer 1 — Foundations:
  Redis sorted sets → top-k vs k-neighbor distinction → score semantics implications

Layer 2 — Scale foundations:
  score histogram → ZRANGEBYSCORE for neighbors → Kafka write buffer

Layer 3 — Scale advanced:
  adaptive bucket boundaries → prefix sum → range-based sharding

Layer 4 — Synthesis:
  global rank formula → rank movement delta

Layer 5 — Friend leaderboard:
  fan-out on write → fan-out on read → celebrity hybrid → app-layer merge

Layer 6 — Operational:
  cache warming → reconciliation → idempotency → monitoring

In practice this means: in the requirements phase, ask scope-sizing questions but don't explain prefix sum. In the high level design, mention Redis sorted sets and Kafka but don't explain adaptive bucket boundaries. In the deep dive, when the interviewer asks about rank at scale, build from histogram → fixed buckets → equal-frequency → prefix sum in sequence.

Why this works. It creates a conversation where complexity is revealed progressively. The interviewer sees you build up from first principles. It also protects your time budget — you only go deep on an area if the interviewer pulls on it. If they don't ask about adaptive buckets, you don't need to explain it.

8. Common mistakes#

Spending too long on requirements. Requirements should feel like a conversation, not an interrogation. 3–4 sharp questions, clean summary, move on. If requirements take more than 5 minutes, you're running out of time for the deep dive.

Treating high level design as a deep dive. High level design is a working system that satisfies functional requirements. Not a perfect one. Save optimization, edge cases, and failure modes for the deep dive where they belong.

Going deep on simple sub-problems. A friend leaderboard of 50 people is a trivial fetch-and-sort. Don't spend 5 minutes architecting it. Recognize when something is in the easy complexity class and say so explicitly, then move on.

Naming solutions without explaining why. "I'll use a Redis sorted set" is not an answer. "I'll use a Redis sorted set because it gives O(log N) writes and O(log N + K) reads for top-k, with rank queries built in — and it keeps members sorted automatically so I never sort manually" is an answer.

Not driving the interview. After finishing one area, say what you want to cover next: "I want to make sure we cover the write path and failure handling before we run out of time — should I go there?" This shows ownership of the conversation and makes sure you cover what matters most.

Collapsing immediately when pushed back. If the interviewer challenges your design, don't immediately abandon it. Engage: understand the concern, check if it's valid, either defend your decision with reasoning or update it with explicit justification.