Lesson 0031 · Master Designer · Module 2
Synchronous vs Asynchronous Systems
Sync is simple until it isn't fast; async is fast until it isn't simple. The Master's move: choose per workflow, not per system — and know the failure modes you're buying.
Mission tie-in: the first System Trade-Off — where lesson 0025's event-driven machinery becomes a measured decision instead of a default.
Knowledge: the ledger of the two modes
| Synchronous | Asynchronous | |
|---|---|---|
| Caller | Gets the result now | Gets an acknowledgment; result later |
| Flow | Visible in one call stack | Distributed across handlers (lesson 0025's honest cost) |
| Failure | Fails in your face, retryable by the caller | Ordering, retries, dead letters, visibility — a new failure zoo |
| Wins | Simplicity, debuggability, consistency | Decoupling, resilience, latency hiding, scale |
The deciding question is about the workflow: does the caller need the result to continue? Confirming an order needs the payment result now — sync. Sending the confirmation email doesn't gate anything — async. Most systems are a mix:
def place_order(cart: Cart, gateway: PaymentGateway) -> Order:
charge = gateway.charge(cart.total, cart.token) # sync: caller needs it
order = order_service.confirm(cart, charge.id)
bus.publish(OrderConfirmed(order)) # async: reactions don't gate
return order
The async failure modes you must be able to name before you adopt it: ordering (handlers may see events out of order), at-least-once delivery (idempotency needed), dead letters (what happens when a handler keeps failing), and observability (the flow isn't in one stack trace). If you cannot answer "what happens when the handler dies mid-way?" — the workflow isn't ready for async.
† The asymmetric default: sync unless a concrete reason demands async. Async-everywhere is the pattern that turns every feature into a distributed-systems problem (lesson 0025's cost, now at system scale).| Failure mode | The question you must answer first | A concrete answer |
|---|---|---|
| out-of-order delivery | What if OrderShipped arrives before OrderConfirmed? | Key handlers by order id; ignore events older than the state. |
| at-least-once delivery | What happens when this handler runs twice? | An idempotency key, or INSERT … ON CONFLICT DO NOTHING. |
| a handler that keeps failing | Where does message five go after three attempts? | A dead-letter queue that a human actually watches. |
| no single stack trace | How do you follow one order across six handlers? | A correlation id on every event and every log line. |
Skill: which mode for this workflow?
The caller must know the payment result before confirming. The payment call should be:
The confirmation email doesn't gate anything. It should be:
Before adopting async, you must be able to answer:
Practice on your own code
List the workflows in your system. For each, mark: does the caller gate on the result? Where failure modes exist (ordering, duplicates, dead handlers), write the answer to "what happens if the handler dies mid-way?" — on paper, before you build more async.
Reveal: a workflow-by-workflow decision
An e-commerce system: place order — sync (payment gates confirmation). Send receipt — async (event, idempotent by order id). Update inventory — async but ordered per SKU, with a dead-letter queue for the warehouse sync. Analytics — async, best-effort, no dead-letter (loss is acceptable). Four workflows, three modes, each decision written down with its failure answer.
Your win
You can classify each workflow by its gating requirement, and you carry the async failure inventory — ordering, at-least-once, dead letters, observability — as a checklist before adopting it.
Read and watch deeper
- Designing Data-Intensive Applications, Kleppmann — ch. 11 "Stream Processing": async systems and their guarantees, rigorously.
- "What Do You Mean by Event-Driven?", Fowler — the vocabulary for choosing between the modes.
- Release It!, Nygard — the failure-mode thinking this lesson's checklist comes from.
- Watch: ArjanCodes YouTube — search "async" or "event driven".
- Next: lesson 0032 — Consistency vs Availability.
- Reference: Trade-offs — synchronous vs asynchronous; glossary — idempotent, dead-letter queue, correlation id.
Walk your workflow list past your agent-teacher and classify each one together.