Class Design
What is this?
These problems ask you to model a small real-world thing in code โ a bank, a coffee machine โ where the operations themselves are easy but the organization is the whole game. It is like drawing the floor plan of a building before anyone moves in: where does each responsibility live, and how do the rooms connect? Nobody grades your speed here; they grade whether your design is clean, safe, and easy to extend when a new feature shows up.
๐ก Fun fact: "Validate before you mutate" isn't just interview advice โ it's the backbone of how real banks process transfers. A money move that half-completes is a genuine financial incident, which is why production systems treat the whole operation as all-or-nothing.
๐ The 2 problems in this chapter are free. Sign in with Google or Microsoft to start solving.
Core idea: These problems have no clever algorithm โ the operations are trivial. What's tested is how you model the domain: clean classes, a single source of truth, validating before you mutate, and a design where adding a new case is data, not a rewrite. Get the shape right and the code almost writes itself.
What's actually being graded
Not: "what's the fastest algorithm?"
But: "is this design correct, safe, and extensible?"
- Correctness & safety โ never leave the system in a half-valid state. Validate fully, then mutate. A half-applied transfer is a financial incident.
- Single source of truth โ centralize rules (e.g. one
_valid_accounthelper) instead of copy-pasting checks into every method, where they drift and develop off-by-ones. - Separation of concerns โ split responsibilities so each class has one job; the orchestrator coordinates them.
- Extensibility โ adding a drink / account type / rule should be registering data, not editing core logic.
The two problems
- Design a Bank System โ transfer/deposit/withdraw with invariants (valid account range, sufficient funds). The lesson: centralize validation, validate before mutating, and express
transferas validated withdraw-then-deposit. The "algorithm" is nothing; the discipline is everything. - Design a Coffee Machine โ model Inventory, Recipe (as data), and a Machine that mediates.
dispense= check availability, then deduct atomically. Adding a drink is a new recipe entry, not new branching. This is the open-ended OOP question where the interviewer watches your clarifying questions and your class boundaries.
The design checklist
| Principle | In practice |
|---|---|
| Validate before mutate | check all preconditions, then apply; never partially |
| Single source of truth | one validation/rule method reused everywhere |
| Separation of concerns | distinct classes, each one job; orchestrator wires them |
| Data over code | new cases are registered, not hard-coded |
| Clear API contracts | what does each method return on failure? (False vs raise) |
The insight: in class design the win is legibility and safety. State the invariants, put each rule in exactly one place, and make the common extension (a new account/drink/rule) a one-line data change.
๐ Draw it yourself
- Class diagram. Sketch the Coffee Machine as
Machine โ Inventory + {Recipe}and trace adispensethat checks inventory, then deducts. - Validate-then-mutate. For the Bank, draw a transfer: validate both accounts + funds first, then move money โ show the rejected path leaving balances untouched.
Snap photos and embed them with the /host-diagrams skill.
Key takeaways
- No algorithm โ it's modeling. Clean classes, clear responsibilities, safe mutations.
- Validate before mutating; never leave half-applied state (especially money).
- One source of truth for each rule; don't scatter validation.
- Make extension data, not code โ new drinks/accounts shouldn't touch core logic.
- Why interviewers use these: they reveal whether you can model a domain and write maintainable, safe code โ the day-job skill algorithms don't test.
Order: Design a Bank System โ Design a Coffee Machine.
Design a Coffee Machine
Core idea: Don't write one giant
dispense()that hardcodes every drink. Split the problem into three actors โ an Inventory that owns quantities, Recipes that are pure data (a name + how much of each ingredient it costs), and a Machine that mediates: check availability, then deduct atomically. Adding a new drink becomes data you register, not code you edit.
1. The problem, in a fresh setting
You're building the firmware brain for an office coffee bar. Behind the front panel are tanks of water, milk, and beans (and tomorrow, maybe chocolate and oat milk). The kitchen menu is a small set of drinks, each of which is really just a bill of materials: an espresso is "30 ml water + 18 g beans"; a latte is "30 ml water + 18 g beans + 150 ml milk."
Your controller must support exactly three things:
| Operation | Meaning |
|---|---|
dispense(drink) |
If every required ingredient is in stock, deduct them and serve the drink. Otherwise, serve nothing and report which ingredient is short. |
refill(ingredient, amt) |
Top a tank back up by amt (without overflowing its capacity). |
low_ingredients() |
List ingredients that have dropped below a "reorder soon" threshold. |
This is an open-ended design problem. There is no clever algorithm hiding here โ the interviewer is watching how you model it. Can a new drink be added without touching dispense? Are availability-check and deduction kept honest (no half-charged brews)? Is each piece testable on its own?
A small usage walk-through (tanks start at water=500 ml, milk=200 ml, beans=100 g):
| Call | Result | Tanks after |
|---|---|---|
dispense("espresso") |
โ served espresso | water=470, milk=200, beans=82 |
dispense("latte") |
โ blocked โ short on milk | water=470, milk=200, beans=82 (unchanged) |
refill("milk", 300) |
milk topped up | water=470, milk=500*, beans=82 |
dispense("latte") |
โ served latte | water=440, milk=350, beans=64 |
* clamped to the milk tank's capacity (we'll set capacity = 500 ml).
Notice the key invariant in row 2: a blocked dispense changes nothing. We don't pour the water and then discover the milk is empty.
Sign in to continue reading
The rest of this lesson is available with a free account. Signing in with Google or Microsoft is free.
Sign in to read the full lesson