High-level design & the deep-dive
Draw the high-level design first — client to load balancer to service to data — then pick the one or two genuinely hard components and go deep. The HLD shows you can compose; the deep-dive shows you can engineer. Justify every box; sketch the API and data model first.
A candidate draws an elaborate diagram: twelve boxes, a service mesh, three message queues, a separate analytics pipeline. The interviewer asks one question — “why is there a queue between the API and the database?” — and the candidate freezes, because there was no reason; the queue was there because diagrams “should have” queues. Contrast a candidate who draws five boxes, every one of which they can defend in a sentence, and then says: “the genuinely hard part here is keeping the timeline fresh at 300K reads/sec — let me spend the rest of our time on exactly that.” The second candidate drew less and demonstrated more. Breadth is table stakes; the interview is won in the depth.
Two phases, two different things being tested
Most candidates treat the interview as a single activity: drawing. But when you see an interview collapse, it’s almost always because the candidate spent all their time on one phase and never reached the other.
After requirements and estimation, the design has two distinct phases, and they prove different competencies:
- The high-level design (HLD) — a simple, end-to-end picture of how a request flows through the system: client → load balancer → service(s) → data store(s), with a cache, queue, or CDN where the estimate justified one. This proves you can compose known components into a working whole. It should be fast and almost boring — the standard skeleton, specialized to this problem.
- The deep-dive — picking the one or two components that are actually hard for this problem and engineering them in detail. This proves you can engineer, not just assemble. It is where senior candidates separate from mid-level ones.
The mistake is spending the whole session on phase one — adding more and more boxes, making the HLD ever more elaborate — and never reaching phase two. A correct, simple HLD plus one deep-dive beats a sprawling HLD with no depth anywhere. The interviewer already assumes you can draw a load balancer; they are waiting to see what you do with the part that doesn’t have a standard answer.
The high-level design skeleton
Why does having a standard skeleton matter? Because it lets you move through the HLD in two or three minutes — freeing the rest of the session for the deep-dive where the interview is actually won. Most systems share a skeleton; your job is to specialize it, not reinvent it. The default flow:
client → DNS/CDN → load balancer → API/service tier → data tier
│
cache · queue (where justified)- Client → CDN/DNS: static assets and geo-routing live at the edge (the traffic unit).
- Load balancer: spreads requests across the stateless service tier (the traffic unit). It exists because the estimate said one box can’t serve the QPS.
- Service tier: stateless app servers, scaled horizontally (the scalability unit). Stateless so any node serves any request.
- Data tier: the database(s) the access patterns chose (the requirements lesson). Sharded if the write estimate demanded it.
- Cache / queue / CDN: added only when a number justified them — a cache because reads ≫ writes, a queue because a write path needs to be async, a CDN because egress bandwidth was large.
Draw this in a couple of minutes, narrating why each box is there in terms of a requirement or an estimate. The narration is the point: a box without a justification is a liability, not an asset.
▸Why this works
Why keep the HLD deliberately simple, even sparse? Because every box is a claim you must defend, and an unjustified box is the fastest way to lose credibility. The interviewer’s job is to probe: “why is that there?”, “what happens if it fails?”, “what does it cost?”. A queue you added for decoration becomes a trap the moment they ask what it buys you. Worse, extra components inflate the failure surface — more things to fail, more consistency boundaries to reason about — which is the over-engineering failure from the requirements lesson made visual. Start with the minimum skeleton that meets the requirements, and add a component only when you can name the specific number or failure mode that demands it. Simplicity is not a lack of sophistication; it is the senior signal that you add complexity only where it pays.
Sketch the API and the data model
Before or alongside the HLD, sketch two artifacts that ground the design in something concrete:
The API. A handful of endpoints that realize the functional requirements — the verbs from the requirements lesson made into calls. For a link shortener:
POST /links {url} → {shortCode}
GET /{shortCode} → 302 redirect to url
GET /links/{shortCode}/stats → {clicks, ...}The API forces you to confront the read/write split, what’s idempotent, and what the response shape is — and it gives the interviewer a concrete contract to push on.
The data model. The core entities (from requirements) as tables/collections with their keys, and — crucially — the partition/shard key if you’re sharding (the data-distribution unit). The shard key is the highest-leverage data decision: choose it to match the dominant access pattern so that the common query hits one shard, and to spread load so no shard is hot.
links: short_code (PK) url created_at owner_id — shard by short_code (point lookups)
clicks: short_code ts ... (append-heavy, time-series) — shard by short_code, time-bucketedThese two sketches turn a hand-wavy box diagram into a design with an actual contract and an actual schema — and they surface the hard parts (a bad shard key, a missing index, a chatty API) before the deep-dive.
Choosing the deep-dive: where the difficulty lives
The deep-dive is the heart of the interview, and choosing what to dive into is itself a senior skill. Pick the component where the problem is genuinely hard — usually the one your estimate flagged or the one the access patterns made awkward:
- A hot read path at 300K reads/sec → deep-dive the cache and fan-out strategy (the caching unit).
- A write rate past a single primary → deep-dive the sharding scheme and the shard key (the data-distribution unit).
- A strong-consistency requirement on a distributed write → deep-dive replication and the CAP/PACELC trade.
- A fan-out like a celebrity timeline → deep-dive the fan-out-on-write vs fan-out-on-read decision and the hybrid.
Then go deep: the data structure, the failure modes, the edge cases, the numbers. The deep-dive is where you show you’ve actually built systems — you discuss the hot-key problem, the thundering herd on cache miss, the rebalancing cost when a shard splits. Announce the choice out loud (“the interesting part is X, I’ll focus there”) so the interviewer can redirect if they wanted a different component — and so they know you can tell the hard part from the easy part.
▸Common mistake
The deep-dive mistake is going broad instead of deep — touching ten components for thirty seconds each instead of one component for ten minutes. It feels safer (you cover more ground) but it reads as shallow: you never demonstrate that you can engineer anything, only that you can name things. The same instinct produces the “and we’d add monitoring, and a CI pipeline, and rate limiting, and…” rattle near the end — true but generic, and it shows when you’ve run out of things to say about the actual problem. The fix: pick the hard component, and keep going deeper until the interviewer stops you. Depth on the right component is the single strongest signal you can send; a tour of buzzwords is the weakest.
You've drawn a clean five-box HLD with 30 minutes left. What is the highest-value way to spend the remaining time?
The interviewer asks 'why is there a message queue between your API and the database?' What does a strong answer look like?
The high-level design proves you can _______ known components into a working whole, while the deep-dive proves you can engineer the one or two parts that are genuinely hard — and the interview is won in the second, because breadth is assumed and depth is the differentiator.
- 01What does the high-level design prove, and what is its skeleton?
- 02Why sketch the API and data model, and what's the highest-leverage data decision?
- 03How do you choose the deep-dive, and what's the failure mode?
After requirements and estimation, the design splits into two phases that test different things. The high-level design proves you can compose: draw the simple end-to-end skeleton — client → DNS/CDN → load balancer → stateless service tier → data tier, with a cache, queue, or CDN added only where a number or failure mode justified it — and narrate why each box exists, because an unjustified box is a liability and extra boxes inflate the failure surface. Ground it with two sketches: the API (the functional verbs as endpoints, exposing the read/write split and idempotency) and the data model (core entities as tables with keys, and the all-important shard key chosen to match the dominant access pattern and spread load). Then comes the part that wins the interview: the deep-dive. Pick the one or two components that are genuinely hard — the hot read path, the sharding scheme, a strong-consistency write, a celebrity fan-out — announce the choice, and go deep on data structures, failure modes, hot keys, and numbers. Breadth is table stakes; depth is the differentiator — a correct simple HLD plus one real deep-dive beats a sprawling diagram with no depth anywhere, and a tour of buzzwords near the end is the weakest signal you can send. Now when you finish drawing the HLD, ask: which one box here is genuinely hard? Then go deep on exactly that, and don’t stop until the interviewer stops you.
Practice
Start at the top. Tasks go easiest → hardest: recall a fact, apply it to a case, then a senior-level stretch. Open one, attempt it, then reveal.
Something unclear?
Ask a question about this lesson. Questions are anonymous and go straight to the author to make the lesson better.
Apply this
Put this lesson to work on a real build.