ATM System
Banking Machine
Design a cash machine: card and PIN, a state machine for the session, a chain of note handlers that plans before it dispenses, and money that never goes wrong.
Overview
A cash machine serves one customer at a time. The customer inserts a card, enters a PIN, and then asks for a balance or a withdrawal. The machine talks to the bank to check the PIN and to move money, and it holds a stock of notes in a few values. When the customer takes the card, the machine is ready for the next person.
The problem is a medium one because each part is simple and the difficulty is in the order of operations. What the keypad may do depends on where the session is, which is a state machine. A withdrawal must take the money from the account and hand out the notes, and either both happen or neither. The notes have to be assembled from the values on hand, which is a small planning problem with a trap in it: taking the largest note first does not always work.
Interviewers use this problem to see whether you keep the session states as classes rather than a pile of flags, whether you plan a withdrawal before you change anything, and whether you handle money as integers. A float balance is the most common mistake in this problem, and it is a real bug, not a style point.
Scoping the problem
- Which operations: balance, withdrawal, deposit, transfer? — Each is a state or a branch in the authenticated state — Balance and withdrawal; deposit as a follow-up
- Who checks the PIN, the machine or the bank? — Decides what the machine may store — The bank; the machine stores nothing about the PIN
- How many PIN attempts, and what happens after? — A counter in one state; the card is blocked and kept — Three, then block and retain
- Which note values does the machine hold? — Decides the dispensing chain and its failure cases — 100, 50 and 20
- What if the account has the money but the machine cannot make the amount? — The account must not be debited — Plan first, then debit, then dispense
- Can the same account be used from two machines at once? — The account needs a lock; the machine needs one too — Yes
- Receipts, a printer, a camera, a cash deposit slot? — Hardware is out of scope; a transaction record is in — A list of transactions
Core entities
The ATM is a context that delegates every key press to its current state object. The Bank owns accounts and cards and is the only place a PIN is checked. The CashDispenser is a chain of note handlers, largest value first.
The session as a state machine
Each state is a class. A method that is not allowed in a state raises InvalidOperation from the base class, so a new state only overrides what it permits. The PIN counter lives in the CardInserted state and disappears with it.
A withdrawal, in the right order
Three things can go wrong: the customer does not have the money, the machine cannot make the amount from its notes, or the two are fine but the order of operations leaves them out of step. The withdrawal therefore plans first, which changes nothing, then debits the account, which can fail and leaves the notes untouched, and only then commits the plan to the note handlers.
- 1. plan — CannotDispense — Untouched — Untouched
- 2. debit — InsufficientFunds — Untouched — Untouched, the plan is dropped
- 3. commit — Cannot fail: the plan was made under the dispenser lock — Debited — Removed
What you will be able to do
- Model the session as State classes and explain why a counter belongs inside the state that uses it.
- Build the note chain as a Chain of Responsibility with a plan step and a commit step.
- Order a withdrawal so that no failure leaves the account and the notes out of step.
- Show why the greedy chain fails on 180 with 100, 50 and 20 notes, and write the exact version.
- Keep money as integer cents and hash the PIN, and say why each matters.
Functional requirements
- Insert a card; a blocked card is refused
- Enter a PIN, checked by the bank against a hash; three wrong attempts block the card and the machine keeps it
- Show the balance and withdraw an amount once authenticated
- A withdrawal is refused when the balance is too low or the notes on hand cannot make the amount, and then nothing changes
- Notes are handed out largest value first from the machine's stock of 100, 50 and 20
- Eject the card and return to idle; every completed withdrawal is recorded as a transaction
Non-functional requirements
- Money is integer cents; no float ever holds a balance or an amount
- A withdrawal either debits the account and dispenses, or does neither
- Two machines using one account at the same time cannot overdraw it
- The machine never stores a PIN in the clear; the comparison is constant-time
- Adding an operation or a state touches one class each
Interview questions
- The greedy chain refuses 180 even though 100 plus four 20s works. How do you fix it?
- Why integer cents and not a float balance?
- What if the hardware jams after the account was debited?
- How would you add deposits and transfers?
- Where is the concurrency in a machine that serves one customer at a time?
Sign up free to read the full topic
More Low-Level Design topics
Start free on Cariara · Coding problems · System design studio