KnowSys

Systems Interview Mastery

Follow one interview prompt, "design a URL shortener", through forty-five minutes: what the interviewer is writing down, how to find the one hard part hiding in the question, and how to go deep on it with numbers and mechanisms instead of boxes.

⏱ 37 min read◆ BeginnerAssumes: a terminal and Python; the rest of this book helps, and so do caching, replication and queues at a sketch level
Start reading

You sit down for a system design interview, and the interviewer writes one line on the whiteboard: "Design a URL shortener." You have forty-five minutes.

It sounds like a short job. A shortener is a table that maps a short code to a long address, plus a web page that looks the code up and sends the visitor on to the long address. You could describe that in two minutes. The interviewer has given you forty-five, and they aren't waiting for the table. Somewhere inside this simple-sounding prompt is one part that is hard, and they're watching to see whether you find it.

It works like a driving test. The examiner doesn't want an explanation of how the engine works. They want to see you check your mirrors, hold your lane and react when something unexpected happens, and a candidate who talks about the engine for the whole test passes nothing. In the interview, the examiner's checklist is a written scoring sheet called a rubric, and the interviewer fills it in while you talk.

So this chapter asks one question: during those forty-five minutes, what is being scored, and how do you spend the time so the score is a fair picture of what you know? We'll start by finding the shortener's hard part ourselves, then work outward to the rubric, the clock, the arithmetic, the drawing and the deep questions, and come back to the shortener at the end to answer it properly.

01Finding the hard part

1.1The obvious design

Let's design the shortener the way most people first would. A visitor pastes a long address, such as a newspaper article's link, and the service hands back a short code like k3Zp, so the visitor can share short.example/k3Zp instead. Later, when anyone opens that short link, the service looks the code up in a table of code → long address and redirects them. The table is the whole state of the system.

The only decision in there that isn't obvious is how to pick the codes. They have to be short, and each code can lead to only one address, so no two addresses may ever be given the same code. The simplest way to get unique-looking codes is to pick them at random from the 62 letters and digits and use whatever comes out. With four characters, that's 62 × 62 × 62 × 62 = 14,776,336 possible codes. Fourteen million sounds like plenty of room.

1.2How soon do random codes repeat?

Before you run anything, make a guess.

Predict before you read on

A shortener picks 4-character codes at random from 14,776,336 possibilities and never checks whether a code is already used. After roughly how many codes is the first repeat likely?

The script draws random 4-character codes until one repeats, and does that 200 times to get a typical answer. For 6 and 7 characters the space is too big to simulate quickly, so it uses a formula instead. The formula is the birthday bound, named after the surprise that 23 people in a room are enough for two of them to share a birthday with even odds. It says a repeat becomes a coin flip after roughly the square root of the size of the space. Save the script as collide.py and run it.

Draw random 4-character codes until one repeats, 200 times, then compute the same point for 6 and 7 characters
python
Python
import math, random, string
 
alphabet = string.ascii_letters + string.digits          # 62 characters
rng = random.Random(9)
 
def first_collision(length):
    seen = set(); n = 0
    while True:
        n += 1
        code = "".join(rng.choices(alphabet, k=length))
        if code in seen: return n
        seen.add(code)
 
trials = sorted(first_collision(4) for _ in range(200))
print(f"4-character codes ({62**4:,} possible): first repeat after a median of {trials[100]:,} codes")
for length in (6, 7):
    space = 62 ** length
    half = math.sqrt(2 * space * math.log(2))             # birthday bound for a 50% chance of a repeat
    print(f"{length}-character codes ({space:,} possible): 50% chance of a repeat by about {half:,.0f} codes")
output
C++
4-character codes (14,776,336 possible): first repeat after a median of 4,360 codes
6-character codes (56,800,235,584 possible): 50% chance of a repeat by about 280,610 codes
7-character codes (3,521,614,606,208 possible): 50% chance of a repeat by about 2,209,524 codes

The first line is a real simulation. With 14.8 million possible codes, the first repeat came after only 4,360 codes at the median, about 0.03% of the space. The 6- and 7-character lines aren't simulated, they come from the birthday bound, and they tell the same story at a bigger scale: a service that has issued about two million 7-character codes, out of 3.5 trillion possible, has roughly even odds of having handed out a duplicate.

A rising stepped curve of the probability that two people share a birthday against the number of people, crossing 0.5 at 23 and approaching 1 by about 60
The original birthday problem: the chance that at least two people in a room share a birthday, against how many people are in it. With 365 possible birthdays the curve passes even odds at 23 people and is close to certain by 60. Random codes follow the same curve, stretched: the even-odds point lands near the square root of the number of possible codes.Image: Rajkiran g, CC BY-SA 3.0, via Wikimedia Commons

Here is the same thing drawn on one small example. Watch what happens to the link of the person who shortens the news article.

A random code repeats long before the space is full
Shortenerpicks a random codeCode tablecode → long addressAll possible 4-character codes14,776,336 of themk3Zprecipe pageQ9xAcat video14.8M codesalmost all unusedWm4dnews articleWm4dnews article+ thousands morek3Zpbank statement
Step 1. Two people have already shortened links. Their codes sit in the table, and the table is the only record of what each code means.
1 / 6

