# System Design Tradeoffs
Every architecture choice buys one property by spending another: latency, correctness, availability, cost, simplicity, operability, or flexibility.
Tradeoffs are not excuses for vague answers. They are how you connect a design choice to [[wiki/non-functional-requirements|non-functional targets]] and explain what risk you are accepting.
## How To State One
Use this shape: **choose X over Y because requirement Z matters more on this path; mitigate the downside with W.**
For example: choose asynchronous indexing over synchronous indexing because write latency matters more than search freshness. Mitigate with a freshness SLO, retry queue, and user-visible "processing" state.
## Common Tradeoffs
- Cache speed vs freshness.
- Async throughput vs user-visible delay.
- Strong consistency vs latency/availability.
- Denormalization vs write complexity.
- Microservices autonomy vs operational overhead.
- Detailed observability vs cost/cardinality.
| Choice | Buys | Spends | Use when |
|---|---|---|---|
| Cache reads | Lower latency, lower database load | Staleness, invalidation complexity | Reads dominate and stale data is acceptable |
| Queue writes | Higher throughput, smoother spikes | Delayed completion, retry semantics | Work can finish after user acknowledgment |
| Denormalize data | Faster reads, simpler queries | Harder writes, repair jobs | Read paths are hot and shape is stable |
| Strong transactions | Simpler correctness model | Lower availability, higher contention | Invariants must not be violated |
| Split service | Team autonomy, independent scaling | Network failures, deploy complexity | Ownership boundary is real and durable |
| Multi-region active-active | Regional resilience, lower local latency | Conflict handling, cost | Users need regional survival and budget allows it |
## Concrete Examples
For a social feed, accepting eventual consistency may be fine. A like count can lag by seconds if the feed stays fast and resilient. The tradeoff should be named, then bounded with freshness and repair guarantees.
For a bank transfer, the same answer is wrong. The system should spend latency and availability to preserve a correctness invariant: money is not created, lost, or double-spent.
For an analytics dashboard, precomputation can be a strong choice. It makes reads cheap and predictable, but requires clear definitions for freshness, backfills, and late-arriving events.
## Failure Modes
- Listing tradeoffs without choosing one.
- Choosing the most complex option because it sounds scalable.
- Optimizing a rare path while harming the common path.
- Ignoring who pays the operational cost after launch.
- Treating reversibility as free; migrations often become the real cost.
## Decision Checklist
- Which user path or invariant is most important?
- What metric proves the chosen side is working?
- What breaks when the sacrificed property gets worse?
- Is the decision reversible with a migration, or effectively permanent?
- Who owns incidents caused by this choice?
## Pro Tip
State the tradeoff explicitly. A design answer without tradeoffs is usually a feature list, not architecture.
Senior answers are specific. "Use cache for speed" is weak. "Cache product catalog reads for 5 minutes because price changes are rare, but bypass cache for checkout pricing" is a design decision.