Interview prep

Interview prep · 14 min

How to run a design interview

A minute-by-minute plan for 45 minutes, and what interviewers listen for.

A system design interview is not a test of whether you know the "right" architecture for Twitter. There isn't one. It's a 45 to 60 minute simulation of a design meeting, and the interviewer is watching how you run it: what you ask, what you decide, what you give up, and whether you notice the hard part before they point at it.

This guide gives you a plan for the clock, tells you what interviewers listen for at different levels, and ends with a URL shortener run through the whole 45 minutes.

The plan on one page

Phase 45-minute round 60-minute round What you leave on the board
1. Clarify requirements 0 to 5 0 to 7 3 to 5 functional requirements, 3 to 4 non-functional ones with numbers
2. Estimate 5 to 8 7 to 10 Reads/sec, writes/sec, storage, and what they imply
3. API 8 to 12 10 to 15 The 2 to 4 endpoints that matter
4. Data model 12 to 15 15 to 20 Main entities, keys, and the database choice
5. High-level design 15 to 25 20 to 32 A diagram that serves every functional requirement
6. Deep dives 25 to 40 32 to 52 One or two hard parts solved properly
7. Wrap-up 40 to 45 52 to 60 Bottlenecks, failure modes, what you'd do next

The exact minutes matter less than the shape: a working design by roughly the halfway mark, and the biggest single block on the hard parts. The most common way to fail is to spend 35 minutes on requirements and boxes and have no time left for the part the question was actually about.

Requirements5 min
→
Estimate3 min
→
API4 min
→
Data3 min
→
High-level10 min
→
Deep dives15 min
→
Wrap-up5 min
The 45-minute shape. The deep dive is the biggest block, because that's where the signal is.

Phase by phase

1. Clarify requirements (5 minutes)

The question is vague on purpose. Narrow it down out loud:

  • Who uses it and for what? "Is this for consumers or for internal teams?"
  • Which features are in scope? List a few, then propose cutting: "I'll focus on posting and the home feed, and leave out search and DMs unless you want them."
  • How well must it work? Scale (daily users), latency targets, consistency needs ("is it okay if a like count is a few seconds stale?"), availability, and durability ("can we ever lose a message?").

Write them down where the interviewer can see. You'll point back at them all interview.

2. Estimate (3 minutes)

Only estimate what changes a decision. Requests per second (average and peak), the read to write ratio, storage per year, and occasionally bandwidth. Then say what the number means: "4,000 reads a second fits on a few servers with a cache; 40 writes a second is nothing for one database." An estimate that doesn't lead to a conclusion is wasted time.

3. API (4 minutes)

Write the few calls that cover the core features, with their important parameters and responses. This pins down what the system actually does and often surfaces questions: pagination, idempotency for writes that may be retried, who is authenticated.

4. Data model (3 minutes)

The main entities, their keys, and the most important access patterns. Then choose the store because of those access patterns: "Every read is a lookup by short code, so a key-value store fits; there are no joins."

5. High-level design (10 minutes)

Draw the simplest design that serves every functional requirement. Walk one request through it from client to storage and back. Each box should trace back to a requirement or a number from your estimate. Don't add Kafka, microservices and three caches yet. Add them when a requirement asks.

6. Deep dives (15 minutes)

Pick the one or two parts where this question is hard, say so, and go deep. "The interesting problem here is the celebrity with 50 million followers" or "The hard part is not selling the same seat twice." Good interviewers will steer you, so ask: "I'd like to go deeper on X. Or is there another area you'd prefer?" Deep means: alternatives considered, the choice, the failure cases, and the numbers.

7. Wrap-up (5 minutes)

Look back at your own design critically: the single points of failure, what breaks first at 10 times the load, what you'd monitor, and what you simplified. Interviewers like candidates who find the weaknesses in their own design before anyone else does.

What interviewers listen for

Everyone is expected to produce a working design. What changes with level is how much you drive and how deep you go.

Signal Junior or mid-level Senior and above
Requirements Asks sensible questions, writes them down Spots the requirement that drives the design and negotiates scope
Estimation Gets the right order of magnitude Uses numbers to rule options in or out, unprompted
Design A correct, simple design that works Simple design first, then evolves it under pressure with clear reasons
Depth Can go deep when guided Picks the hard parts without prompting, knows several solutions and their failure modes
Trade-offs Names a trade-off when asked States what each choice gives up as a habit
Operations Aware that things fail Talks about failure modes, monitoring, deploys, cost and migrations
Communication Explains clearly Drives the conversation and keeps the interviewer oriented

