Learning pathsPricingA
Question Breakdowns

Splitwise

Design Splitwise expense sharing: exact money splits, balanced ledger, concurrent edits, idempotency and confirmed settlements.

Splitwise: Understand the building blocks

Choose a mechanism because it satisfies a requirement. These explanations describe the exercise design, not undisclosed implementation choices at the named company.

Splitwise: Quick vocabulary

TermMeaning and role in this exercise
API: Application Programming InterfaceThe contract for requests, responses and errors between components. An API route does not itself enforce every business invariant.
SQL: Structured Query LanguageA language for querying/manipulating relational data. Correctness still depends on constraints, transactions and isolation choices.
HTTP: Hypertext Transfer ProtocolThe request/response protocol used by web APIs and media fetching. Application retries still need safe operation identities.

Splitwise: Ledger and immutable revisions

What it means: A ledger is authoritative history of recorded monetary or obligation changes. Immutable revisions keep corrections auditable rather than overwriting the past.

Why this problem needs it: Expense edits must preserve a traceable zero-sum history.

How to use it: Commit an expense/revision and its balanced deltas together, use integer minor units with a currency policy, and reconstruct balances from accepted facts.

Example in this design: Shares 334,333,333 for a 1,000 expense produce net balances 666,-333,-333 when A paid.

When it fits: Useful when edits, retries and reconciliation must preserve an explainable balance.

Alternative and limits: Mutable balances can be faster to read but still need safe revision history and reconciliation. Recording a settlement is not proof an external payment occurred.

Splitwise: Relational database transaction and constraints

What it means: A relational store keeps structured rows; a transaction commits a bounded group of changes together. Constraints reject specified invalid states.

Why this problem needs it: Expense, shares, revision and operation result must agree after commit.

How to use it: Use primary/unique keys and a chosen isolation/locking protocol for the actual invariant. Atomically persist related rows and the operation result before acknowledgement.

Example in this design: Reject a set of shares that does not sum to the expense; enforce it within the transaction protocol.

When it fits: Useful for bounded cross-row correctness, joins and access paths that fit the relational model.

Alternative and limits: Key/value stores can fit simpler keyed operations. “SQL” alone does not prevent lost updates, validate every cross-row rule or coordinate an external provider.

Mechanism reference

Splitwise: Compare-and-set (CAS) and optimistic concurrency

What it means: A conditional write changes state only if an expected version or value still matches. The comparison and write share one atomic boundary.

Why this problem needs it: Two edits based on the same revision must not silently overwrite each other.

How to use it: Carry the version read by the caller; atomically compare, mutate and advance it. On conflict, re-read or reject under the business policy.

Example in this design: One expected-revision update succeeds and the competing stale edit conflicts.

When it fits: Useful when concurrent requests must not silently overwrite the same owned state.

Alternative and limits: Row locks or a serial owner can simplify highly contended updates. A read followed by an unconditional write is not CAS.

Splitwise: Projection and materialized view

What it means: A projection is a derived read model built from authoritative facts; it improves a particular read path and can be rebuilt.

Why this problem needs it: Fast balance reads can be rebuilt from accepted expense facts.

How to use it: Consume versioned facts with replay-safe updates, expose a watermark/revision, and compare or rebuild from the authoritative history.

Example in this design: After editing to 1,200, the net correction is 134,-67,-67; replay applies that revision once.

When it fits: Useful when read shapes or volume justify duplicating computation/state.

Alternative and limits: Read authoritative rows directly for a simpler strongly current baseline. A stale projection must not grant revoked access or decide a strict inventory transition.

Splitwise: Ledger records expense 1000 paid by A; Shares 334,333,333 conserve the exact total; Net balances are 666,-333,-333: sum zero; Transaction and request identity prevent double posting
Splitwise: connect a named mechanism to the requirement and an exact exercise trace.
Read the diagram

Ledger records expense 1000 paid by A; Shares 334,333,333 conserve the exact total; Net balances are 666,-333,-333: sum zero; Transaction and request identity prevent double posting

Open original
Splitwise: worked example
Splitwise: Ledger records expense 1000 paid by A; Shares 334,333,333 conserve the exact total; Net balances are 666,-333,-333: sum zero; Transaction and request identity prevent double posting

Splitwise: connect a named mechanism to the requirement and an exact exercise trace.

