Common System Design Tradeoffs
The Nature of Tradeoffs
Every system design decision involves giving something up to get something else. There is no universally "right" answer — only answers that are better or worse for a specific set of requirements. Recognizing this is the first step to thinking like a senior engineer.
Consistency vs Availability (CAP Theorem in Practice)
CAP Theorem: In a distributed system, you can only guarantee two of three:
- Consistency: Every read receives the most recent write
- Availability: Every request receives a response (non-error)
- Partition Tolerance: System continues operating despite network partitions
Since network partitions are unavoidable in distributed systems, the real choice is between consistency and availability during a partition.
Choose consistency when correctness is paramount:
- Banking: You MUST NOT show a stale balance (double spending risk)
- Inventory: Overselling a product is worse than a temporary error
- Medical records: Stale data can be dangerous
Choose availability when uptime matters more:
- Social media feed: Showing slightly old posts is fine; downtime is not
- CDN: Serving cached content is acceptable even if origin is down
- DNS: Stale resolution is better than NXDOMAIN
Real-world: Most systems use eventual consistency — they provide strong consistency for critical paths (payments) and eventual consistency for less critical ones (feed, analytics).
Latency vs Throughput
Latency: Time to complete a single request (p99 = 200ms)
Throughput: Number of requests completed per unit time (10K req/sec)
These often conflict:
| Optimization | Latency Impact | Throughput Impact |
|---|---|---|
| Larger batch sizes | Increases (wait for batch) | Increases (amortize overhead) |
| More caching | Decreases (cache hit) | Increases (fewer DB queries) |
| Connection pooling | Decreases (reuse connections) | Increases (fewer handshakes) |
| Read replicas | Decreases (closer reads) | Increases (more read capacity) |
Design implication: If your SLA requires p99 < 200ms, you cannot batch writes. If you need 100K writes/sec, batching is essential.
Normalization vs Denormalization
Normalized (3NF): Data stored once, referenced by ID
- Pro: No data duplication, updates are atomic
- Con: JOINs are expensive at scale
Denormalized: Data duplicated across tables/services
- Pro: Reads are fast (no JOINs), independent scaling
- Con: Updates are complex, storage costs increase
When to denormalize:
- Read-heavy workloads (>90% reads)
- Data that is read together is stored together
- When JOINs become the bottleneck
Example: In a social network, the user's name is stored with every post (denormalized) because you always display name + post together. Updating the name requires a background job to propagate the change.
Sync vs Async Processing
Synchronous: Client waits for the full operation to complete
Client → Service A → Service B → Service C → Response to Client
(blocks for entire duration)
Asynchronous: Client gets an immediate acknowledgment; processing happens later
Client → Service A → Queue → Response to Client (immediate)
→ Worker → Service B → Service C
| Aspect | Sync | Async |
|---|---|---|
| Latency | Higher (waits for all steps) | Lower (immediate ack) |
| Reliability | Lower (one failure breaks chain) | Higher (retries via queue) |
| Complexity | Lower | Higher (eventual consistency) |
| Use case | Checkout, login, searches | Email sending, analytics, notifications |
Monolith vs Microservices
Monolith: Single codebase, single deployment unit
- Pro: Simple to develop, test, deploy, debug
- Con: Scaling requires scaling entire app, tight coupling
Microservices: Independent services communicating over network
- Pro: Independent scaling, deployment, technology choice
- Con: Network complexity, distributed transactions, operational overhead
When to choose monolith: Startups, small teams, when domain is not well understood
When to choose microservices: Large teams, clear domain boundaries, different scaling needs per component
SQL vs NoSQL
| Factor | SQL | NoSQL |
|---|---|---|
| Schema | Rigid, predefined | Flexible, schema-on-read |
| ACID | Full support | Varies (many are BASE) |
| Scaling | Vertical (bigger box) | Horizontal (more boxes) |
| JOINs | Native | Expensive or impossible |
| Best for | Complex queries, transactions | High volume, simple access patterns |
SQL examples: PostgreSQL, MySQL, Aurora
NoSQL examples: DynamoDB (key-value), MongoDB (document), Cassandra (wide-column), Neo4j (graph)
Push vs Pull Models
Push: Producer sends data to consumer
- Pro: Low latency, consumer doesn't poll
- Con: Consumer must handle backpressure
- Example: WebSocket notifications, webhooks
Pull: Consumer requests data from producer
- Pro: Consumer controls rate, simpler error handling
- Con: Higher latency (polling interval), wasted requests
- Example: REST API polling, log shipping
Pre-computation vs Real-time Computation
Pre-computation: Compute results ahead of time, store them
- Pro: Reads are instant (lookup from cache/table)
- Con: Stale data, expensive writes
- Example: Twitter's timeline (precomputed fan-out)
Real-time computation: Compute on every request
- Pro: Always fresh data
- Con: Slower reads, more compute cost
- Example: Google search results (computed per query)
Hybrid approach: Pre-compute most cases, fall back to real-time for edge cases.
Decision Framework
Step 1: Clarify Requirements
Before evaluating tradeoffs, understand what matters:
- Functional requirements: What must the system do?
- Non-functional requirements: What qualities must it have?
- Scale: 1K users? 1M? 1B?
- Latency: Real-time (<100ms)? Near-real-time (<1s)? Batch (minutes)?
- Availability: 99.9%? 99.99%? 99.999%?
- Consistency: Strong? Eventual?
- Cost: Budget constraints?
Step 2: Identify the Decision Points
For each major component, identify what you're choosing between:
Database: SQL vs NoSQL?
Communication: Sync vs Async?
Caching: Pre-compute vs On-demand?
Architecture: Monolith vs Microservices?
Deployment: Single region vs Multi-region?
Step 3: Map Requirements to Options
Create a decision matrix:
| Option | Scale | Latency | Consistency | Complexity | Cost |
|---|---|---|---|---|---|
| PostgreSQL | Medium | Low (local) | Strong | Low | Low |
| DynamoDB | High | Low | Eventual | Medium | Pay-per-use |
| Cassandra | Very High | Low | Eventual | High | High |
Step 4: Choose and Justify
Pick the option that best fits your specific requirements. The key insight: there is no universally best option.
Decision template:
"I'm choosing [option] because [primary requirement] is most important. This gives us [benefit] at the cost of [tradeoff]. For our use case, [tradeoff] is acceptable because [reason]."
Step 5: Identify Mitigations
Every tradeoff has mitigations:
- Eventual consistency → Use CRDTs or version vectors
- High latency → Add caching layer
- Complexity → Invest in observability and documentation
- Cost → Optimize with reserved capacity or spot instances
Justifying Your Choices
The Interview Framework
In an interview, you're evaluated not just on what you choose, but on how you reason about it. Use this structure:
- State the options: "We could use X or Y"
- Identify the tradeoff: "X gives us A but costs B. Y gives us C but costs D."
- Connect to requirements: "Given our requirement for [R], [option] is better because..."
- Acknowledge the cost: "The tradeoff is [cost], which we mitigate by [mitigation]"
Example: Designing Twitter's Timeline
Tradeoff: Fan-out on write vs Fan-out on read
Fan-out on write (pre-compute):
- When a user tweets, push it to all followers' timelines
- Reads are instant (lookup precomputed list)
- Writes are expensive (celebrity with 100M followers = 100M writes)
- Storage: O(followers × tweets) = massive
Fan-out on read (compute on demand):
- When user loads timeline, fetch all followed users' recent tweets and merge
- Reads are expensive (merge from many sources)
- Writes are cheap (just store the tweet)
- Storage: O(tweets) = manageable
Twitter's hybrid approach:
- For regular users (<10K followers): Fan-out on write
- For celebrities (>10K followers): Fan-out on read (assembled at read time)
- This balances read and write costs
Interview answer:
"I'd use a hybrid approach. For 99% of users who have fewer than 10K followers, I'd fan-out on write — push each tweet to all followers' timeline caches. This makes reads O(1). For the 1% of celebrity accounts, I'd fan-out on read — at read time, merge the celebrity's recent tweets into the timeline. This avoids the write amplification problem where a single tweet from a celebrity would require 100M writes. The tradeoff is slightly higher read latency for users following celebrities, but this is acceptable because celebrities are a small fraction of the user base."
Common Interview Tradeoff Questions
| Question | Key Tradeoff |
|---|---|
| How do you scale a database? | Vertical (simple, limited) vs Horizontal (complex, unlimited) |
| How do you handle failures? | Fail-fast (fast recovery, user impact) vs Fail-safe (slow recovery, no data loss) |
| How do you design a cache? | Cache-aside (manual, consistent) vs Write-through (automatic, stale risk) |
| How do you handle traffic spikes? | Over-provision (waste) vs Auto-scale (delay, complexity) |
Anti-patterns to Avoid
- "It depends" without explanation: Always follow up with WHY it depends
- Choosing without reasoning: Show your thought process
- Ignoring costs: Every choice has a cost — acknowledge it
- Pretending there's a perfect answer: Embrace the tradeoff
Closing Statement Template
Always end your design with: "In terms of future improvements, we could [X] to address [tradeoff]. For the initial design, I focused on [primary requirement] because [reason]."
Practice Problems
Design a scalable Tradeoffs system. Cover high-level architecture, data model, and API design.
Solution
// Complete system design:
// - Functional + Non-functional requirements
// - Capacity estimation
// - Data model (SQL/NoSQL choice)
// - API endpoints
// - Component architecture
// - Scaling strategy
// - Monitoring & reliabilityHow would you scale Tradeoffs to handle 10x the current load? Identify bottlenecks and solutions.
Solution
// Scaling approach:
// 1. Load balancing
// 2. Database sharding/replication
// 3. Cache layer (Redis)
// 4. CDN for static assets
// 5. Async processing (queues)
// 6. Microservices decompositionAnalyze potential failure modes for Tradeoffs and design mitigation strategies.
Solution
// Failure mitigation:
// 1. Redundancy (multi-AZ)
// 2. Circuit breakers
// 3. Retry with backoff
// 4. Dead letter queues
// 5. Health checks
// 6. Graceful degradationQuiz
1. According to CAP theorem, in a distributed system with network partitions, you must choose between:
2. When would you choose eventual consistency over strong consistency?
3. What is the main tradeoff of denormalizing a database?
4. In Twitter's timeline design, why is a hybrid fan-out approach used instead of pure fan-out on write?
5. What is the tradeoff between sync and async processing?
Flashcards
Question
What does CAP theorem state?
Click to reveal answer
Answer
In a distributed system with network partitions, you can guarantee either Consistency or Availability, but not both. Partition Tolerance is unavoidable in distributed systems.
Question
When to choose SQL vs NoSQL?
Click to reveal answer
Answer
SQL: Complex queries, JOINs, ACID transactions, rigid schema. NoSQL: High scale, flexible schema, simple access patterns, horizontal scaling.
Question
Fan-out on write vs fan-out on read?
Click to reveal answer
Answer
Fan-out on write: Push data to all consumers at write time (fast reads, expensive writes). Fan-out on read: Compute at read time (fast writes, expensive reads). Hybrid: fan-out on write for regular users, on read for high-fanout accounts.
Question
Sync vs async processing?
Click to reveal answer
Answer
Sync: Immediate feedback, simpler, less resilient (one failure breaks chain). Async: Immediate ack, more resilient (queue retries), eventual consistency, more complex.
Question
Normalization vs denormalization?
Click to reveal answer
Answer
Normalized: No duplication, updates are atomic, expensive JOINs. Denormalized: Data duplicated, fast reads, complex updates, more storage.
Question
How to justify a tradeoff in an interview?
Click to reveal answer
Answer
1) State the options. 2) Identify the tradeoff (what you gain vs what you lose). 3) Connect to requirements (why this option fits). 4) Acknowledge the cost and mention mitigation.
Question
Pre-computation vs real-time computation?
Click to reveal answer
Answer
Pre-computation: Compute ahead of time, store results (instant reads, stale data). Real-time: Compute per request (always fresh, slower reads). Hybrid: pre-compute common cases, real-time for edge cases.
Revision Notes
Key Takeaways
- 1.Every design decision involves a tradeoff — there is no universally right answer
- 2.CAP theorem forces a choice between consistency and availability during partitions
- 3.Latency and throughput often conflict — understand your SLA before optimizing
- 4.Denormalization trades update complexity for read performance
- 5.Sync vs async is about resilience vs immediate feedback
- 6.Start monolith, split to microservices when you have clear domain boundaries and team scale
- 7.Always connect your choice to specific requirements, not general preferences
- 8.Acknowledge the cost of your choice and mention mitigation strategies
Interview Tips
- •When presenting options, always say: 'We could do X or Y. X gives us [benefit] at the cost of [tradeoff]. Given our requirement for [R], I'd choose X because [reason].'
- •Never say 'it depends' without following up with what it depends on and why
- •For Twitter's timeline, always mention the hybrid fan-out approach — it's a classic example
- •When choosing SQL vs NoSQL, tie it to your access patterns: 'We need complex JOINs and ACID, so SQL'
- •End every design with: 'In the future, we could improve [X] to address [tradeoff]'
- •If stuck, ask yourself: 'What is the most important requirement?' and optimize for that
Cheat Sheet
System Design Tradeoffs Cheat Sheet
CAP Theorem:
- Partition tolerance is unavoidable
- Choose: Consistency vs Availability during partitions
- Most systems: Eventual consistency with strong consistency for critical paths
Latency vs Throughput:
- Batch processing: Higher throughput, higher latency
- Streaming: Lower latency, lower throughput per batch
Normalization vs Denormalization:
- Normalized: Consistent, expensive reads (JOINs)
- Denormalized: Fast reads, complex updates
Sync vs Async:
- Sync: Immediate feedback, less resilient
- Async: Immediate ack, eventual consistency, more resilient
Monolith vs Microservices:
- Monolith: Simple, scale as unit, tight coupling
- Microservices: Independent scale/deploy, network complexity
SQL vs NoSQL:
- SQL: ACID, JOINs, vertical scaling
- NoSQL: Flexible schema, horizontal scaling, limited queries
Push vs Pull:
- Push: Low latency, backpressure issues
- Pull: Consumer control, polling overhead
Pre-compute vs Real-time:
- Pre-compute: Instant reads, stale data risk
- Real-time: Fresh data, slower reads
Interview Framework:
- State options
- Identify tradeoff (gain vs cost)
- Connect to requirements
- Acknowledge cost + mitigation