Problem statement
Design the object model and core APIs for a self-contained vending machine controller — the software that runs on the machine itself, driving its keypad, coin slot, hopper, and dispensing motors.
Operating context. One physical machine with a fixed grid of product slots (say 30–60 slots), each slot holding one product type at a set price and a small count of units. A shopper walks up, inserts coins one at a time, selects a slot, and the machine either dispenses the item and returns any change, or refunds the inserted money. Only one shopper interacts at a time, but coin insertion, selection, and cancel arrive as discrete events the controller must handle in order. The machine keeps a coin bank (its float) used to make change. No network — everything is in-process on the machine's embedded board.
Out of scope. The physical hardware drivers (motor timing, coin-validator electronics), the restocking/admin console UI, persistence across power loss, telemetry or fleet management, and any card/contactless reader wiring (design the seam for it, but do not build it).
What to produce. The class hierarchy (entities, value objects, controller/services), the public API each class exposes, and above all the state machine the controller runs: the states (idle, collecting money, dispensing, and any others you need), the events that drive transitions (insert coin, select slot, cancel, dispense-done), and the actions on each transition. Be explicit about: how inventory is tracked per slot, how change is computed from the coin bank and what happens when exact change is impossible, how a cancel/refund returns the shopper's money, and how a second payment method (a card reader) could be added later without rewriting the state machine.
Functional requirements
- Accept coins one at a time, accumulating the shopper's inserted balance and rejecting denominations the machine does not recognise.
- Let the shopper select a slot; dispense the item only when the slot is in stock and the inserted balance covers its price.
- Compute and return the correct change from the coin bank after a successful purchase, decrementing that slot's count.
- Cancel an in-progress transaction on request and refund all coins inserted so far.
- Reject a selection when the chosen slot is empty or the inserted balance is insufficient, without ending the transaction.
- Refuse the sale and refund the balance when the purchase would succeed but the machine cannot assemble exact change.
Non-functional requirements
- Every event (insert, select, cancel, dispense-done) resolves to exactly one well-defined next state; no undefined or dead transitions.
- Slot inventory and the coin bank are never left in an inconsistent state if an event arrives mid-transition (single-threaded, run-to-completion event handling).
- Change computation over the coin-bank denominations runs in time linear in the number of denominations, independent of the balance amount.
- Adding a new payment method (card reader) must not modify the core state machine's transition logic — plug it in behind a payment abstraction.
- The controller is unit-testable with no real hardware: coin acceptor, dispenser, and clock are injectable fakes.
- Adding a new coin denomination or a new slot layout is a localised change that does not touch the purchase or refund code paths.
Topics
- System Design LLD
- Patterns State
- Oop Solid
- Patterns Strategy
- Statemachine