AlgoInsight

System Design

The 15 System Design Trade-offs I Actually Get Asked About

The strongest answer to most system design questions is 'it depends' - but only if your very next sentence is what it depends on. Here are the fifteen tensions that decide it.

By Admin2026-06-1811 min readsystem-designtrade-offsdistributed-systemsarchitectureinterview-prepscalability

A candidate once told me, flatly, "you should always use microservices." I asked why. He said "because they scale." I asked what he'd give up to get that scaling. He didn't have an answer, because in his head microservices were simply better - not a trade, just an upgrade.

That's the single most common mistake I see in system design interviews, and it's a mindset problem before it's a knowledge problem. There are no free wins in system design. Every choice that buys you something costs you something else. The job - in the interview and in production - isn't to find the "best" architecture. It's to name the trade you're making and explain why it's the right one here.

After a few hundred loops, the same handful of tensions come up again and again. Learn to recognize them and "it depends" stops being a cop-out and becomes the most senior thing you can say - as long as you immediately say what it depends on.

graph LR
    D[Any design decision] --> T1[buys you something]
    D --> T2[costs you something else]
    T1 -.the senior move is naming both.-> T2
This simple diagram makes the core point: any design decision buys you something and costs you something else, and the senior move is naming both sides of that trade rather than treating a choice as a pure upgrade.

The big four (these decide most designs)

1. Consistency vs Availability. During a network partition, you either refuse stale answers (consistent, but some requests fail) or keep answering (available, but possibly stale). This is the CAP trade-off, and it's the one I probe hardest. Payments lean consistent; activity feeds lean available.

2. Latency vs Consistency. Even with no failure, guaranteeing every read is perfectly current means coordinating across nodes, and coordination costs milliseconds. Want it fast and always-correct everywhere? You'll pay for it in infrastructure and complexity.

3. Latency vs Throughput. Throughput is how much you process per second; latency is how long any one request takes. Batching work raises throughput but makes individual requests wait. A system tuned for raw throughput often feels sluggish per-request, and vice versa.

4. Read vs Write optimization. You can make reads cheap by precomputing and caching aggressively - but then every write has to update all those copies, so writes get expensive. Or you keep writes cheap and pay to compute on read. A system can't be optimized for both; you pick based on your read/write ratio.

Interview: When I ask about read/write optimization, the answer I'm listening for starts with a question back to me: "What's the read-to-write ratio?" A social feed is ~100:1 reads, so I'll happily make writes expensive to make reads instant. A logging system is write-heavy, so I'll do the opposite. Naming the ratio before choosing is what separates senior from mid-level.


The architecture tensions

5. Monolith vs Microservices. Microservices scale teams and let services fail independently - at the cost of network calls, distributed-systems complexity, and operational overhead. A monolith is simpler and faster to build, until the team and codebase outgrow it. The honest answer is almost always "start monolith, split when the pain is real," not "microservices because scale."

6. SQL vs NoSQL. Relational databases give you strong consistency, joins, and transactions; NoSQL gives you horizontal scale and flexible schemas - usually by relaxing one of those guarantees. The question is never which is "better," it's which guarantee you can afford to give up.

7. Normalization vs Denormalization. Normalized data has no duplication and is easy to keep correct, but reads need joins. Denormalized data duplicates fields so reads are fast and join-free - at the cost of having to update the same value in many places. This is the read-vs-write trade wearing a database costume.

8. Stateful vs Stateless. Stateless services are trivial to scale and replace - any instance can handle any request. But the state has to live somewhere, so you push it into a database or cache. Stateful services can be faster but are painful to scale and recover.


The scaling tensions

9. Vertical vs Horizontal scaling. Vertical (bigger machine) is simple but has a ceiling and is a single point of failure. Horizontal (more machines) scales nearly without limit but drags in load balancing, data partitioning, and coordination. You scale up until you can't, then scale out and pay the complexity tax.

10. Strong vs Eventual consistency in caching. A cache makes reads fast but introduces a second copy of the truth that can go stale. Keeping it perfectly in sync defeats the speed benefit; letting it drift means serving old data. Cache invalidation is famously hard precisely because it's this trade with no clean answer.

11. Sync vs Async processing. Synchronous is simple and gives the user an immediate answer, but it ties up resources while waiting and couples caller to callee. Asynchronous (queues, background jobs) is resilient and absorbs spikes, but adds complexity and means the user doesn't get an instant result.

12. Push vs Pull. Push delivers data the instant it changes (great for real-time, costly to maintain connections). Pull lets clients ask when they want (simple, but either wasteful from over-polling or stale from under-polling). Notifications push; most APIs pull; the right answer depends on how fresh the data must be.


The "everything costs something" tensions

13. Performance vs Cost. You can almost always go faster by spending more - more replicas, more cache, more regions. The real engineering is hitting your latency target at a cost you can defend, not chasing speed you don't need.

14. Availability vs Cost. Each "nine" of availability costs more than the last. Going from 99.9% to 99.99% might mean multi-region redundancy that doubles your bill. The question is what an hour of downtime actually costs you - that's what sets how many nines are worth buying.

15. Simplicity vs Flexibility. A system built for every future requirement is complex, slow to build, and hard to operate. A simple system is fast to ship but may need rework later. Over-engineering for imagined scale is one of the most common - and expensive - mistakes I see, in interviews and in real codebases.

Trade-off Lean one way when… Lean the other when…
Consistency vs Availability wrong data causes harm (payments) staleness is cheap (feeds)
Read vs Write optimized reads dominate (social) writes dominate (logging)
Monolith vs Microservices small team, early stage many teams, proven scale
Vertical vs Horizontal simplicity matters, load is modest load exceeds one machine
Simplicity vs Flexibility requirements are clear genuine future variance is known

How to use these in an interview

You don't recite all fifteen. You let them work in the background as a checklist. When I push on a design - "why a queue here?", "why denormalize?" - what I'm really testing is whether you see the trade you just made. The candidates who pass don't defend their choice as obviously correct. They say something like: "I denormalized here because this is read-heavy and I'd rather pay on writes - the cost is I now have to keep these copies in sync, which I'll handle with..." Both sides, out loud, every time.

That habit - never stating a choice without naming what it costs - is the core muscle of system design, and it's exactly what we drill across System Design Fundamentals. Once you have it, the blank whiteboard stops being scary, because every question becomes the same question: what am I willing to give up, and why?


Go deeper

More articles