Requirements checklist
Ask, one at a time, absorbing each answer:
□ split kinds equal / exact / percentage — shapes the hierarchy □ invalid split behavior reject whole expense, atomically □ money representation integer minor units; never floats — say why □ leftover on uneven splits sums-exactly invariant; deterministic policy □ groups vs ad-hoc a group is a scope, not a wallet □ settlement semantics recorded entry; no real money moves □ edits/deletes usually out of scope — leave the append-only seam
The core model
Entry (record) expenses + settlements, append-only, immutable Split (hierarchy) shares(totalMinor, participants); validation INSIDE each kind Equal base + deterministic leftover (sorted order, first get +1) Exact sum(amounts) == total or reject Percentage basis points (10000 == 100%), largest-remainder rounding Ledger PairKey(min,max) -> signed net; stated sign convention addExpense shares (validates) -> apply per non-payer -> append record recordSettlement SAME write path — apply + append settleUp (read) net positions -> greedy max-debtor/max-creditor heaps
Invariants: shares sum exactly to total · ledger == fold(record) · one write path · no floats anywhere · invalid split leaves no partial state.
Principles demonstrated (name them at the decision)
- Separation of record and derivation — expenses are truth, balances are arithmetic; every balance can explain itself.
- Single responsibility — each split kind owns its shares and its validation; rounding has exactly one site.
- Open/closed — a new split kind is a new class carrying its own validation; no central switch to forget.
- One write path — settlements are ordinary entries, not a special case; one place for atomicity, idempotency, and correctness.
Complexity facts
addExpense O(participants) merges after share computation
getPairBalance O(1) hash lookup; per-user net O(counterparties)
settleUp greedy heaps, O(n log n), <= n-1 transfers
fewest-transfers-OPTIMAL is NP-hard — greedy is a
heuristic; say so unprompted
What earns points, per report dimension
- Requirements & interface — you interrogated money (representation, rounding) and pinned split validation, group semantics, and record-only settlement before designing.
- Core design & invariants — record-first layering stated in words, validated split hierarchy, canonical pairwise ledger with a sign convention, one write path.
- Extension probe — the round will move the requirements; points come from naming the change surface precisely: which layer absorbs it, which seams protect the rest, and confessing honestly if your structure can't.
- Complexity honesty — costs justified from your own keying; the greedy presented as a heuristic with the NP-hard caveat.
- Communication — money decisions narrated with concrete numbers; probes answered directly, layering named in plain words.