Home/Low-level design/Expense Sharing System

Expense Sharing System

Integer accounting and idempotent operations

Money uses integer cents, and every expense preserves a zero-sum balance vector. Equal division allocates the remainder deterministically by sorted member name. Floating-point rounding is unnecessary and would make cent conservation harder to guarantee.

go
total, count := 10, 3
base, remainder := total/count, total%count
fmt.Println(base, remainder) // 3 cents each, one extra cent to allocate

Idempotency spans both expense and settlement methods. Canonical expense identity ignores participant order but preserves membership, payer and total. Retry recognition occurs before current-balance checks so a completed settlement remains safely retryable. Settlement suggestions operate on copies and use a deterministic greedy pairing; they do not claim a globally minimal transfer count.

Go models this service with a struct and pointer-receiver methods. Constructor functions return a pointer; validation failures return errors rather than panicking. Scalars in snapshot structs are copied by value. Maps, slices, and optional pointers still require detached copies when crossing the service boundary. Go maps do not have key iteration order; use ordered slices for ranked results. There are no threads, persistence, wall-clock reads, or external side effects in this exercise.

Put it into practice

Implement the exercise in a full-screen workspace, then run its tests.

Open practice