Define expense sharing before designing payments

For “design Splitwise,” ask whether the system records shared expenses and settlements or actually transfers money. This original exercise records group expenses, per-currency obligations and confirmed manual settlements. It does not initiate bank transfers. A payment integration introduces provider idempotency, unknown outcomes and reconciliation; compare Payment System. Product names are prompts, not private implementation claims.

A share is the part of an expense a participant owes. A ledger is authoritative history from which balances can be reconstructed. A projection is a convenient derived view. A settlement records a reduction of an obligation under a declared confirmation policy. A record saying “paid” is not independent evidence that money moved outside the application.

Ask the questions that change correctness

AskAssumption for the worked designConsequence
Groups, individual expenses or both?Groups with bounded membershipGroup identity and permission scope every query/write
Equal, exact, percentage or weighted splits?Equal and exact amounts firstValidation and deterministic rounding depend on split type
One or several payers?One payer in the baselineMultiple payers add contributions whose total must equal the expense
Currency and conversion?Separate currency ledgers, no automatic conversionDo not add INR and USD or infer an exchange rate
Edits/deletes and audit history?Versioned corrections, retained historyReversal/replacement must be atomic and authorized
Settlements versus real transfer?Confirmed manual record; no bank chargeProvider results are outside the current system boundary
Membership changes and privacy?Current members may read; removed members' obligations remain under explicit policyAccess revocation is different from debt cancellation
Scale, skew and freshness?One million expenses/day, groups capped at 100 in this exerciseAtomic owner and bounded reads before extra services

Open: “I’ll design recording and correcting shared expenses and tracking per-currency balances. I’ll exclude actual transfer and currency conversion unless you want those as deep dives. How should rounding and settlement confirmation work?”

State the invariants and round deliberately

Every expense has an integer amount in the currency's declared minor unit. Do not hard-code two decimal places for all currencies. Participant shares sum exactly to that amount. Ledger deltas sum to zero within each expense revision/currency. The payer's credit and participants' debits are facts of the same committed operation. Replaying one request does not create another expense.

In this illustrative currency, 1,000 minor units split equally among A, B and C produces shares A=334, B=333, C=333. Divide using integer quotient 333 and distribute the remainder 1 in a documented stable participant order. If A pays the entire expense, net deltas are A=+666, B=-333, C=-333. A also owes its own share, so A is not credited the full 1,000 as a net balance.

Expense 1000 is split into 334,333,333; payer A's net credit is 666 and all ledger deltas sum to zero.
Integer shares, payer contribution and net obligations must reconcile.
Read the diagram

A pays 1000; A, B and C share equally → Integer quotient is 333; remainder is 1 → Stable participant order assigns shares 334, 333, 333 → Net = paid − owed: A +666, B −333, C −333 → Conservation check: 666 − 333 − 333 = 0 → Currency scale is declared; do not assume every currency has cents

Open original
Split 1000 minor units without losing a unit
Expense 1000 is split into 334,333,333; payer A's net credit is 666 and all ledger deltas sum to zero.

Integer shares, payer contribution and net obligations must reconcile.

Exact splits reject totals other than the expense amount. Percentage/weighted splits require a declared input precision and remainder policy rather than floating-point summation. Zero/negative amounts, invalid currency, duplicate participant IDs and nonmember participants need explicit validation. Refund/correction behavior is a separate operation, not an unexplained negative expense trick.

Model immutable facts and revision ownership

Contract / pseudocode
groups(group_id,version)
memberships(group_id,user_id,status,role)
expenses(expense_id,group_id,currency,amount_minor,payer_id,current_revision)
expense_revisions(expense_id,revision,actor_id,request_id,state)
ledger_entries(expense_id,revision,user_id,currency,delta_minor)
request_keys(group_id,actor_id,request_key,request_hash,result_id)
settlements(settlement_id,group_id,currency,from_user,to_user,amount_minor,state)
Contract / pseudocode
POST /groups/{id}/expenses {requestKey,currency,amountMinor,payer,shares}
PUT /expenses/{id} {requestKey,expectedRevision,newAmount,newShares}
GET /groups/{id}/ledger?currency=...&cursor=...&limit=...
POST /groups/{id}/settlements {requestKey,currency,from,to,amountMinor}
GET /groups/{id}/balances?currency=... -> balances, projectionRevision

