Use case diagram
What can the actor do, from outside the system, without touching a single internal detail? The lightest UML diagram on purpose: no classes, no messages, no code - just capability. It answers "what", never "how", which is exactly why it is the first diagram worth drawing in a design conversation, before anything else has been decided.
Actors: primary and secondary
An actor is anything outside the system that interacts with it - almost always drawn as a stick figure, even when the actor is not a person. There are two flavors, and the distinction matters more than the shared stick-figure icon suggests:
- Primary actor - the one who initiates the use case, to get something they want.
A
Usersubmitting login credentials. - Secondary actor - something the system relies on to finish the job, without
starting the interaction itself. An
AuthServiceor an externalEmail Providerthe system calls out to mid-flow.
Use cases and the system boundary
A use case is one oval per goal an actor can accomplish - named as a verb phrase ("Log In", not "Login Screen"), never an implementation detail. The system boundary is a labeled box that separates "the system" from everything outside it; actors always sit outside the box, use cases always sit inside it.
The line from actor to use case carries no arrowhead and no label by default - it just means "this actor participates in this use case." Most of the expressive power in this notation lives in three other relationships, which most explanations skip entirely.
<<include>>, <<extend>> and generalization
<<include>> factors out a step that always happens as part of a use case, and
that more than one use case needs - the use case equivalent of extracting a shared
method. The arrow is dashed, points from the including use case to the included one, and
is labeled «include».
<<extend>> is the opposite: optional, conditional behavior that only sometimes
inserts itself into a base use case, at a defined extension point. The arrow is dashed,
points from the extending use case back to the base one, and is labeled «extend».
Generalization works on actors and use cases the same way it works on classes: a
hollow-triangle arrow from the more specific actor to the more general one. A
Registered User who can do everything a Guest User can, plus checkout, generalizes
from Registered User to Guest User - the arrow points at the actor being
specialized, not the other way round.
The login flow, built up in stages
Stage 1 - just the actor and the boundary. One actor, one empty box, before a single goal has been named.
Stage 2 - add the primary goal. "Log In" is the whole reason the actor showed up.
Stage 3 - factor out a mandatory step, add a secondary actor. Every login attempt must check the credentials against a store, and that check leans on a system outside this one's boundary.
Stage 4 - add an optional extension. Some accounts require a second factor, but only
some - this is «extend»'s exact use case, plugged in at one point without forcing every
login through it.
Four stages, and the diagram now distinguishes "always happens" from "sometimes happens" without a sentence of prose - exactly the distinction a text description tends to blur.
When to reach for it: scoping, or when a system has more than one kind of actor (a user and an admin, say) and you need to nail down who can do what before anyone argues about implementation. When not to bother: once the actors and goals are obvious and agreed on - three ovals restating "users can log in and log out" a week into the project is decoration, not information.
Common mistakes
- Naming a use case after a UI screen instead of a goal. "Login Screen" describes a page; "Log In" describes what the actor is trying to accomplish. The diagram should survive a redesign of the screen.
- Drawing every internal step as its own use case. Use cases are goals visible from outside the system. "Validate Credentials" earns a place because it is shared and mandatory; "Hash Password" is an implementation detail that belongs on a class diagram, not here.
- Confusing
«include»with«extend». If it always happens, it is include. If it is conditional and optional, it is extend. Mixing them up describes the system as more rigid or more flexible than it actually is. - Treating the boundary box as decoration. The box is a factual claim about what is inside the system and what is an external dependency - draw it wrong and a secondary actor gets mistaken for a use case, or vice versa.
Try it yourself: sketch a use case diagram for an online food-delivery app with a
Customer and a Restaurant actor. Which use case should «include» "Process Payment"?
Which one is a good candidate for «extend» (something optional, like "Apply Promo
Code")? Is there a secondary actor hiding in the payment step?
Check yourself
A "Payment Gateway" actor sits outside the system boundary, connected to a "Process Refund" use case, but no human ever interacts with it directly. What kind of actor is it?