A junior candidate who builds a clean, correct design and explains it well will do fine. A senior candidate who does the same thing but needs the interviewer to point out every hard part will not.

Common mistakes

  • Jumping to boxes. Drawing a load balancer in minute two, before anyone knows what the system does.
  • Estimating without concluding. Five minutes of arithmetic and then never using the result.
  • Buzzword architecture. Kafka, Kubernetes, microservices and a service mesh for a system with 50 writes a second. Every component needs a reason.
  • Never committing. "We could use SQL or NoSQL, both have pros and cons" and then moving on. Pick one and say why.
  • Going deep too early. Twenty minutes on the database schema, then no time for the high-level design.
  • Ignoring the hard part. Designing a perfect generic web app for "design a ticket booking system" and never discussing two people grabbing the same seat.
  • Silence. Thinking quietly for three minutes. The interviewer can only grade what they hear. Think out loud, even when unsure.
  • Defending instead of listening. When the interviewer pushes back, they are usually giving you a hint or testing whether you can adapt. "Good point, that breaks when... so let's change it to..." scores far better than arguing.

When you get stuck

Everyone blanks at some point. What matters is what you do in the next ten seconds. Say what's happening and use one of these moves:

  • Go back to the requirements. "Let me check this against what we said matters most: never losing an order." The requirement usually points at the answer.
  • Use the numbers. "We said 500 writes a second of simple inserts. One Postgres on a decent machine usually handles that, so I won't shard yet; I'd confirm with a quick load test." Numbers rule options in or out.
  • Name the options out loud. "I can see two ways: a queue, or a direct call with retries. Let me compare them on what happens when the kitchen tablet is offline." Comparing two options is easier than inventing one.
  • Make it smaller. "Let me get it working for one restaurant first, then see what breaks at a thousand."
  • Ask, specifically. "Would you like me to focus on the write path or the read path?" is a fine question. "What should I do?" is not.

Never sit in silence. A half-formed thought said out loud gives the interviewer something to work with.

The first two minutes, weak and strong

The prompt is "Design a URL shortener."

Weak: "OK, so we'll have a load balancer, then some app servers, and a database, probably Cassandra because it scales, and a Redis cache in front." Boxes in the first minute, a database chosen before anyone knows the traffic, and no question asked.

Strong: "Before I design anything, let me pin down what it must do. Users paste a long URL and get a short one, and opening the short one redirects. Do we need custom aliases? Expiry? Click analytics? And roughly how many new links a day, and how many clicks? I'll assume reads far outnumber writes, maybe 100 to 1, unless you tell me otherwise." Requirements first, assumptions said out loud, and the read-heavy shape spotted before any box is drawn.

Phrases for stating trade-offs

Trade-offs are the currency of these interviews. Make them a habit with a few sentence shapes:

Situation Say something like
Making a choice "I'll go with X because of Y. The cost is Z, which is acceptable here because..."
Rejecting an option "We could do X, but it gives up Y, and we said Y matters more for this system."
Deferring complexity "For now one database is enough for these numbers. If writes grow 10 times, I'd shard by user ID."
Picking consistency "Likes can be eventually consistent, a few seconds stale is fine. The seat inventory can't, so that path goes through a single primary with a conditional update."
Under uncertainty "I'm not sure of the exact limit, but roughly a few thousand writes a second per node, so we're well inside it."
Inviting steering "There are two hard parts here, X and Y. I'd start with X unless you'd rather see Y."

The pattern is always the same: the choice, what it costs, and why that cost is fine for this system's requirements.

Worked example: a URL shortener in 45 minutes

Here is what a calm, complete run looks like. Times are approximate.

0 to 5: requirements

"Users paste a long URL and get a short one. Anyone opening the short URL is redirected. Should users pick custom aliases? Do links expire? Do we need click analytics?" Say the interviewer answers: custom aliases yes, optional expiry, basic click counts.

