Use Cases and System Design Examples
EDA where it earns the complexity — with hostile review
Event-driven architecture fits when facts must fan out, work can lag, and services must evolve independently. It is the wrong default for "every service call." Below: solid use cases, a ride-sharing design that survives review, and explicit when-nots.
Fit use cases
- Real-time analytics — market ticks, clickstream; consumers aggregate without blocking producers.
- IoT / telemetry — high ingest, many device events; brokers absorb spikes.
- E-commerce side effects — after order commit: email, loyalty, search index, warehouse — not on the checkout critical path.
- Microservice integration — replace chatty sync meshes with domain events (still need sagas for multi-step consistency).
Worked system: ride-sharing
Events: RideRequested, DriverAccepted, LocationUpdated, RideCompleted. Matching, billing, ETA, analytics consume independently.
| Event | Producer | Consumers | Failure mode | Mitigation |
|---|---|---|---|---|
RideRequested | Rider API | Matching, analytics | Duplicate → two rides | Idempotency on ride_id |
DriverAccepted | Matching | Rider, driver apps | Two drivers accept | CAS on ride status; only OPEN→ASSIGNED emits success |
LocationUpdated | Driver | Rider map, ETA | Out-of-order GPS | Per-ride sequence; drop older |
RideCompleted | Driver | Billing | Lost event → no fare | At-least-once + idempotent bill on ride_id |
The double-accept race, traced. Drivers D7 and D9 both consume RideRequested(ride_id=r42) and both send accept. Each accept runs:
UPDATE rides SET status='ASSIGNED', driver_id=?
WHERE id='r42' AND status='OPEN'
The database serializes the two updates: the first wins (rowcount=1) and the service emits DriverAccepted(D7); the second sees rowcount=0 — the status='OPEN' guard failed — and emits AcceptRejected(D9), which the driver app renders as "ride no longer available." The WHERE-status guard plus the affected-rows check is the same conditional-write discipline as the saga chapter's balance guard: the state transition, not the reader, decides the winner.
Numbers sketch: city peak 200 ride requests/s. Matching consumer group with 20 partitions → ~10 RPS/partition if balanced. Hot geohash partition (airport) can skew — watch partition lag, not only group lag. Billing at-least-once with unique (ride_id) constraint prevents double charge under redelivery.
Hostile design-review table
| Slice | First bottleneck under load | Rejected alternative | Trade-off paid |
|---|---|---|---|
| Ride matching via events | Hot partition / lag on airport geohash | Synchronous match in one monolith DB for all cities | Eventual assign; more moving parts |
Billing on RideCompleted | DLQ from bad fare rules; lag → delayed charge | Charge inside driver app offline only | Must operate DLQ + replay runbooks |
| Location stream | Bandwidth + fan-out to many riders | Global ordered single queue | Per-ride ordering only; drop stale |
| Checkout payment (counterexample) | — | EDA for card charge | Wrong tool — use sync + idempotent Payment API |
Queue, bus, or log
- Queue — one worker per message; task offload.
- Pub-sub — fan-out without long retention.
- Retained log — multi consumer groups + replay (ride-sharing default).
Delivery & dual-write (non-negotiable)
Default is at-least-once. Exactly-once end-to-end for arbitrary side effects is not free. Write state and outbox in one DB transaction; relay publishes; consumers dedupe on business keys.
When NOT to use EDA
- Caller needs the result now (auth, payment capture confirmation).
- Strong consistency read path immediately after write.
- No fan-out — overkill vs RPC/queue.
- Complex multi-step undo without an orchestrator — pure choreography becomes unownable.
Operational signals
- Consumer lag (per partition).
- DLQ depth and age.
- Schema compatibility failures.
- Outbox oldest unsent timestamp.
Drill ladder
- Q: Two drivers accept the same ride event — correct design? A: Conditional update on status; loser gets reject event; only one
DriverAssigned. - Q: Why not at-most-once for billing? A: Dropped completion = free rides; prefer at-least-once + idempotent charge.
- Q: Name one bottleneck a diagram-only EDA design usually misses. A: Hot partitions, dual-write loss, or lag SLOs.
🤖 Don't fully get this? Learn it with Claude
Stuck on Use Cases and System Design Examples? Open Claude, copy a block below, and it'll teach you this exact concept — visually and interactively.
Build the mental picture, not memorization.
I just read a lesson on **Use Cases and System Design Examples** (System Design) and want to truly understand it. Explain Use Cases and System Design Examples from first principles using ONE vivid real-world analogy and a visual mental model — draw it as ASCII art or a clear step-by-step diagram — with a concrete example using real numbers. Then ask me one question to check I got the mental picture, and wait for my reply. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
Socratic — adapts to where you're stuck.
Teach me **Use Cases and System Design Examples** interactively. Ask me ONE guiding question at a time, wait for my answer, and adapt to my confusion — build the idea with me step by step instead of explaining it all at once. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
Active recall exposes what you missed.
Quiz me on **Use Cases and System Design Examples** with 5 questions, easy to tricky, ONE at a time. Tell me if each answer is right; at the end, explain clearly what I got wrong and why. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
Intuition + hook + flashcards for long-term memory.
Help me remember **Use Cases and System Design Examples** for the long term: give the one-sentence intuition, a memorable hook/mnemonic, a tiny worked example, and 3 active-recall flashcards (Q -> A). If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.