1.3Why this is the hard part

Picking a code at random looks fine and fails much sooner than the size of the space suggests. The obvious repair is to look the code up before storing it and draw again if it's taken. On a single database that lookup is cheap, but a real shortener runs on many servers, and two of them can check the same code at the same moment, both see it free, and both hand it out. The only way to stop that with a lookup is to send every new code through one central database that decides for everyone, and then that one machine is on the path of every new link: if it's slow, every link is slow, and if it's down, nobody can shorten anything. So the design question is how to make codes unique without every server asking one central machine each time. Section 6.3 gives the answer interviewers expect, Snowflake-style identifiers, and most of the follow-up questions you'd get on this prompt come out of it.

Every classic question has a part like this one, small and easy to walk past while you draw the obvious boxes. Finding it is half the interview, and the interviewer knows exactly which part they hid. That raises the next question: how does anyone check that you found it? The answer is a scoring sheet, so let's look at what's on it.

02What the interviewer is writing down

A design interview is a work sample: for forty-five minutes you're asked to do a compressed version of what the job involves. You take a vague request, turn it into requirements, and propose something that would work, while someone watches how you get there.

2.1Why companies use a structured interview

The format exists because it predicts job performance better than a chat does. Schmidt and Hunter's 1998 meta-analysis (a study that combines the results of many earlier studies) covered 85 years of research on hiring methods (Psychological Bulletin 124(2)). It rated each method by its validity, a correlation between the method's scores and later job performance, where 0 means the scores tell you nothing and 1 would mean they predict it perfectly. It put structured interviews at 0.51, against 0.38 for unstructured ones.

"Structured" means every candidate gets comparable questions, and interviewers score against written criteria instead of an overall impression. That's the rubric from the opening. It exists because impressions are less reliable than criteria.

?What does that mean for you?

It means the interviewer is filling in a sheet as you talk, and they can only score what they see or hear. A trade-off you considered silently and didn't say out loud doesn't exist on their sheet. So the first rule of the interview is to think aloud. The next question is what the sheet asks for.

2.2The axes a design answer is scored on

Companies don't publish their rubrics, but the widely used prep frameworks agree on what interviewers look for. Alex Xu's framework (ByteByteGo) lists the "ability to collaborate, to work under pressure, and to resolve ambiguity constructively" and "the ability to ask good questions". Hello Interview's delivery guide says "more senior candidates should be able to identify these places themselves and lead the discussion". Put together, they come to roughly four axes:

AxisWhat earns itWhat loses it
Problem navigationClarifying scope, naming the requirements that matter, finding the hard part earlyDesigning before asking anything; treating every feature as equal
Solution designA design that meets the stated requirements, with components that have reasons to existBoxes without purpose; over-engineering
Technical depthReal mechanisms and numbers in the deep dive: how the index, the replication or the cache behavesBuzzwords that dissolve under one follow-up question
CommunicationThinking aloud, checking in, taking a hint and using itLong silences; defending a choice after the interviewer showed a flaw

Finding the shortener's hard part, which we did in section 1, is the first row. Explaining how its codes become unique is the third.

?Why isn't "the right answer" on the list?

Because there isn't one. A news feed can be built by doing the work when someone posts (fan-out on write: copy the post into every follower's list) or when someone reads (fan-out on read: look up everyone they follow and merge). Both are defensible for some requirements. What's scored is whether you picked for a stated reason, and whether you know what your pick costs.

2.3The question behind the question

The shortener's hard part was unique codes. Every classic prompt is written around one or two parts like that, and the interviewer knows what they are. Most of your score depends on whether you find them and spend your deep-dive time there. Here are eight common prompts and what each one hides. The last column names the mechanism that answers it, and the later sections explain the ones you haven't met yet.

PromptWhat it's testingThe mechanism you'll need
URL shortenerMaking IDs unique without a central machine to ask; a read-heavy lookupSnowflake-style IDs or counters written in base 62 (section 6.3); keeping popular answers in a cache
News feed / TwitterFan-out on write versus read, and the celebrity problemPrecomputed timelines, plus a merge at read time for huge accounts (section 5.1)
Chat / messagingHolding millions of long-lived connections open; keeping messages in order within a conversationA tier of servers that only hold connections, a sequence number per conversation, tracking who is online
Rate limiterCounting requests across many servers without a bottleneckA token bucket kept in a shared store; what happens when the store fails (section 6.1)
Payments / checkoutA charge that happens exactly once over a network that drops messagesIdempotency keys, state machines, reconciliation (comparing records afterwards to catch mismatches) (section 6.4)
Typeahead / search suggestAnswering in a few tens of milliseconds at huge read ratesPrecomputed results for every prefix, tries (trees of letters), caching at the edge
Distributed cacheSplitting keys across servers, moving them when servers change, and one very popular keyConsistent hashing (a way of assigning keys to servers so that adding one moves few keys), replication, an eviction policy (what to drop when the cache is full)
Metrics / logging pipelineWrite throughput and summarising old dataAppend-only ingest, batching, downsampling (keeping fewer points for older data)