Authenticate the caller and authorize the group/object operation. Atomically validate membership policy, claim request identity, insert the revision and ledger entries, and advance the current expense revision. Unique identities and constraints protect local boundaries; cross-row share conservation needs a transaction/procedure or another enforcing owner, not a CHECK on one unrelated row. Select a relational store for these bounded transactions as a baseline; name the constraints/access paths rather than claiming every SQL database transaction prevents every anomaly.

One million expenses/day is about 11.6 writes/s average, 116/s at a 10× peak. At an illustrative 2 KB per expense/history footprint before further corrections, raw growth is about 2 GB/day; replica/index overhead and retention are separate. Large groups, repeated edits and ledger reads can dominate differently, so state the group cap and bounded pagination instead of sharding reflexively.

Follow create, correct and read

An authorized write commits an expense revision and conserved ledger facts; a balance projection follows and can be rebuilt.
Authoritative ledger facts and convenient balance reads have different guarantees.
Read the diagram

Client sends group-scoped request key and expense payload → Transaction checks membership, key payload and expected revision → Insert balanced immutable postings, revision and outbox event → Commit all rows together; timeout leaves outcome unknown → Same key retrieves committed result; conflicting payload rejects → Projection consumes unique event IDs; rebuild from ledger if needed

Open original
Commit the expense once; balances are a projection
An authorized write commits an expense revision and conserved ledger facts; a balance projection follows and can be rebuilt.

Authoritative ledger facts and convenient balance reads have different guarantees.

A create retry with the same caller-scoped key and request fingerprint returns the original expense result. Reusing that key with different shares is a conflict. A balance cache is keyed by group, currency and applicable policy/revision. It must not bypass current authorization. The response exposes its projection revision when lag is permitted; a correctness-critical settlement decision consults the authority or a projection proven current under the chosen contract.

To correct expense e7 revision 1 to revision 2, reverse the old effects and post the new effects atomically, preserving the audit history. For the 1,000 example, replacing the amount with 1,200 and equal shares changes A's net credit from 666 to 800 and B/C from -333 to -400. The adjustment is +134,-67,-67, summing to zero. A second editor submitting expectedRevision=1 after revision 2 commits gets a conflict, not an extra reversal.

Only one correction advances e7 from revision 1 to 2; its conserved adjustment is applied once, and a stale editor is rejected.
Version checks protect the correction and its corresponding ledger effects together.
Read the diagram

Revision 1 nets: A +666, B −333, C −333 → New amount 1200; each share 400; nets +800, −400, −400 → Adjustment postings: A +134, B −67, C −67 → Adjustment sums to zero; original history remains intact → Expected revision 1 advances atomically to revision 2 → Another edit with expected revision 1 conflicts; reload and retry

Open original
Edit an expense with a balanced adjustment
Only one correction advances e7 from revision 1 to 2; its conserved adjustment is applied once, and a stale editor is rejected.

Version checks protect the correction and its corresponding ledger effects together.

Simplify debts without inventing money

Net balances A=+666, B=-333, C=-333 can be represented as B owing A 333 and C owing A 333. A simplification proposes transfers preserving each person's net per-currency obligation. It does not prove a minimum number of transfers for every general problem, and it must respect any agreed restrictions on counterparties/groups. Do not simplify across currencies or groups whose obligations may not legally/product-wise be netted.

A confirmed manual settlement B→A of 100 reduces B's debt by 100 and A's credit by 100: new net balances A=+566, B=-233, C=-333. Stable settlement identity prevents replay from applying it twice. Define who can confirm, how the other party disputes it and whether overpayment is permitted. Do not silently let an untrusted client declare arbitrary other members' debts paid.

If real payment is added, record intent and an explicit pending/unknown/succeeded/failed outcome. A provider timeout is unknown; retry/reconcile the same provider identity. Do not modify the authoritative debt as definitively paid merely because an HTTP request was sent. That is a new product boundary, not a small UI feature.

Handle failures and operate safely

FailureRequired behavior
Response lost after create commitRetry returns the existing expense; history is not duplicated
Two editors read revision 1One conditional correction wins; loser rereads and resolves conflict
Projection worker replays an eventRevision/entry identity prevents an extra balance effect
Projection is rebuilt while edits continueCapture a source position, replay through a known boundary, verify before switching
Member removed with an unpaid sharePreserve the agreed financial record; revoke access under a separate policy
Settlement confirmation duplicatedOne ledger effect per settlement identity

