~/problems / Simulation & OOP design / Object-oriented design and extensible simulations

Basics: a bank account class with invariants

easy basics ~10 min

Most design rounds start the same way: turn a small domain into a class whose state can never become invalid. Here the rule is simple: a balance never goes negative, and a failed operation changes nothing.

Implement class Account:

  • Account(owner, balance=0) stores the owner's name and a starting balance (a non-negative integer, in cents).
  • deposit(amount) adds amount to the balance.
  • withdraw(amount) subtracts amount from the balance.
  • transfer(other, amount) moves amount from this account into the Account other.
  • balance() returns the current balance.
  • history() returns a list of this account's successful operations, oldest first, as (kind, amount) tuples. kind is "deposit", "withdraw", "transfer_out" or "transfer_in".

Validation, all raising ValueError:

  • amount must be a positive integer for all three operations (0 and negatives are rejected).
  • withdraw and transfer raise if the balance is too small.
  • transfer raises if other is this same account.
  • The constructor raises if the starting balance is negative.

When an operation raises, neither account's balance or history may change.

a = Account("ann", 100)
b = Account("bob")
a.deposit(50)
a.transfer(b, 120)
a.balance(), b.balance()   # (30, 120)
a.history()                # [("deposit", 50), ("transfer_out", 120)]
b.history()                # [("transfer_in", 120)]
a.withdraw(31)             # ValueError: insufficient funds; a.balance() is still 30

Two classic traps: every account needs its own history list (watch out for mutable default arguments or class-level lists), and history() should return a copy, so a caller can't edit your account's state through it.

Show hint

validate first and mutate last: check every rule at the top of each method, and only then touch the balances and histories.

Topic: Object-oriented design and extensible simulations. Classes that survive new requirements: games, payments, subscriptions, refactors.

0:00
Ctrl ' run · Ctrl ↵ submit
esc