?How do you find the hard part if you don't recognise the prompt?

Ask which requirement is most expensive to meet at the stated scale. It's probably the one where a naive design does work proportional to something huge: followers per post, open connections per server, retries per failure. In the shortener it was the cost of making sure a new code hasn't been used, which grows with every code issued. Name the part out loud once you've found it: "the interesting part here is the fan-out".

Finding it early only pays off if you leave yourself the time to dig into it, and forty-five minutes goes quickly.

03Spending forty-five minutes

A candidate who draws boxes until minute thirty has nothing left for the part that's scored most heavily. Both popular frameworks therefore split the time the same way: a short scoping phase, a broad design, and most of what remains on depth.

3.1Two frameworks, one shape

PhaseXu (ByteByteGo), 45 minHello Interview
Scope and requirements3–10 minRequirements ~5 min
Entities and API(part of high-level design)Core entities ~2 min, API ~5 min, optional data flow ~5 min
High-level design10–15 min10–15 min
Deep dive10–25 min~10 min
Wrap-up3–5 min(not a separate phase)

Here's the answer as a pipeline, with what each phase should leave on the board. Two terms appear in its first step. Functional requirements say what the system does: shorten a link, follow a link. Non-functional requirements say how well it does it: how fast, how often it may be down, how much it may lose. We'll use the later phases in sections 4 to 6, so treat this as the map.

One design answer, phase by phase
●
?
Scope
~5 min
#
Numbers
only if they decide
⇄
API + data
~5 min
▦
High-level
~15 min
↧
Deep dive
~15 min
✓
Wrap-up
~3 min
Step 1. Ask who uses it, what the core actions are, and what's out of scope. Write down 3–5 functional requirements and the non-functional ones as numbers: users, requests per second, latency target, durability.
1 / 6

For the shortener, the two API calls in the third step are the whole interface: one call creates a code for a long address, and one looks a code up. The first phase, though, needs more care than it gets.

3.2Requirements: turning adjectives into numbers

"Highly available, low latency, scalable" describes every system and constrains none of them. A non-functional requirement (one about how well the system behaves, not what it does) is useful only when it's a number you could be wrong about. Several of the numbers below need a word first. p99 latency is the response time that 99 out of 100 requests beat, so it describes the slow end. Availability is the share of time the system works, and 99.9% over a month leaves about 43 minutes of downtime. Read-your-writes means a user always sees their own latest change, even if other people see it a little later.

VagueUsefulWhat it decides
"Low latency"p99 under 200 ms for readsWhether a synchronous cross-region call is allowed
"Highly available"99.9% monthly, reads onlyAbout 43 minutes of downtime a month; writes may degrade
"Scalable"100 M daily users, 10:1 read/writeWhether one database primary can take the writes
"Consistent"A user sees their own post immediately; others within 5 sRead-your-writes, not global linearisability (every reader seeing every change in one agreed order, the strictest form)
"Durable"No acknowledged payment is ever lostSynchronous replication before the acknowledgement (the copy on a second machine is written before the client is told "done")

?Why spend precious minutes on this?

Because every later decision is justified against these numbers. "I'm using async replication because the requirement is five seconds of staleness" is a design argument. "I'm using async replication" is a preference.

Once the requirements are numbers, the next phase turns them into more numbers. That's the phase the two frameworks disagree about.

04Estimation that changes a decision

Xu's framework includes back-of-the-envelope estimation early, meaning rough arithmetic with round numbers to see how big the problem is. Hello Interview calls upfront estimation "often unnecessary" and suggests telling the interviewer you'll "do math while designing when/if necessary".

Both are right about something. Arithmetic that doesn't change a decision is wasted time; arithmetic that does is the most persuasive thing you can put on a whiteboard. To see one that does, we'll borrow a second prompt, a news feed, because its numbers lead somewhere. First we need the raw material.

4.1Numbers worth carrying

Round everything. The goal is the order of magnitude.

QuantityValueSource
Seconds in a day86,400, call it 10⁵
L1 cache hit0.5 ns (Norvig); about 1.2–1.5 ns on a recent laptop CPUNorvig; chapter 02
Main memory access100 ns (Norvig); about 83 ns on a recent laptopsame
A real syscallabout 350 ns on a recent laptopchapter 07
Send 2 KB over 1 Gbps20 µsNorvig
4 KB random read, laptop NVMe, queue depth 1120.8 µschapter 09
Read 1 MB sequentially from memory250 µsNorvig
Disk seek (spinning)8 msNorvig
US to Europe and back150 msNorvig

Norvig's figures are from a "typical PC" of their time, and the others come from the experiments in chapters 02, 07 and 09 on a recent laptop. Neither is a promise about yours, but both are the right order of magnitude, which is all an estimate needs. Notice the spread: from half a nanosecond to 150 milliseconds is a factor of 300 million, so one round trip across the ocean costs as much as hundreds of millions of L1 cache hits.