Track rejected invalid splits, conservation violations, stale-edit conflicts, projection age and reconciliation differences. Use a bounded ledger rebuild/checkpoint process. Alert on a mismatch between authoritative facts and balances rather than “repairing” it with an untraceable mutable total. Group-scoped access logs should avoid logging sensitive expense descriptions or authentication tokens. Storage, history growth and projection reads are the baseline cost drivers.

Foundation, senior and staff explanations

Foundation: define shares/ledger, compute the 1,000-unit example, draw an authorized write/read and explain replay. Intermediate: add pagination, revision conflicts and cache freshness. Senior: show an atomic correction, a recoverable projection and settlement uncertainty; identify authorization and observability boundaries. Staff: compare synchronous balances against asynchronous projections for actual workloads, plan migration/reconciliation with no double posting, define group-domain ownership and specify rollback/read cutover gates.

Practice before revealing the answer

Deliver clarifying questions, the three conservation/replay invariants, record/API model, a complete create-and-read path and the e7 correction trace. Add an edit arriving during a balance rebuild. For staff depth, require that old and new clients continue during a schema migration.

Question: Is giving A a net credit of 1,000 correct when A also owes an equal share?

Show answer and explanation

Answer: No. A's own share is 334, so A's net credit is 666. B and C owe 333 each. All deltas must reconcile to zero.

Question: Can a client set the cached balance to its newly calculated total after editing?

Show answer and explanation

Answer: That can overwrite another committed change or trust unauthorized input. The ledger revision owner validates and commits the correction; projections follow a replay-safe protocol.

Primary documentation: PostgreSQL constraints and transaction isolation. These explain selected database mechanisms; the ledger policy, rounding and scale are independent exercise assumptions.

Decision review: Splitwise

Splitwise: What it is

An expense-sharing design records who paid and who owes under an explicit currency, rounding and revision policy.

Splitwise: Why it is needed

Balances are derived views; rounding and edits must preserve per-currency conservation and author authorization.

Splitwise: When to use it

Use immutable expense facts and balanced adjustments when history, auditability or correction matters; distinguish recording settlement from actually moving money.

Splitwise: How to use it

Compute shares in integer minor units using a deterministic remainder rule. Atomically publish a revision and its balanced adjustments. Rebuild balances from applicable facts, without combining different currencies silently.

Splitwise: Compare an alternative

Overwriting an expense is simpler but loses history unless another audit mechanism preserves it. Automatic cross-currency settlement introduces exchange-rate and fee contracts outside ordinary expense splitting.

Splitwise: Worked decision exercise

The following inputs and policies are original exercise assumptions; they are not measurements or undisclosed company behavior.

A pays 1,000 units shared equally with B and C. Assign shares 334,333,333 in a stable order; nets are +666,-333,-333. Editing the amount to 1,200 gives +800,-400,-400, so the balanced adjustment is +134,-67,-67.

Splitwise: 1000 split as 334,333,333: nets +666,-333,-333; Edit to 1200: nets +800,-400,-400; Adjustment +134,-67,-67 sums to zero; Expected revision prevents two conflicting edits
Splitwise: a concrete state and recovery trace under the exercise assumptions.
Read the diagram

1000 split as 334,333,333: nets +666,-333,-333; Edit to 1200: nets +800,-400,-400; Adjustment +134,-67,-67 sums to zero; Expected revision prevents two conflicting edits

Open original
Splitwise: worked example
Splitwise: 1000 split as 334,333,333: nets +666,-333,-333; Edit to 1200: nets +800,-400,-400; Adjustment +134,-67,-67 sums to zero; Expected revision prevents two conflicting edits

Splitwise: a concrete state and recovery trace under the exercise assumptions.

Can two editors both publish a correction based on revision 1?

Show answer and explanation

Answer: Not under an expected-revision rule: one advances the revision and the other receives a conflict. A retry with the same operation ID returns its committed result. The adjustment sums to zero, and recording a settlement does not prove a provider transferred money.

Splitwise: Check the design

Verify rounding, revision replay, membership changes and independent currency ledgers. Compare a rebuilt balance projection with canonical expense facts.

Your study notes