Why patterns matter more, not less
A model can produce a correct-looking checkout service in thirty seconds. What it cannot do for you is decide what the business should do when the payment gateway returns success, the inventory service times out, and the customer refreshes the page twice. That decision is architecture, and it is made of trade-offs someone has to own.
Every pattern below exists because a distributed system fails in a way a single process never does: partially. Half the work committed. A response that never arrived but whose side effect did. A dependency that is not down, merely slow — which is worse. Patterns are the compressed, named answers to those situations.
The map: which pattern fixes what
1. Saga — transactions that span services
Order → Payment → Inventory → Shipping cannot sit inside one ACID transaction once each step owns its own database. A saga replaces the single transaction with a sequence of local transactions, each paired with a compensating action that semantically undoes it.
- Payment captured, inventory reservation fails → issue a refund, not a rollback.
- Compensations are business operations, so they are visible and auditable.
- Choreography for short flows, orchestration once you need visibility.
2. Circuit Breaker — stop calling what is already broken
The recommendation service gets slow. Checkout threads block waiting on it. The pool exhausts. Now checkout is down because of a feature nobody would have paid for. A circuit breaker counts failures, opens after a threshold, fails fast while open, and probes with a half-open trickle before restoring traffic.
3. Bulkhead — isolate the blast radius
Named after ship compartments: one flooded section does not sink the vessel. Give payments, search and recommendations separate thread pools, connection pools and queues so a runaway feature can only exhaust its own allocation.
4. Outbox — the database and the broker agree
Saving the order and publishing OrderPlaced are two systems and therefore two failure points. Write the event into an outbox table inside the same transaction as the order, then let a relay publish it. The commit is atomic; delivery is at-least-once and eventually consistent.
5. Idempotency — retries stop being dangerous
A timeout is not a failure, it is an unknown. Clients retry unknowns. Without an idempotency key the customer is charged twice; with one, the second request returns the stored result of the first. Every payment, booking and order API needs this before it needs anything else.
6. CQRS — reads and writes are different products
A million product searches and ten thousand orders have almost nothing in common: different shapes, different consistency needs, different scaling curves. CQRS lets orders stay normalised in PostgreSQL while search runs on Elasticsearch and analytics on a columnar store, fed by events.
7. Cache-Aside — the default caching strategy
Read from Redis; on a miss, read the database, populate the cache, return. Simple, resilient to cache loss, and honest about the real cost: you now own invalidation and a window of staleness. Bound it with TTLs and explicit deletion on write.
8. API Gateway — one front door
Without one, every client must know your service topology, and cross-cutting concerns get reimplemented ten times. The gateway centralises TLS, authentication, routing, rate limiting, aggregation and observability — and becomes a component you must scale and keep thin.
9. Strangler Fig — replacing the monolith without a rewrite
Route one path at a time to a new service behind a façade. /products moves, everything else stays. The monolith shrinks until it is retired. Big-bang rewrites fail because they require you to be right about everything at once.
10. Event-Driven Architecture — publish facts, not commands
OrderPlaced fans out to inventory, shipping, notifications and analytics without the order service knowing any of them exist. You buy loose coupling and independent scaling; you pay in eventual consistency, duplicate delivery, ordering guarantees and replay tooling.
How to use these in an interview
- State the failure mode first: “payment can succeed while inventory fails.”
- Name the pattern as the response, not as decoration.
- Say the cost out loud — every pattern here buys safety with complexity or latency.
- Describe how you would observe it: breaker state, outbox lag, saga compensations.
| Pattern | Buys you | Costs you |
|---|---|---|
| Saga | Cross-service consistency | Compensation logic, no isolation |
| Circuit Breaker | Fast failure, recovery | Tuning, false trips |
| Bulkhead | Contained blast radius | Lower peak utilisation |
| Outbox | Reliable event publishing | Relay, dedup, lag |
| Idempotency | Safe retries | Key storage and lifetime |
| CQRS | Independent read scaling | Two models, sync lag |
| Cache-Aside | Latency and DB relief | Staleness, invalidation |
| API Gateway | Central cross-cutting concerns | Single choke point |
| Strangler Fig | Incremental migration | Long dual-run period |
| Event-Driven | Loose coupling | Eventual consistency, debugging |
Each pattern below has its own deep dive with diagrams, failure walkthroughs and interview framing. Start with the one that matches the outage you had most recently.