A labelled cross-section of a submarine cable: a few optical fibres in petroleum jelly at the centre, surrounded by a copper tube, polycarbonate, steel wires, a water barrier and polyethylene
Cross-section of a submarine communications cable. Almost all of it is armour, insulation and water barrier around the few optical fibres in the middle, and those fibres are what the US-to-Europe row in the table measures. Light crosses the ocean in them at about two-thirds of its speed in a vacuum, and no software change makes that trip shorter.Image: Mysid, public domain, via Wikimedia Commons

4.2A worked estimate: does the feed fit?

Say the prompt is a feed for 100 million daily users, each opening the app five times a day and posting once every ten days. We divide a day's totals by the 10⁵ seconds in a day.

Timeline reads per second100M × 5 / 10⁵ s≈ 5,000/s average
Peak reads (assume 3× average)5,000 × 3≈ 15,000/s
Posts per second100M / 10 / 10⁵ s≈ 100/s
Fan-out writes if average follower count is 200100 × 200≈ 20,000 inserts/s
Post storage per year at 1 KB per post100/s × 10⁵ × 365 × 1 KB≈ 3.6 TB
Reads per post≈ 50 : 1

Two decisions fall out of it. Reads outnumber posts fifty to one, so it's worth doing work at write time to make reads cheap: the 20,000 inserts a second is a price a read-heavy system can pay. And 3.6 TB a year of posts is small enough that the storage choice is about access pattern, not volume.

A real system had almost exactly this ratio, and it learned something from it.

Predict before you read on

In 2012 Twitter served about 300,000 timeline reads a second against about 6,000 writes a second. Given that, where should the work of assembling a home timeline happen?

4.3The estimates that change designs

Each estimate is useful because of what you do when it comes out one way or the other:

EstimateIf the answer is…Then
Read/write ratioFar above 10:1Precompute, cache, fan out on write
Working set sizeFits in one machine's RAMA cache tier or even a single node may do
Write rate at peakBeyond one primary's capacityPartition the write path (chapter 22 on Redis Cluster slots is one model)
Storage growthPetabytes a yearTiering, object storage, retention policy
Latency budget vs round tripsBudget smaller than the round tripsFewer hops, colocate, or go asynchronous
Fan-out factorUnbounded (followers, recipients)Cap it, batch it, or change direction for the tail

The feed's numbers said to do the work when a post is written. Now we have to draw that, and the drawing has to be something you can follow one post through.

05The high-level design

The high-level design is where you show a working system. It should be the simplest thing that meets the functional requirements, drawn so that one request can be followed through it.

5.1Walk one request through the boxes

A box earns its place when you can say what it does to a specific request. Here's the write path of the hybrid feed from section 4.2, with one post followed through it as you'd narrate it. The post service is the first box, which stores posts and answers the app. A queue is a waiting line for jobs: the post service drops a message on it and moves on, and fan-out workers pick messages up when they can. The timeline cache keeps, for each user, a short list of the IDs of the posts they should see.

Posting to a feed with hybrid fan-out
Post servicestores postsQueuewaiting jobsFan-out workerscopy IDs into listsTimeline cacheone list of post IDs per user, up to 800Celebrity postskept apartAna's phonefollows Ben and a celebritypost 901Ben'sAna's list880, 874200 more listspost 950no fan-outtimeline901, 880, 874
Step 1. Ben has 200 followers, close to the average from the estimate. He posts, and the post service stores it durably with a time-ordered ID, 901. Ben's request can return now; the rest happens later.
1 / 7

?Why narrate a request instead of describing components?

Because it exposes gaps. Describing a "fan-out service" sounds complete. Walking a post through it forces the questions an interviewer will ask anyway: what happens when the author has 30 million followers, and does the user wait for it? The frames above answer both because we followed one post, then a second one that behaved differently.

5.2Choosing components, with reasons

The queue and the cache in that picture were choices, and every component choice is a trade-off. Each should come with a one-line reason tied to a requirement, and with the cost it brings:

ChoiceReach for it whenCost you should name
Cache in front of the databaseRead-heavy, tolerant of brief stalenessInvalidation (removing entries that have gone stale), cold starts (an empty cache after a restart sends everything to the database), thundering herd on a miss (many requests all missing at once and all hitting the database)
Queue between servicesWork can be asynchronous; absorb burstsDelivery is at-least-once (a message may arrive twice); consumers must be idempotent (safe to run twice)
Relational databaseTransactions, joins, moderate write rateScaling writes needs partitioning
Key-value or wide-column storeHuge write rates, simple access by keyNo joins; data modelled around queries
Object storageLarge blobs, cheap durabilityLatency per request in tens of ms
Read replicasScale readsReplication lag (replicas trailing the primary) breaks read-your-writes

Once the boxes are on the board, the interviewer stops listening to the whole design and picks one box. What they ask next is where most answers fall apart.

06Going deep

The deep dive is where depth is scored. The interviewer picks a component, or you do, and asks follow-ups until you reach the limit of what you know.

6.1What a probe looks like

Here's a third prompt, a rate limiter (a service that caps how many requests one user may make), a few minutes into the deep dive. Notice that each question takes the previous answer one layer down. A token bucket is the mechanism the candidate names: each user has a bucket that refills slowly with tokens, every request takes one, and an empty bucket means the request is rejected.

