What This Diagram Answers
Class diagrams say what exists; sequence diagrams say who talks to whom, in what order, with what results — for one scenario. They are the interview tool of choice for narrating a user journey (“walk me through booking a seat”) because they expose orchestration mistakes class diagrams hide: wrong layer making decisions, missing failure paths, circular calls.
Anatomy
Actor :BookingUI :BookingService :SeatInventory
│ │ │ │
│ selectSeats() │ │ │
├───────────────►│ │ │
│ │ reserve(show,seats) │
│ ├───────────────────►│ │
│ │ ┌─────────────┐ │ hold(seats) │
│ │ │activation │ ├────────────────────►│
│ │ │bar = work │ │◄────────────────────┤
│ │ └─────────────┘ │ Hold │
│ │◄───────────────────┤ │
│◄───────────────┤ BookingResponse │ │
time ─────────────────────────────────────────────────────────►
- Lifeline: dashed vertical line per participant; the box header names it (
:ClassName= instance). - Activation bar: thin rectangle while the participant processes — width of this bar is its busy time.
- Solid arrow, filled head → synchronous call (caller waits).
- Solid arrow, open head → asynchronous (fire-and-forget / callback later).
- Dashed arrow → return value.
- Time flows downward — reading order is execution order.
Interaction Frames (combined fragments)
| Frame | Meaning |
|---|---|
alt [cond1] ... [else] | if/else alternatives |
opt [guard] | optional step |
loop [n times] | iteration |
par | parallel blocks |
┌──alt──[ seats available ]─────────────┐
│ BookingService → SeatInventory: hold │
└──[else]───────────────────────────────┘
│ BookingService → BookingUI: error() │
└───────────────────────────────────────┘
The alt frame is where senior candidates earn points: the failure branch drawn unprompted.
Drawing Rules That Keep Diagrams Honest
- One diagram per scenario; “everything” diagrams become unreadable at ~8 messages.
- Arrows between adjacent layers only — a UI→Inventory arrow skipping Service signals a missing orchestrator.
- Returns matter for sync calls (they carry the data contract); async flows show callbacks instead.
- Actor stick figure only for real external humans/systems, never internal objects.
Interview Application
- Narrating BookMyShow booking as a sequence (select → reserve → payment → confirm/expire) demonstrates both modeling and API thinking.
- The expiry path (hold TTL firing when payment stalls) is the follow-up that separates complete designs.
Common Mistakes
- Drawing returns for every async message — async has no immediate return.
- Lifelines for plain data objects (DTOs) — noise.
- Missing activation bars entirely, losing all timing information.
Why the Arrowhead Is a Runtime Decision
The two message types differ in one property — does the caller wait? — but that property cascades into thread usage, failure handling, and latency behavior. Drawing them distinctly forces designers to decide concurrency explicitly instead of inheriting it by accident.
Side by Side
SYNCHRONOUS (filled head) ASYNCHRONOUS (open head)
:Client :Service :Client :Broker/Service
│ pay(order) │ │ publish(evt) │
├──────────────►│ │ ┄┄┄┄┄┄┄┄┄┄┄┄► │
│ ┌───────────┐ │ │ │ processes
│ │ blocked, │ │ │ (returns │ later, maybe
│ │ waiting │ │ │ instantly) │ on other thread
│ └───────────┘ │ │ ◄─callback──── │
│◄──────────────┤ result │ (if any) │
│ │ │ │
caller's clock stops until reply caller continues immediately
Left: client’s activation bar spans the entire downstream processing — it is on the hook for the callee’s latency. Right: client’s bar ends at send; correlation of results happens via callback, future, or never.
Semantics Table
| Property | Synchronous | Asynchronous |
|---|---|---|
| Caller blocks | Yes — thread parked | No |
| Result delivery | Immediate return value | Callback / future / polling |
| Failure mode | Exception propagates to caller | Lost/delayed delivery; retries are receiver’s job |
| Temporal coupling | Callee must be alive now | Callee may be down; queue holds work |
| Throughput ceiling | Limited by round-trip latency | Bounded by queue capacity & consumers |
Worked Example: Checkout Payment
SYNC choice ASYNC choice
UI → Service: checkout UI → Service: checkout
Service → Gateway: charge() Service → Broker: PaymentRequested
Service ← result: approved/declined Service ← ack (queued)
UI ← "approved" (truthful answer) UI ← "processing…" + order status page
Broker → Worker → Gateway (later)
Sync fits when the user needs this exact answer to proceed (“was the card declined?”). Async fits when confirmation can lag (“order received”) — buying resilience (broker retries, gateway downtime survivable) at the cost of eventual consistency and duplicate-handling requirements.
Production Implications
- Sync chains multiply unavailability: three sequential sync hops at 99.9% each yield ≈ 99.7% path availability (0.999³) — illustrative arithmetic that explains why deep synchronous call stacks are an architecture smell.
- Async demands idempotent consumers and explicit dedup keys — duplicates are normal, not exceptional.
- Timeout design belongs to sync paths; backpressure (bounded queues, load shedding) belongs to async ones.
Interview Framing
- Choosing per-edge (“payment charge stays synchronous — UX needs the verdict; email goes async”) demonstrates the judgment being tested.
- On diagrams: open-head arrows with no return line; async completion shown as a separate callback lifeline event.
Common Mistakes
- Mixing semantics silently: drawing a fire-and-forget arrow then using its “result” two frames later.
- Making everything async to sound scalable — losing truthful error reporting for operations users depend on.
Premium Content
Unlock Sequence Diagrams and all premium lessons with a subscription.
From ₹199.99/year — See plans