Building an ATM Use Case Diagram Without Losing Your Mind

Most people rush through ATM diagrams and get stuck because they treat every button press as a separate use case. That's wrong, and it makes the diagram unreadable within twenty minutes. I've seen it happen on projects more times than I care to count.

The trick is thinking about actors first, not features. An ATM has three main actors: the customer, the bank teller, and the bank's backend system. That's it. Everything else is a variation or a side effect. Start with the customer. Their use cases are straightforward: withdraw cash, check balance, transfer funds, and change PIN. But here's where people mess up — they draw "deposit cash" as a separate use case. It isn't, not really. The hardware differs, but from a modeling perspective it's the same flow as a withdrawal. The account is credited instead of debited. Combine them or explicitly note the dependency. I learned this the hard way on a project for a regional credit union back in 2019. Our client insisted that "deposit checks" and "deposit cash" needed separate use cases because their deposit machines handled both. The diagram grew to forty-three use cases and nobody could read it. What I ended up doing was creating a single "make deposits" use case with two include relationships to "verify deposit amount" and "update account records." The check vs cash distinction lived in the textual description, not the diagram. It took three minutes and everyone stopped arguing.

Actor Relationships and Including

The bank teller actor is easy to overlook. They're not just someone who refills cash. Tellers handle card issuance, dispute resolution, and machine malfunctions. Draw a <> relationship between the teller and "handle machine error" because both the customer and the teller interact with that same process. That's a common pitfall — beginners duplicate use cases across actors when they should be using generalization or inclusion. The backend banking system is another actor people treat incorrectly. It's not just a passive recipient of data. It validates transactions, updates ledgers, and sends confirmations. Model it as a system boundary with <> relationships coming from use cases like "withdraw cash" and "transfer funds." This shows which operations the backend actually participates in rather than implying it touches everything.

Generalization Patterns

Generalization is useful here but underused. A standard customer and a premium customer have different withdrawal limits and fee structures. Instead of duplicating every use case, draw a generalization arrow from "premium customer" to "customer" and note the differences in constraints. Same goes for the machine itself — some ATMs offer balance transfers, others don't. A <> from "feature-rich ATM" to "basic ATM" keeps your diagram clean. One nuance that trips people up: don't make the ATM hardware an actor. It's not. The customer interacts with the ATM interface, but the machine is part of the system boundary. Actors must be external to the system being modeled. The ATM is the system. Everything outside it is an actor.

Get the Full Details

Collection of FF Fonts for Cool Nicknames
Collection of FF Fonts for Cool Nicknames

Common Mistakes That Waste Time

Here are the mistakes I see constantly. First, drawing login as a standalone use case. It's not. Authentication is a precondition for every other use case in the diagram. Put it in the notes section as a constraint, or use an <> from each relevant use case. Second, treating error handling as primary flow. "Withdraw cash - insufficient funds" is not a separate use case. It's an extension point. Use <> relationships for exception scenarios, not new use case bubbles. Third, over-modeling. An ATM diagram should live somewhere between fifteen and twenty-five use cases. If you're pushing forty, you're modeling implementation details instead of user goals. Use cases describe what the user accomplishes, not every screen they see along the way. "Check balance" covers the entire balance inquiry flow regardless of how many screens it takes on the actual machine. The real downside of use case diagrams for ATM systems is that they don't capture timing or state transitions. If you need to model what happens when a customer doesn't take their card within thirty seconds, a use case diagram won't help you. You'd need a state machine diagram for that. Don't try to force sequence logic into a static diagram. It just creates confusion.

For tooling, I use Lucidchart for quick drafts and draw.io when I need something free and exportable. The actual software doesn't matter much. What matters is keeping the abstraction level consistent. Every stakeholder on that project should be reading the same diagram and seeing the same scope boundaries.