An interviewer probing a rate limiter
InterviewerCandidateHow do you limit per user across 50 API servers?Token bucket, state in a shared storeEvery request now hits Redis. Latency?One round trip; atomic script; local pre-checkRedis goes down. What happens?Fail open, alert, keep a local fallback
Step 1. The hard part from 2.3: counting across machines. A per-server counter lets a user through 50 times the limit.
1 / 6

?What's the interviewer looking for in a probe?

Whether your knowledge has a floor. Anyone can say "use Redis". The follow-ups test whether you know what that choice does to latency, what happens when it fails, and what you'd do instead. Running out of knowledge at roughly the fourth question is normal. Running out at the first is the signal they're checking for.

6.2Three probes every deep dive gets

You can prepare for most follow-ups because they come in three kinds. The rate limiter conversation above contained two of them: the second question was about scale, and the last was about failure.

ProbeThe questionWhat a strong answer includes
Failure"This node dies. What happens?"Detection time, who takes over, what's lost, what the user sees
Scale"Traffic grows 10×. What breaks first?"The first resource to saturate, with a number, and the fix
Correctness"Two of these happen at once. What happens?"The race (two actions interleaving), the rule it breaks (an invariant: something that must always be true, like "one code, one address"), and the mechanism that prevents it

Answer each at the level of mechanism, meaning what each machine does and in what order. "It fails over" doesn't say that. Take a database with a leader, the one machine that accepts writes, and a replica, a copy of the data on another machine. The leader sends the replica a regular "I'm alive" message, a heartbeat. A mechanism-level answer sounds like this: "The replica notices the missed heartbeats after a few seconds, a new leader is elected, and writes acknowledged by the previous leader but not yet copied are lost, unless replication was synchronous."

The shortener from section 1 is still unanswered, and it makes a good place to practise all three.

6.3Back to the shortener: unique IDs without asking anyone

Recall the problem from section 1. Random codes collide early, and checking each one before storing it only works if every server asks the same central database, which then slows down or stops every new link when it does. Handing out numbers from one central counter has the same flaw. The answer interviewers expect is to build uniqueness into the identifier itself, so that each machine can issue IDs alone and never produce one another machine could produce.

Twitter's Snowflake does this with a number cut into three fields. The top 41 bits are the time in milliseconds since a custom starting date (an epoch), the next 10 bits identify the machine, and the last 12 bits are a sequence, a counter that restarts every millisecond. That's 63 bits, so the whole ID fits in one 64-bit integer. Two machines can't produce the same ID because their machine fields differ. One machine can't repeat one because the timestamp or the sequence differs. (A shortener then writes the number in base 62, using the same letters and digits as before, to get a short code.)

A hierarchy of servers in three numbered layers below a row of reference clocks, with arrows showing each layer taking time from the one above
How machines keep time with NTP. Reference clocks at the top feed stratum 1 servers, which feed stratum 2, and so on down to ordinary machines, each correcting its own clock against the servers above it. When a clock has drifted far enough, the correction is a jump, and the jump can be backwards. The scene below shows what that does to a Snowflake generator.Image: Benjamin D. Esham, public domain, via Wikimedia Commons
A Snowflake generator issues IDs, then meets a clock that goes backwards
Machine's clockmillisecondsGenerator, machine 7time · machine · sequenceIDs issuedmust never repeatTnowlast used: noneT · 7 · 0T · 7 · 1T+1 · 7 · 0T · 7 · 0duplicateT+2 · 7 · 0
Step 1. The clock reads millisecond T. A request arrives for a new ID.
1 / 7

?Why Snowflake's layout in particular?

Because it's a compact answer to a question most shorteners and feeds hit, and every field has a reason. Twelve bits of sequence give 4,096 IDs per millisecond per machine, 10 bits of machine give up to 1,024 machines, and 41 bits of milliseconds cover 69 years from a custom epoch. The README also says what happens when the clock runs backwards: Snowflake "will refuse to generate ids" until time passes the last one it issued. That's the failure mode, and interviewers ask about it. It's also a correctness probe and a failure probe at once, so you can practise both on it.

Another approach is to hand each server a block of numbers from a shared counter and let it count through the block alone, writing them in base 62. The server still asks a central counter, but once per block instead of once per link, so a short outage of the counter goes unnoticed while servers have numbers left. That trades the clock problem for the need to keep the counter safe and never hand out the same block twice, and it's a reasonable alternative as long as you say what it costs.

6.4Making retries safe: idempotency keys

The same pattern, find the failure and build the answer into the data, solves the payments prompt. A client sends a request to charge a card and the network drops the reply. The client can't tell whether the charge happened, so it retries, and now the card may be charged twice.

The fix is an idempotency key: the client invents a unique key for each logical operation, such as one checkout, and sends the same key with every attempt. The server stores the key together with the result, in the same database transaction as the charge itself, so either both are saved or neither is. When a repeat arrives with a key the server has seen, it returns the stored result instead of charging again. Clients should also retry with exponential backoff (waiting longer after each failure) and jitter (adding some randomness to the wait), so that a recovering server isn't flattened by every client retrying at the same moment. Stripe describes this design in Designing robust and predictable APIs with idempotency.

