On Monday I sat a Google Forward-Deployed-Engineer system-design round, and I did not pass. I knew the components — caches, queues, shards, load balancers. What I didn't do, under pressure, was the one thing that separates an engineer from an architect. So I spent the week rebuilding the skill from the ground up. This is what I found, organized the way I wish I'd walked in knowing it.
There's a popular post making the rounds — "These 15 articles will turn you from engineer to architect" — with links to Instagram's design, Netflix's architecture, caching, Kafka, and the rest. They're good articles. But reading fifteen blueprints doesn't make you an architect any more than reading fifteen recipes makes you a chef. The blueprints are the what. The interview tests the how — and the how is a single habit.
The one habit: name what you're allowed to give up
An engineer, handed "design Instagram," reaches for a familiar box and rationalizes backward. An architect asks a different first question: what am I allowed to sacrifice? Every real system is a negotiation among things you cannot fully have at once — and the famous one has a name.
CAP is the whole mindset in three letters. When the network partitions (and at scale it will), you get to keep either consistency or availability for that data — never both. A bank balance keeps consistency and refuses the write; a "likes" counter keeps availability and reconciles later. The architect says which one they're sacrificing out loud, and why. That sentence — "for this data I'll trade consistency for availability because a stale like is fine but a rejected payment isn't" — is the sound of the job.
Fifteen blueprints are the vocabulary. Trade-offs are the grammar. You can't speak the language by memorizing more words.
The architect's loop — a method you can run under pressure
Here's the failure I actually made: I jumped to boxes-and-arrows before establishing the numbers that make one architecture correct and another wasteful. So I turned the habit into a five-step loop I can run out loud in any interview. It doubles as the outline for every answer.
The architect's loop. Blue steps are where I used to skip straight to Sketch. The interview grades you on Constrain, Estimate, Stress, and Evolve — the parts that show judgment, not recall.
The magic is step 2. Back-of-envelope numbers gate every later choice. Daily active users × actions × payload = your write QPS. Reads are usually 10–1000× writes. Storage is data-per-day × retention. Without those, you cannot justify a cache, a shard count, or a queue — you can only guess, and an interviewer can smell a guess. With them, one architecture becomes obviously correct and another obviously wasteful, and you get to say why.
The vocabulary, re-grouped by the decision it settles
Now the fifteen topics stop being a reading list and become four groups of decisions. For each, the only thing worth memorizing is the non-obvious call — the one a smart engineer gets wrong.
Group 1 — the data plane (where state lives)
| Topic | The non-obvious call |
|---|---|
| Database choice | Pick by access pattern, not hype: model the hot query first, then choose the store that makes it O(1). SQL for ACID + relations; wide-column for massive-write feeds; the shard key exists to keep the hot query on one shard. |
| Caching | The hard part isn't speed, it's invalidation. TTL is the pragmatic default; the trap is the thundering herd on a cold/expired key — fix with request coalescing + stale-while-revalidate. cache-aside is the common write policy. |
| Data structures | They map to the storage medium: B-trees minimize disk seeks (SQL indexes); LSM-trees favor writes (Cassandra); consistent-hashing rings move minimal data when a node joins/leaves; bloom filters cheaply skip lookups that would miss. |
Group 2 — the front door & the contract
| Topic | The non-obvious call |
|---|---|
| Load balancer vs reverse proxy | Different questions. LB answers "too much traffic for one box" (spread across identical backends). Reverse proxy answers "I need a smart front door" (TLS, routing, buffering slow clients off the app) — it can front a single service. Most gateways are both. |
| REST / APIs | Statelessness is the point: each request carries its own context, so any server can handle it — the property that lets you scale horizontally behind an LB. Idempotency is what makes retries safe in a distributed system. Reach for gRPC (internal, low-latency, streaming) or GraphQL (client-shaped payloads) when REST's uniformity costs you. |
Group 3 — the async backbone (decoupling in time)
| Topic | The non-obvious call |
|---|---|
| Kafka / queues | A replayable log decouples producers from consumers in time and rate. Ordering is per-partition, not global — choose the partition key to preserve the order you actually need. Your real health metric is consumer lag, not throughput. |
| Microservices | The driver is organizational, not technical (Conway's law — teams deploying independently). You trade an in-process call for a network hop that fails, buying discovery, retries, circuit breakers, tracing, and sagas instead of distributed transactions. Contrarian truth: most systems should start as a well-structured monolith. |
| Architectural patterns | Each trades coupling for flexibility, or consistency for scale: event-driven (decoupled, eventually consistent), CQRS (split read/write models when their loads diverge), strangler-fig (migrate a monolith incrementally). Naming the pattern isn't the skill — knowing which constraint it relieves is. |
Group 4 — the two case studies (where a uniform strategy breaks)
Instagram and Netflix are famous because each teaches one sharp lesson about the tail of a distribution.
Instagram = hybrid fan-out. A uniform strategy breaks on the tail: push is O(1) reads but explodes for celebrities; pull is cheap writes but slow reads. The answer is both, chosen per account. Spotting when a uniform rule fails on the tail is the whole test.
Netflix teaches the opposite split: separate the massive, cacheable data plane (video pre-encoded into many bitrates, pushed to CDN edges near ISPs) from the small, dynamic control plane (auth, recommendations — microservices in the cloud). And it treats failure as normal: chaos engineering deliberately kills instances to prove the system survives. The architect's takeaway — design for failure as the default case, and move bytes close to users.
The closing move I forgot to make
Here's what I now do that I didn't on Monday. After the happy-path sketch, I walk the failure modes out loud: what happens when this node dies, this queue backs up, this cache goes cold, this shard runs hot? Then I name the bottleneck and the next scaling lever. A design without its failure story is an engineer's answer. Naming the bottleneck and how you'd evolve past it — that's the architect's, and it's the part that gets graded.
The whole method in one breath
Constrain the problem, estimate the numbers, sketch the path those numbers demand, stress it against failure, and evolve — naming the bottleneck and the next lever. State every trade-off out loud. That's it. That's the difference between knowing the fifteen articles and being the person who can design the sixteenth.
I failed a system-design round on Monday. By Friday it had become a framework — and, honestly, I understand this material better now than if I'd passed. Turning the failure into something I could teach is what made it stick. If you're prepping too: don't read the fifteen articles for the answers. Read them for the trade-offs, and practice saying which one you're choosing, out loud, every single time.
Written after a Google FDE system-design round I didn't pass, digesting the "15 articles, engineer → architect" reading list into the one habit underneath them. If it helps you walk in calmer than I did, it did its job. — Paul