On the board:

  • Functional: create a short link (optionally custom), redirect, optional expiry, click counts.
  • Non-functional: redirects fast (under 50 ms at the server), highly available (a dead link breaks someone's campaign), short codes never collide, links durable for years.

5 to 8: estimates

  • 100 million new links a month, about 40 writes a second (100M / 2.5M seconds).
  • Reads 100 times writes: about 4,000 redirects a second on average, say 20,000 at peak.
  • 5 years of links: 100M × 60 = 6 billion links. At about 500 bytes each, 3 TB.
  • Code length: base62 with 7 characters gives 62^7, about 3.5 trillion codes, far more than 6 billion.

Conclusion said out loud: "Writes are trivial. Reads are heavy and very cacheable. 3 TB would fit on one large database, but every query is a lookup by key, so a store that partitions by key lets it keep growing without a migration later."

8 to 12: API

POST /links          { url, alias?, expiresAt? }  -> 201 { code, shortUrl }
GET  /{code}         -> 301 or 302 to the long URL, 404 if unknown or expired
GET  /links/{code}/stats  -> { clicks }

A short note on 301 vs 302: a 301 is cached by browsers, which saves load but means we stop seeing clicks. Since we want click counts, use 302.

12 to 15: data model

links(code PK, long_url, owner_id, created_at, expires_at). Every redirect is a lookup by code, with no joins, so a key-value or wide-column store (DynamoDB, Cassandra) partitioned by code fits well. Clicks go elsewhere (see the deep dive).

15 to 25: high-level design

%% caption: The redirect path reads through a cache. Clicks leave the hot path through a queue.
flowchart TD
  CL(["Client"]) --> LB["Load balancer"]
  LB --> LS["Link service<br/>create and redirect"]:::hot
  LS --> CA["Cache<br/>hot codes"]
  CA -- "miss" --> ST[("Link store<br/>partitioned by code")]:::store
  LS -. "click events" .-> CE[["Queue"]]
  CE --> CJ["Counter job"]
  CJ --> SS[("Stats store")]:::store
The redirect path reads through a cache. Clicks leave the hot path through a queue.

Walk a redirect through it: look up the code in the cache, fall back to the store on a miss, return a 302, and fire a click event onto a queue without waiting for it.

25 to 40: deep dives

Generating codes without collisions. Options: hash the URL and take 7 characters (collisions need checking and retrying), random codes with an insert-if-not-exists (simple, retries are rare at this density), or a counter turned into base62. A single counter is a bottleneck and a single point of failure, so hand out ranges: each app server grabs a block of 10,000 IDs from a coordination service and allocates locally. Trade-off: codes become guessable in sequence, so if that matters, shuffle the ID bits before encoding. Custom aliases use the same table with an insert-if-not-exists, so a taken alias fails cleanly. Generated codes go through the same insert, so if the counter ever produces a code someone already chose as an alias, the server just takes the next ID.

Making redirects fast. Link popularity is extremely skewed, so a cache with a 95% or better hit rate is realistic. Cache-aside with a TTL, and on a miss for an unknown code, cache the "not found" too, briefly, so bots scanning random codes don't hammer the store.

Click counts. Incrementing a counter in the link row on every redirect would turn a read-heavy path into a write-heavy one. Instead, emit an event, aggregate counts per code per minute in a stream job, and write the totals. Counts are a few seconds stale, which the requirements allow.

40 to 45: wrap-up

"The link store and cache are replicated across zones, so losing one machine doesn't break redirects. The ID range service is the piece to watch: if it's down, existing redirects still work, and servers keep allocating from the range they already hold. At 10 times the traffic, the cache tier grows first. I'd monitor redirect latency, cache hit rate and 404 rate. I skipped abuse detection, like phishing links, which a real product would need early."

That's a complete answer. It isn't clever. It's ordered, every component has a reason, and each deep dive names its trade-off.

Plan your own clock

You're asked to "design a parking garage payment system" in a 45-minute round. Before you design anything, write what you'd aim to have on the board at minute 5, minute 15 and minute 25, and name the part you'd choose for the deep dive.

Show one answer

Minute 5: functional requirements (enter with a ticket or number plate, pay at a kiosk or app, exit gate opens if paid), non-functional ones (gate must open within 2 seconds, must work if the internet is down, never charge twice), and rough scale (say 500 garages, 2,000 cars a day each).

Minute 15: the numbers (about 1 million entries a day, roughly 12 a second, tiny), the API (POST /entries, POST /payments with an idempotency key, POST /exits), and the data model (entries, payments, garages, rates).

Minute 25: a high-level design with a local controller in each garage that can open gates offline and syncs to a central service, plus the payment provider.

Deep dive: offline operation and payments. How the gate decides while the network is down, and how payments made in the app reach the gate, without ever charging twice when a payment request is retried.

What to remember

  1. Follow a fixed shape: requirements, estimates, API, data model, high-level design, deep dives, wrap-up.
  2. Have a working design by roughly the halfway mark, and spend the largest block on the hard parts.
  3. Every estimate should end in a conclusion, and every box should trace back to a requirement.
  4. Seniority shows in driving: finding the hard parts yourself and stating trade-offs unprompted.
  5. State choices as "X because Y, at the cost of Z, which is fine here because...".
  6. Finish by critiquing your own design: failure points, what breaks at 10 times the load, and what you'd monitor.