6.5Deep-dive material, by topic

These topics come up constantly, and each is a mechanism you can explain from first principles. The last column says where this book goes deeper.

TopicThe mechanism to knowWhere it's covered
Unique IDs without coordinationTwitter's Snowflake: 41 bits of milliseconds, 10 bits of machine ID, 12 bits of sequenceSection 6.3
Exactly-once effectsClient-generated idempotency keys, as in Stripe's idempotency design, plus retries with backoff and jitterSection 6.4
Cache behaviourHit ratio, eviction, stampedes on a hot missChapter 22
Where latency comes fromQueueing near saturation; a request that waits on many servers at once is as slow as the slowest, so rare slowness becomes commonChapter 16
Why a server drops connectionsThe kernel's waiting line for new connections (accept queues), its connection-tracking table (conntrack), and the buffers each connection gets (socket buffers)Chapter 10
Sizing and autoscalingLittle's Law (section 7.2), headroom, autoscaler lagChapter 42
Network boundaries in the cloudPrivate cloud networks (VPCs), address translation (NAT), traffic between zonesChapter 33

So far every prompt has been a design question. Some interviews ask about something that already exists instead.

07Systems questions: going down the stack

Some interviews, especially for infrastructure, SRE (site reliability engineering) and backend roles, swap the design prompt for a systems question. The question is about something already built: how it works, or why it's misbehaving. There's no blank whiteboard to fill, so the skill being tested changes from drawing to walking.

7.1Two kinds of systems question

KindExampleWhat it's testing
Explain the path"What happens when you type a URL and press enter?"Whether you can walk the layers in order and go deep where asked
Debug the symptom"p99 latency doubled after a deploy; CPU is flat. Walk me through it."Method: hypotheses, the evidence that separates them, and the tools

?How deep should "what happens when you type a URL" go?

As deep as the interviewer steers. Give a complete, shallow pass first: DNS (turning the name into an address), TCP (opening the connection), TLS (encrypting it), HTTP (the request itself), the server, the response, rendering. Then offer to go deeper on one layer, or follow where they point. A complete shallow walk followed by one deep layer beats a deep first layer that never reaches the server.

7.2A debugging answer, step by step

The debugging question is a method test, and the method is the same one the deep dive rewards: narrow the space, name the evidence. Here's the shape of a strong answer to "p99 doubled after a deploy, CPU is flat". Its first step compares p99 with p50, the median response time, which describes a typical request. Three more ideas come up. Off-CPU time is time a request spends waiting, for a lock, a connection or a slow dependency, instead of running code. Little's Law says the average number of requests inside a system equals the arrival rate times the time each one stays, which tells you how big a pool of connections has to be. A USE pass is a walk through every resource (CPU, memory, disk, network, pools), checking its utilisation (how busy it is), saturation (whether work is queueing for it) and errors.

p99 doubled, CPU flat: a structured answer
●
?
Scope
which, since when
Δ
Diff
what changed
◐
Split
on-CPU vs waiting
▤
Resources
USE pass
✓
Confirm
one test
Step 1. Ask which endpoints, all hosts or some, and whether p50 moved too. p99 up with p50 flat points at waiting, not at more work per request.
1 / 5

The interviewer scores the structure more than the final guess: narrowing the space, naming the evidence, and ordering hypotheses from cheap to check to expensive.

7.3Where the depth for these lives

Each systems question is a walk down several layers of the stack, and this book has a chapter for most layers. The table only names the layers; the chapters it points to explain them:

QuestionLayers to walkChapters
What happens when you type a URL?DNS, TCP handshake, TLS, HTTP, kernel receive path, app10, 33
Why is the tail latency high?Queueing, contention, fan-out, measurement16, 41
What happens on fork() and exec()?Processes, copy-on-write, page tables, the loader06, 04, 46
Why did the container get OOM-killed?cgroups, memory accounting, page cache11, 05
Is fsync enough for durability?Page cache, flush, device caches08, 09
Why is this lock slow?Spinning, parking, convoys13, 16

Whichever kind of question you get, what counts as a good answer also depends on the level you're interviewing for.

08What changes with seniority

The same prompt is given to mid-level, senior and staff candidates. The bar moves in who drives and how far past the obvious the answer goes.

8.1The same question at three levels

Hello Interview's guide makes the key distinction: "More junior candidates can expect the interviewer to jump in here and point out places where the design could be improved. More senior candidates should be able to identify these places themselves and lead the discussion." Extending that:

