Skip to content

9.7.2 — UML for LLD: Four Diagrams Worth Drawing

Most UML you will ever be shown is decoration. There are fourteen official diagram types and you will use four, because those four answer questions that are genuinely hard to answer in prose:

DiagramThe question it answers
Use caseWho can do what?
ClassWhat exists and how is it connected?
SequenceWho calls whom, in what order?
State machineWhat can this one object do next?
ActivityWhat is the decision flow, including the branches?

The class diagram is built in full in 9.2.7, with all six relationship types and their arrowheads. This page covers the other four, plus the part that matters most in an interview: which one to draw, when, and how fast.

The rule that governs all of it: a diagram earns its place only if it answers a question that words would take a paragraph to answer. If you can say it in a sentence, say it in a sentence. An interviewer watching you draw boxes for six minutes is watching six minutes of not-designing.

1. The use case diagram: who can do what

This is the simplest diagram in UML and the one most worth the ninety seconds it costs, because drawing it forces step 2 and step 3 of the method (9.7.1) to actually happen rather than being skipped.

Stick figures are actors. Ovals are things they can do. Lines connect them. That is the whole notation.

Parking Lot SystemDriverAttendantAdminpark a vehiclepay and exitmark spot brokenview occupancyset pricingadd a floor
Figure 1 — Use cases for a parking lot. Ninety seconds of drawing, and it has already surfaced the administrator — the actor whose existence is the reason pricing must be configurable rather than hard-coded.

What it is for. Three things, and each one is a real payoff rather than documentation.

It finds the actor you forgot. Everybody draws the driver. The administrator is the one who turns "pricing" from a constant into a PricingStrategy, and the attendant is the one who reveals that a spot can be out of service, which is a third state your Spot did not have a minute ago.

It fixes the system boundary. The box is what you are building. Anything outside it is somebody else's problem, and drawing the box is a visual version of the deferral sentence from step 1.

It becomes your method list. Each oval turns into a public method. If an oval has no method by the end of the interview, you did not finish; if a method matches no oval, you built something nobody asked for.

What to skip. UML has <<include>> and <<extend>> relationships between use cases. Skip them. They generate long arguments about which is which, they add nothing to the design, and no interviewer has ever given a point for one.

2. The sequence diagram: who calls whom, in what order

A sequence diagram shows one scenario as a conversation between objects. Objects across the top, time running down, arrows for calls.

GateParkingLotSpotAllocatorSpotTicketspark(vehicle)allocate(size)spot | nullclaim(vehicle) — fails if already takentrue | falsesave(ticket)Ticketif claim returns false: loop back to allocate, next candidate
Figure 2 — Parking a vehicle, one scenario. Solid arrows are calls, dashed arrows are returns, and the tall bars show which object is currently doing the work. The red note at the bottom is the race being handled explicitly.

The notation you need is small: solid arrow for a call, dashed arrow for a return, and a narrow vertical bar on an object's lifeline while it is executing. Everything else — combined fragments, alt boxes, par boxes — is optional and usually better said in one sentence next to the diagram, as the red note does above.

What it is for, and this is where it beats prose. A sequence diagram makes two things visible that a class diagram completely hides.

Who is in charge. In Figure 2 the ParkingLot calls everybody and nobody calls back into it. That is a coordinator, and it is a deliberate design choice. If the arrows instead bounced back and forth — the allocator calling the lot, which calls the spot, which calls the allocator — you would be looking at a circular dependency, and it would be obvious in a way that reading four files is not.

Where the failure branches are. The claim can fail. On a class diagram, claim(): boolean looks like an ordinary method. On the sequence diagram, that false return needs somewhere to go, and drawing it forces you to answer the question: retry with another spot, or tell the driver the lot is full? That is exactly the concurrency point from step 8 of the method, and the diagram dragged it out of you.

