Software Engineering · Chapter 2 of 31
System design, at the level actually asked
The round that decides most senior loops. Not a memorised architecture — a sequence of defensible trade-offs.
System design is named in 73% of these postings and it is where most senior interviews are won or lost. The failure mode is memorising an architecture and reciting it regardless of the question.
The sequence that works
- Clarify before designing. What are the read and write volumes, what latency is acceptable, how consistent must it be, and what is explicitly out of scope. Five minutes here saves the round — and interviewers score it.
- Put numbers on it early. Requests per second at peak, data volume per day, storage growth in a year. An architecture with no arithmetic cannot be evaluated, and this is the most common thing separating a mid-level answer from a senior one.
- Start simple and let the requirements break it. A single service and a database is a legitimate first answer. Let scale, availability or latency force each addition, and say what forced it.
- Name the trade-off at every branch. Consistency against availability, latency against cost, simplicity against flexibility. The design is not the answer; the reasoning is.
- Then attack your own design. What happens when this component fails, when traffic is ten times, when a dependency is slow rather than down. Volunteering that is what senior sounds like.
The trade-offs worth being fluent in
| Choice | Buys you | Costs you |
|---|---|---|
| Caching | Latency and load | Staleness, and an invalidation problem that is genuinely hard |
| Async / queue | Absorbs spikes, decouples | Eventual consistency, ordering, and a new failure mode |
| Denormalising | Read speed | Write complexity and the risk of divergence |
| Sharding | Horizontal scale | Cross-shard queries, rebalancing, hot keys |
| Read replicas | Read scale, cheaply | Replication lag — read-your-own-writes breaks |
| A second datastore | Fits the access pattern | Two things to operate, and consistency between them |
The question that separates levels
“What breaks first as this grows?”
A mid-level answer describes a working system. A senior answer knows which component saturates first, roughly when, and what the next move is — and says so before being asked.
What the interviewer is actually scoring
Almost every candidate believes the system design round tests knowledge of components. It does not, past the first ten minutes. It tests whether you make decisions with stated reasons and known costs — and the most reliable way to demonstrate that is to establish numbers before you draw anything.
The five numbers to ask for, and what each unlocks
| Ask | Typical answer | What it lets you decide |
|---|---|---|
| Daily active users, and peak concurrency | 10M DAU, peak ~5% concurrent | Whether this is one database or many. Most designs never need sharding and candidates shard anyway |
| Read-to-write ratio | 100:1, or 1:1 | The single highest-leverage number. 100:1 means caching and read replicas solve it. 1:1 means neither will, and you have a genuinely hard problem |
| Payload size | 2 KB per record, or 2 MB | Decides whether this fits in memory, whether it belongs in object storage, and what your network bill looks like |
| Latency target, at which percentile | p99 under 200 ms | p50 targets are almost meaningless. The tail is where the design lives, and asking which percentile signals experience immediately |
| What is allowed to be stale, and for how long | counts can lag 60s; balances cannot | This is the consistency question in the only form that has a real answer. Ask it this way and you will get a usable number; ask 'do we need strong consistency' and you will get 'yes' |
A worked example: the design that should be boring
Prompt: design a URL shortener. It is the most-asked warm-up in the field and most candidates over-build it. Watch what the numbers do.
- 100 million new links a year at, say, 500 bytes of metadata each is 50 GB a year. Ten years of data fits on one ordinary database instance with room to spare. Say that out loud. The candidate who announces ‘this fits on one machine for a decade, so I am not going to shard it’ has just demonstrated more seniority than the one who opens with a sharding scheme.
- The read-to-write ratio is enormous — perhaps 10,000:1. That single fact means the entire read path is a cache lookup, and the database is almost never touched on the hot path. Everything else follows from it.
- The genuinely interesting question is ID generation, and it is the only part that is actually hard. A random 7-character key from a 62-character alphabet gives about 3.5 trillion possibilities — but random generation needs a uniqueness check on write, which is a read before every write. A counter encoded in base 62 avoids the check and leaks your volume to anyone who watches the keys increment. Both are correct; say which you picked and why.
- The part nobody raises unprompted, and it is a differentiator: a URL shortener is an open redirect. It will be used for phishing within a week of launch. Raising abuse handling — scanning, rate limits per account, a takedown path — moves you from 'built it' to 'has operated one'.
The three sentences that most improve a system design round
“Before I draw anything, can I get five numbers?” It converts the rest of the hour from opinion into arithmetic, and it costs two minutes.
“This fits on one machine, so I am not going to distribute it.” Choosing the boring option deliberately, and defending it, reads as senior. Reaching for a distributed system nobody asked for reads as junior no matter how well you describe it.
“Here is what breaks first, and here is how we would know.” Almost nobody volunteers the failure mode or the signal that detects it. It is the fastest available way to sound like someone who has been on call for their own design.
A fourth, if the conversation allows it: “what would we cut if we had six weeks instead of six months?” That is the staff-level move — it shows you can separate the architecture from the schedule.
The trade-offs you will be asked to defend
| Choice | Take it when | The cost you must name |
|---|---|---|
| Cache-aside | Reads dominate and staleness is tolerable | Thundering herd on a cold key, and a stale-write race unless you invalidate on write |
| Read replicas | Read-heavy and the app tolerates replication lag | Replication lag is user-visible: a user writes, reads their own data, and sees the old value. Read-your-own-writes needs routing to the primary |
| Sharding | One machine genuinely cannot hold it | Cross-shard queries and transactions become application code. Resharding is a project. Almost never needed as early as candidates propose it |
| Async queue | The work can happen after the response | You have introduced at-least-once delivery, so every consumer must be idempotent — and now you own a backlog that can grow |
| Strong consistency | Money, inventory, or anything with a legal meaning | Latency, and availability during a partition. Say which one you are giving up |
Check yourself