Mid-levelSeniorStaff
Who drivesInterviewer steers; you respond wellYou drive; interviewer probesYou drive, and reframe the problem when it's the wrong one
DepthA working design; depth in one area when askedFinds the hard part unprompted; deep on it with numbersDeep in several areas; knows where the design will break in a year
Trade-offsKnows the optionsPicks with reasons tied to requirementsWeighs operational cost, team ownership, migration path
FailureHandles single-node failureHandles partitions (parts of the network that can't reach each other), overload, retriesHandles cascading failure and what the organisation does about it

On the shortener, a mid-level answer might be a working table and a cache, with the ID question raised by the interviewer. A senior answer raises the collision problem unprompted and brings the numbers. A staff answer might ask whether the shortener needs short codes at all for the stated use, and how existing links would move to a new scheme.

?Does "staff" mean a bigger design?

No. It usually means a more selective one. Staff answers are often smaller than senior ones, because they cut features the requirements don't need and spend the saved time on migration, operability and how the system fails.

Knowing the bar still doesn't guarantee passing it, and good engineers miss for the same few reasons again and again.

09Why good engineers fail these interviews

9.1Symptom, cause, fix

Almost every failure traces back to a section of this chapter, which makes the table below a checklist for reviewing your own practice runs:

Symptom in the interviewLikely causeFix
Interviewer keeps redirecting youYou designed before scopingAsk two or three questions and write the requirements down first
Ran out of time before the deep diveToo long on estimation or on boxesBudget by the clock: high-level done by minute 25
Deep dive stalls at the first follow-upKnowledge of names, not mechanismsStudy how one system of each kind works inside
"Why did you choose that?" and you can't sayA default, not a decisionTie every choice to a requirement, out loud
Interviewer hints and you don't take itDefending the designTreat hints as requirements you missed; adopt, and say why
Design is huge and shallowListing every component you knowCut to what the requirements need; go deep on the hard part
Silence for minutesThinking privatelyThink aloud, even when unsure; say what you're weighing

9.2Handling what you don't know

You'll hit questions past your knowledge, because the interviewer keeps asking until you do. The scored behaviour is how you handle the edge:

  • Say where your knowledge ends. "I haven't operated Cassandra, but I'd expect a write here to go to the commit log and memtable first. Is that the part you want to explore?"
  • Reason from principles. You may not know a system's exact default, but you can probably reason about what it must do and what that would cost.
  • Don't invent specifics. A made-up number or config flag is worse than "I'd measure it". Interviewers often know the real value.

Knowing the failure modes tells you what to fix. The last question is how to practise fixing it.

10How to practise

10.1A practice plan

Each step below trains one of the things the sections above said gets scored, so you can stop when you've covered the ones you're weakest at.

  1. Pick eight prompts from section 2.3 and, for each, write down the hard part and the mechanism before you design anything.
  2. Rehearse against a clock. Forty-five minutes, out loud, with the phase budget from section 3.1. Record it, or practise with someone who'll interrupt.
  3. Learn one system deeply per category: one database, one cache, one queue, one load balancer. Deep-dive answers come from knowing one real thing well, not ten things by name.
  4. Drill the three probes (failure, scale, correctness) against every design you practise.
  5. Keep a numbers sheet like section 4.1, filled in with numbers you've timed yourself where you can.
  6. Review each practice run against the four axes in section 2.2. Which one lost points?

11Summary

  1. Every prompt hides one hard part. The shortener's is making codes unique: random 4-character codes first repeated after a median of 4,360 draws out of 14.8 million possible.
  2. It's a structured work sample. Structured interviews predict job performance better than unstructured ones (0.51 against 0.38 in Schmidt and Hunter), and they're scored against a rubric.
  3. Only what you say gets scored. Think aloud, including the options you rejected.
  4. Find the hard part by asking which requirement is most expensive at scale, and name it out loud.
  5. Budget the clock. About five minutes of scope, fifteen of high-level design, and the largest block on the deep dive.
  6. Requirements are numbers. "p99 under 200 ms" constrains a design; "low latency" doesn't.
  7. Estimate only what decides something. A 50:1 read/write ratio justifies fan-out on write; "a lot of servers" justifies nothing.
  8. Walk a request through the boxes. It exposes gaps before the interviewer does, and it's how the feed's celebrity exception showed up.
  9. Deep dives get three probes: failure, scale and correctness. Answer at the level of mechanism, as with Snowflake's refusal to issue IDs when the clock steps back.
  10. Seniority changes who drives, and how selective the design is, more than how big it is.
  11. Learn why designs were made, not the designs. Interviewers change a requirement to see whether you can re-derive.

12Build this

A practice kit you'll reuse.

  • A one-page numbers sheet: Norvig's table next to the same quantities timed on your own computer (memory latency, a syscall, a loopback round trip, an SSD read), using the methods in chapters 02, 07, 09 and 10.
  • For eight prompts, a card with: the hard part, the mechanism, the key estimate, and the three probes with your answers.
  • One small implementation per card where it's cheap: a Snowflake ID generator that handles a backwards clock, a token-bucket limiter in Redis with a fail-open path, an idempotency-key table for a toy payment endpoint.
  • Three recorded forty-five-minute mock answers, reviewed against section 2.2's axes.

Start with the first implementation. Run your generator, then set the clock back by hand and watch whether it refuses, the way the Scene in section 6.3 does.

13Interview questions

beginnerDesign a URL shortener. What's the hard part?›

Generating short, unique codes without a coordination bottleneck, and serving a read-heavy workload fast. Random codes are the obvious choice and they collide early: the birthday bound puts a repeat near the square root of the space, so 4-character codes repeat after a few thousand. For IDs, use a Snowflake-style scheme (timestamp, machine ID, sequence) or pre-allocated ranges from a counter, encoded in base 62. For reads, put a cache in front of the store, since popular links are read far more than they're written. Follow-ups are usually custom aliases (a uniqueness check), expiry, and analytics without slowing the redirect.

beginnerWhy ask clarifying questions instead of starting to design?›

Because the requirements decide the design, and the prompt deliberately leaves them out. Two or three questions (scale, read/write mix, latency and consistency needs, what's out of scope) turn "design a chat app" into a problem with a checkable answer. They also score directly: resolving ambiguity is one of the things interviewers are asked to look for.

intermediateFan-out on write or fan-out on read for a news feed?›

It depends on the read/write ratio and the follower distribution. Fan-out on write makes reads one cache lookup but costs a write per follower; fan-out on read makes posting cheap but every read queries everyone you follow. With reads far outnumbering writes, as at Twitter (about 300k reads against 6k writes a second in 2012), fan out on write, except for accounts with huge followings, whose posts are merged in at read time.

intermediateHow would you make a payment API safe to retry?›

Idempotency keys. The client generates a unique key per logical operation and sends it with each attempt. The server records the key with the result in the same transaction as the effect, and on a repeat returns the stored result instead of charging again. Clients retry with exponential backoff and jitter so a recovering server isn't flattened. That's the design Stripe describes publicly.

intermediateYour rate limiter keeps its state in Redis. Redis fails. What happens?›

Decide in advance, and usually fail open: let requests through, alert, and fall back to a coarse per-server limit. The limiter exists to protect the API, so it mustn't become the API's worst dependency. Stripe's guidance is that limiter errors should "fail open" so the API stays functional. Fail closed only where letting traffic through is worse than an outage, such as a brute-force login limit.

deepWalk me through what happens when a Snowflake-style ID generator's clock goes backwards.›

IDs are time-ordered because the top bits are milliseconds since an epoch. If NTP steps the clock back, the generator could reissue timestamps it already used, and with the same machine ID and a reset sequence, produce duplicate IDs. Snowflake refuses to generate IDs until the clock passes the last timestamp it issued. The costs: a stall for the size of the step, and the need for unique machine IDs, which is its own coordination problem at deploy time.

deepHow do you answer a question at a staff level instead of a senior level?›

Same prompt, different emphasis. Drive the discussion, and be more selective: cut what the requirements don't need. Spend the time on where the design breaks under growth, how it fails and recovers, what it costs to run, and how you'd migrate to it from what exists. Weigh options by operational burden and ownership as well as by performance. Often the answer is smaller, not bigger.

14Go deeper

check yourself
What are the three probes almost every deep dive includes?›

Failure (this node dies), scale (traffic grows ten times) and correctness (two of these happen at once). Answer each with a mechanism and a number.

When should you skip a back-of-the-envelope estimate?›

When no plausible answer would change a decision. Estimation earns time when it ends in "so I'll…".

Why did Twitter stop fanning out tweets from its largest accounts?›

A tweet from an account with tens of millions of followers meant tens of millions of timeline inserts. Merging those accounts' tweets in at read time is a few extra reads per timeline instead.

Why does a structured interview use a rubric?›

So candidates are scored on the same criteria. It's a large part of why structured interviews predict job performance better than unstructured ones.

Alex Xu — A Framework for System Design Interviews (ByteByteGo)

The four-step framework, its time budget, and lists of signals and red flags. ByteByteGo.

Hello Interview — Delivery Framework

A finer-grained phase plan, the case for skipping upfront estimation, and what changes by level. hellointerview.com.

Schmidt & Hunter — The Validity and Utility of Selection Methods (1998)

The meta-analysis behind structured interviews. Psychological Bulletin 124(2).

High Scalability — The Architecture Twitter Uses to Deal with 150M Active Users

A summary of Raffi Krikorian's QCon 2012 talk: fan-out on write, 800-entry timelines in Redis, and read-time merge for celebrities. Article.

The best-documented real answer to the feed question.
Stripe — Scaling your API with rate limiters

Four kinds of limiter, token buckets in Redis, and failing open. Stripe blog.

Stripe — Designing robust and predictable APIs with idempotency

Brandur Leach, 2017: idempotency keys, backoff and jitter. Stripe blog.

Twitter Snowflake (2010)

The README explains the 64-bit layout and the backwards-clock behaviour. GitHub.

Peter Norvig — Teach Yourself Programming in Ten Years

Source of the approximate timing table most "latency numbers" lists derive from. norvig.com.

Contention, Queueing & Tail Latency

Where latency comes from under load, and why fan-out makes the tail everyone's problem. Chapter 16.

Queueing, Capacity & Scaling

Sizing a fleet and the autoscaler behaviour behind "what breaks at 10×". Chapter 42.

Performance Engineering

The method behind a good debugging answer: USE, RED and profiling. Chapter 41.

Redis Internals

Deep-dive material for the cache and rate-limiter questions. Chapter 22.