When to draw one in an interview. Only for the one core flow, and only if it is genuinely multi-object. A three-object sequence is not worth drawing; you can say it. A flow with a coordinator, two collaborators, a conditional claim and a persistence step is worth ninety seconds, because it is now the artefact you narrate against for the rest of the session.

3. The state machine diagram: what can this object do next

Any object with a lifecycle deserves one, and this is the highest-value diagram in an LLD interview because it maps directly onto code you are about to write.

IDLEwaiting for coinsHAS CREDITbalance: MoneyDISPENSINGmotor runningOUT OF STOCKrefuses selectioninsertCoininsertCoin / add to balanceselect [credit ≥ price]dispensed / return changecancel / refundselect [sold out]restock
Figure 3 — A vending machine's states. The label format is event [guard] / action. Every arrow becomes one case in a transition function, and every arrow you did not draw becomes a rejected transition.

The notation is three things. A filled circle is where the object starts. A rounded box is a state. An arrow is a transition, labelled event [guard] / action — the event that triggers it, the condition that must hold, and what happens as a result. A circle with a ring around it marks a final state, if there is one.

Why this diagram is worth more than the others in an interview. It converts directly into code, one arrow at a time:

typescript
type MachineState =
  | { kind: "idle" }                                         // (1)
  | { kind: "hasCredit"; balance: Money }
  | { kind: "dispensing"; item: Sku; change: Money }
  | { kind: "outOfStock"; item: Sku };

function transition(state: MachineState, event: MachineEvent): MachineState {
  switch (state.kind) {
    case "idle":
      if (event.kind === "insertCoin") {                     // (2)
        return { kind: "hasCredit", balance: event.coin };
      }
      throw new IllegalTransition(state, event);             // (3)

    case "hasCredit":
      if (event.kind === "insertCoin") {
        return { kind: "hasCredit", balance: state.balance.add(event.coin) };
      }
      if (event.kind === "cancel") return { kind: "idle" };  // (4) refund is the caller's job
      if (event.kind === "select") {
        if (!inventory.has(event.item)) return { kind: "outOfStock", item: event.item };
        if (state.balance.lt(priceOf(event.item))) return state;    // (5) not enough: no change
        return { kind: "dispensing", item: event.item,
                 change: state.balance.sub(priceOf(event.item)) };
      }
      throw new IllegalTransition(state, event);
    // ... remaining states
  }
}

(1) Each state carries exactly the data that state has. An idle machine has no balance, and the type says so, which means no code anywhere can read a balance that does not exist. This is the union-of-states spelling, and it is why the diagram and the type are the same artefact.

(2) One if per arrow leaving that state. You can check your code against the figure by counting.

(3) Anything not drawn is rejected loudly. This one line answers half the "what if the user does X" questions an interviewer can ask, and answering them by construction is much stronger than answering them one at a time.

(4) The transition function is pure: it returns the next state and does not touch hardware. The action written on the arrow — refunding the coins — is performed by the caller after the transition is accepted. Keeping the decision pure and the effects outside is what makes the whole thing easy to reason about.

(5) Returning the same state is a legal answer, and it is how "you have not put in enough money" is expressed without an exception.

One thing worth adding when the interviewer pushes. Real state machines often need entry and exit actions — something that must happen every time you enter a state, regardless of which arrow you came in on. Turning on the motor when entering dispensing, or starting a timer when entering hasCredit so an abandoned transaction refunds itself after ninety seconds. Naming that unprompted shows you have built one of these rather than only drawn one (9.4.14).

4. The activity diagram: the decision flow

An activity diagram is a flowchart with two extra symbols worth knowing. It answers "what is the sequence of steps and decisions", including the branches and the parallel bits.

read platefind a free spotspotfound?yesnoshow LOT FULLclaim the spotforkprint the ticketupdate the displayjoin
Figure 4 — Parking, as a decision flow. The diamond is a branch, the two thick bars are a fork and a join, and the ringed circle is the end. The fork says printing the ticket and updating the display are independent and may happen in either order.

