OOD Worked Examples
1. A preserved invariant can still hide wrong behavior
The legacy account subtracts before checking funds. With balance 10, withdraw 12 returns False but leaves -2. Moving the check before mutation repairs the failed operation contract. Clamping to zero would preserve nonnegative balance but still violate unchanged-state rejection. Test the result and both state observations.
The repaired trace is 10/(), rejected 12 -> 10/(), deposit 5 -> 15/(5,), withdraw 3 -> 12/(5,-3). The transition argument maintains opening + sum(history) = balance. The two lab representations agree on public behavior while differing in costs; no concurrency or storage guarantee follows.
2. A getter can leak through two layers
rows = [{'minor': 10}]
outer_copy = tuple(rows)
rows[0]['minor'] = 20
assert outer_copy[0]['minor'] == 20
value_snapshot = tuple(row['minor'] for row in rows)
rows[0]['minor'] = 30
assert value_snapshot == (20,)
The second representation freezes the observations needed by this contract. It does not preserve an API expecting mutable transaction records; that migration must be stated. Copying only the list prevents structural mutation through that list, not mutation through aliases to nested records.
3. A neat extraction changes failure behavior
Original order: consume/calculations, then output. Proposed order: output header, output rows, then calculate. If calculation raises, the proposed version has already changed external state. With a generator, a second traversal is exhausted. For the lab, consume and validate once, build the escaped output, then make one write. This takes linear memory and prevents output on input failure; a sink that partially writes then raises still cannot be rolled back by this function.
4. An interface with one provider can be useful
A timestamp policy uses one system clock in production but needs a deterministic clock in tests. The seam solves a present problem. A second formatting interface that simply wraps one stable expression may instead add navigation cost. Count neither as automatically good or bad: name the current benefit, migration cost and revisit trigger. A callable is sufficient for many small injected policies.
Transfer
If a new account provider requires withdrawals of at least 2, a client withdrawing 1 from balance 3 exposes incompatibility with the original contract. If the supertype explicitly permitted provider-specific minima, the client obligation would be different. Use the labs, then attempt the practice tasks before their key.