The two symbols worth learning are the diamond, which is a branch with a condition on each outgoing arrow, and the thick bar, which is a fork when several arrows leave it and a join when several arrive. The fork is the useful one, because it is how you say "these two things are independent" without saying anything about threads.

When it beats a sequence diagram. A sequence diagram is about who; an activity diagram is about what happens next. If the interesting content of your flow is a chain of decisions — is the spot free, is the customer a member, is the payment authorised — the activity diagram shows it and the sequence diagram buries it. If the interesting content is which object is responsible for what, it is the other way round.

When to draw one in an interview: rarely. Most LLD flows are better served by the state machine, which carries strictly more information about an object's life. Reach for the activity diagram when the problem is genuinely a process rather than an object — an approval workflow, a checkout with several validation gates, an order fulfilment pipeline.

5. The class diagram, in one paragraph

9.2.7 covers this properly. The interview-relevant summary: a filled diamond is composition (the part dies with the whole — a floor cannot outlive its lot), a hollow diamond is aggregation (the part survives independently — a team and its members), a plain arrow is association (I hold a reference to you), a dashed arrow is dependency (I mention you in a signature but do not hold you), a hollow triangle is inheritance, and a hollow triangle on a dashed line is interface implementation. Put the multiplicity at each end — 1, 0..1, 1..*, * — because the numbers are where the unstated requirements hide.

The single most common mistake is drawing composition where association is meant. If you can delete the container and the parts still make sense, it is not composition, and claiming otherwise commits you to a lifecycle rule you did not intend.

6. Which diagram, when, in an interview

Draw the use case diagram if the problem has more than one kind of user. Ninety seconds, and it catches the actor you would have missed.

Draw the class diagram always, but keep it small. Boxes with names and the important fields, lines with multiplicities. Do not write out every getter; nobody has ever been scored on a complete attribute list.

Draw the state machine whenever anything has a lifecycle. This is the highest-return diagram, because it converts straight into the transition function that is the best code you will write in the session.

Draw the sequence diagram for exactly one flow, and only if the flow is genuinely multi-object with a branch in it.

Draw the activity diagram almost never, unless the problem is a workflow.

And the discipline that matters more than any of this: a diagram is a thinking tool, not a deliverable. Draw it, use it to make a decision, say what the decision was, and move on. The failure mode is minute thirty with a beautiful chart and no code, which is one of the two standard ways to fail this interview (9.7.1).

Next: 9.7.3 puts the method and the diagrams to work on the purest lifecycle problem of all — a vending machine, where one transition function has to prove that nobody ever loses money.

Recall

  • Four diagrams matter: use case (who can do what) · class (what exists, 9.2.7) · state machine (what this object can do next) · sequence (who calls whom). Activity is a fifth, for workflows.
  • Use case: stick figures, ovals, a box for the system boundary. Its value is finding the forgotten actor and turning ovals into your method list. Skip <<include>> and <<extend>>.
  • Sequence: solid arrow calls, dashed arrow returns, bars for who is executing. It reveals who is in charge and where the failure branches go — both invisible on a class diagram.
  • State machine: filled circle for the start, rounded boxes for states, arrows labelled event [guard] / action. Converts one-arrow-per-if into a transition function; anything not drawn is rejected. Mention entry and exit actions if pushed.
  • Activity: diamond for a branch, thick bar for fork and join. Use it when the content is a chain of decisions rather than a cast of objects.
  • Class diagram shorthand: filled diamond = composition (part dies with whole) · hollow diamond = aggregation · plain arrow = association · dashed = dependency · hollow triangle = inheritance. Always put multiplicities on.
  • A diagram earns its place only if prose would take a paragraph. Draw, decide, narrate, move on.

Self-test: What does a sequence diagram show that a class diagram cannot? What does an arrow you did not draw on a state machine mean in code? Which diagram converts most directly into code, and why? When is an activity diagram the right choice? What is the difference between a filled and a hollow diamond?

Quiz Bank

FoundationalWhat does each of the four diagrams show that the others cannot, and when would you draw each in a 45-minute interview?

The use case diagram shows who is allowed to do what, and the system boundary. Nothing else shows the boundary, which is why it is a visual version of "here is what I am not building". Draw it in the first ten minutes if there is more than one kind of user, because it costs ninety seconds and it catches the actor you would otherwise forget — usually the administrator, whose existence is the reason a configuration value has to be configurable.

The class diagram shows what exists and how the pieces are connected, including ownership and multiplicity. It is the only one that shows structure. Draw a small one always, with names, important fields and the numbers at each end of every line, and resist the urge to list every method.

The sequence diagram shows who calls whom in what order for one scenario. This is the one that reveals two things structure hides: which object is the coordinator, and where the failure branches go. A claim(): boolean on a class diagram looks like an ordinary method; on a sequence diagram the false return needs somewhere to go, and drawing that arrow forces you to decide what happens when the claim loses. Draw one, for the core flow only, and only if it is genuinely multi-object.

The state machine shows what one object can do next, which no other diagram addresses at all. Draw it whenever anything has a lifecycle, which in these problems is nearly always.

The ordering advice. If you only have time for two, draw the class diagram and the state machine, because those two convert into code most directly — the class diagram becomes your files, and the state machine becomes your transition function. The use case diagram is cheap enough to be worth it anyway. The sequence diagram is a luxury that pays off when the flow has a real branch in it.

And the meta-rule that outranks all of them: a diagram is a thinking tool. Draw it, make the decision it exists to help you make, say what the decision was, and then write code. A finished chart with no code is one of the two classic ways to fail this interview.

FoundationalExplain the state machine notation and show how it becomes code.

The notation is four things. A filled circle marks where the object begins its life. A rounded box is a state. An arrow is a transition, labelled event [guard] / action — the event that triggers it, a condition in square brackets that must hold, and an action after a slash that happens as a result. A circle with a ring around it is a final state.

So select [credit ≥ price] / dispense means: when the select event arrives, if the credit is at least the price, move along this arrow and dispense.

The conversion into code is mechanical, which is what makes this diagram so valuable in an interview.

Each state becomes one variant of a union type, carrying exactly the data that state has and no more. An idle vending machine has no balance, and the type says so, which means no code anywhere can read a balance that does not exist.

Each arrow becomes one branch of a transition function, matched on the current state and the incoming event. You can literally check your code against your drawing by counting arrows and branches.

Each guard becomes the if inside that branch.

And each action is performed by the caller after the transition is accepted, not inside the transition function itself. Keeping the function pure — state and event in, next state out, nothing touched — means you can reason about legality without thinking about hardware, refunds or emails.

The most valuable line is the one for the arrows you did not draw: a default that throws IllegalTransition. Anything the diagram does not permit is now rejected loudly rather than silently doing something odd. This single line pre-answers half the "but what if the user does X" questions an interviewer can think of, and answering them by construction is far stronger than answering them one at a time.

Two refinements worth naming if pushed. Entry and exit actions run every time you enter or leave a state, regardless of which arrow you took — starting the dispensing motor, or starting a ninety-second abandonment timer when credit is inserted. And self-transitions, where an event leaves a state and returns to it, which is how "you inserted another coin" and "you have not put in enough yet" get expressed without an exception being involved.

AppliedAn interviewer says: skip the diagrams, just write code. How do you respond, and what do you actually do?

Agree immediately, and then do about ninety seconds of drawing anyway, out loud, with a reason attached.

Why agreeing is right. The interviewer is telling you something real: they want to see code, and they have watched candidates burn twenty minutes on a chart. Arguing about process is a bad use of your first minute, and the request is also information about how this particular session will be graded.

What you do anyway, and how to frame it. Two artefacts survive the cut, because both are code rather than decoration.

The state machine, written as a type. Instead of drawing boxes, type the union straight into the editor and narrate it: "the order is placed, paid, packed or shipped, and here is the data each one carries." That is the diagram, expressed in the medium they asked for, and it costs thirty seconds.

The class list with the relationships stated aloud. Rather than drawing lines, write the class declarations with their fields and say the numbers: "a lot owns floors, a floor owns spots, and a ticket references one spot and one vehicle." The multiplicities were the valuable part of the class diagram, and they can be spoken.

What you genuinely drop. The use case diagram — but not the thinking behind it, so you still ask "who else uses this besides the driver?" as a spoken question. The sequence diagram — unless the flow gets complicated enough that you and the interviewer start disagreeing about who calls what, at which point three boxes and four arrows resolve it faster than three minutes of talking, and you say exactly that as you draw them.

The underlying point, which is worth understanding rather than memorising: the diagrams were never the deliverable. Each one exists to force a decision — who the actors are, what owns what, what the legal transitions are, where the failure branch goes. If you can reach those decisions while typing, the drawing was scaffolding you did not need. A candidate who says "I will keep the state machine as a union type rather than drawing it, so it is checked by the compiler instead of by me" has answered the request and demonstrated why the diagram existed, in one sentence.

InterviewYou draw a class diagram with a filled diamond between Order and OrderLine, and the interviewer asks whether that is right. Talk through it.

The filled diamond is composition, and composition is a specific and fairly strong claim. It says three things: an OrderLine belongs to exactly one Order, it cannot exist without that order, and deleting the order deletes its lines.

For Order and OrderLine, that is almost certainly correct, and here is how to justify it rather than assert it. An order line has no meaning on its own — "two units of SKU-88 at £4.50" is not a thing anybody can look up or act on outside the order it belongs to. It is never shared with a second order. And if the order is deleted, keeping its lines would leave rows nobody can reach. All three tests pass, so the filled diamond is right.

The contrast that shows you understand the distinction. Order and Customer is not composition. A customer exists before the order, survives after it, and is referenced by many orders. That is an association, drawn as a plain arrow with * at the order end and 1 at the customer end. Getting this one wrong is the common mistake, and it matters because a diagram claiming composition here would imply that deleting a customer deletes their order history, which is both wrong and, in most jurisdictions, illegal.

The test to say out loud, because it generalises: if I delete the whole, does the part still make sense? If yes, it is aggregation or association. If no, it is composition.

Why the distinction is more than notation. Composition tells the reader who is allowed to create the part. If OrderLine is composed into Order, then nothing outside Order should be constructing one — lines are created through order.addLine(...), which is also the method that can enforce rules like "you cannot add a line to a shipped order". The diamond is therefore a statement about where an invariant lives, which is exactly the modelling axis being graded (9.7.1).

And the honest caveat worth adding: in a forty-five minute interview, nobody will fail you for a hollow diamond where a filled one belonged. What they are checking with this question is whether you know the difference exists and can reason about it — so the worst possible answer is "I just always use the filled one".

Flashcards

FlashThe four diagrams and their questions

Use case: who can do what. Class: what exists and how connected. Sequence: who calls whom, in what order. State machine: what can this object do next. Activity: what is the decision flow.

FlashState machine transition label

event [guard] / action. Filled circle starts, rounded box is a state, ringed circle ends. One arrow becomes one if; anything not drawn throws IllegalTransition.

FlashSequence diagram notation

Solid arrow = call. Dashed arrow = return. Vertical bar = this object is executing. It reveals who coordinates and where failure branches go.

FlashDiamonds

Filled = composition, the part dies with the whole. Hollow = aggregation, the part survives. Test: delete the whole — does the part still mean anything?

FlashWhen to draw

Always: a small class diagram and any state machine. Cheap and worth it: use case, if more than one actor. One only: sequence, for the core flow. Rarely: activity, for genuine workflows.