5. Design Splitwise
Difficulty: Medium Topics: Strategy Pattern, Graph Simplification, Observer Pattern Key Concepts: Managing debts, different split types (Equal, Exact, Percent).
Phase 1: Requirements Gathering
Goals
Design an expense sharing application.
Identify users, groups, and expense types.
Define how debts are recorded and settled.
1. Who are the actors?
User: Adds expenses, views balances, settles debts.
Group: A collection of users sharing expenses.
System: Calculates splits and updates balances.
2. What are the must-have features? (Core)
Add Expense: User pays, others owe.
Split Types: Support Equal, Exact, and Percentage splits.
Balance Sheet: Show net balance per user.
Settle Up: Record payments to clear debts.
3. What are the constraints?
Validation: Percentages must add to 100%. Exact amounts must equal total.
Precision: Handle currency rounding (2 decimal places).
Phase 2: Use Cases
UC1: Add Expense
Actor: User Flow:
User selects a group or friends.
User enters total amount and selects split type (e.g., Equal).
System validates the split.
System calculates individual shares.
System updates the Balance Sheet (Graph).
System notifies involved users.
UC2: Settle Up
Actor: User Flow:
User A pays User B X amount.
System records a "Payment" transaction.
System updates the debt graph (A owes B reduced by X).
Phase 3: Class Diagram
Step 1: Core Entities
SplitwiseService: Facade for operations.
ExpenseManager: Manages expenses and balances.
Expense: Stores details (amount, payer, splits).
Split: Abstract class for split logic.
User: Participant.
Step 2: Relationships
Expensehas-manySplit.SplitreferencesUser.ExpenseManagerhas-manyExpense.
UML Diagram
Phase 4: Design Patterns
1. Strategy Pattern
Description: Defines a family of algorithms, encapsulates each one, and makes them interchangeable.
Why used: Different split types (
EqualSplit,ExactSplit,PercentSplit) require different validation and calculation logic. Strategy allows adding new split types easily.
2. Observer Pattern
Description: Defines a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically.
Why used: To notify group members when an expense is added, modified, or settled, ensuring all users have up-to-date balance information.
Phase 5: Code Key Methods
Java Implementation
Phase 6: Discussion
Debt Simplification
Q: How to simplify debts (minimize transactions)?
A: "Use a Min-Heap and Max-Heap. Calculate the net balance for each user (Credits - Debts).
Push users with
net > 0to Max-Heap (Creditors).Push users with
net < 0to Min-Heap (Debtors).Pop max creditor ($C$) and max debtor ($D$).
Settle amount
min(|D|, |C|).Update remaining balance and push back to heaps if not zero.
Repeat until heaps are empty."
Scalability
Q: How to handle millions of users in different groups?
A: "Use Consistent Hashing to shard the database. Since most expenses are within a
Group, shard byGroupIDand ensure all group data resides on the same DB shard to avoid expensive cross-shard transactions when adding expenses or settling up."
Concurrency
Q: Handling race conditions (two people editing same expense)?
A: "Use Optimistic Locking (versioning) on the Expense object. If version mismatch during save, prompt user to refresh. If high contention is expected, queue updates per group in Kafka and process them sequentially via a dedicated worker."
Financial Precision (SDE-3 Concept)
Q: How do you handle $100 split 3 ways ($33.33)? Who pays the extra $0.01?
A: "Use
BigDecimalfor all calculations to prevent floating-point errors. For rounding remainders: calculate exact shares (amount / participants). Distribute the integer pennies evenly. If there's a remainder (e.g., $100 / 3 = $33.33 with $0.01 left over), distribute the remaining pennies randomly or give them to the payer."
SOLID Principles Checklist
S (Single Responsibility):
Expensestores data,ExpenseManagercalculates logic,Splitdefines type.O (Open/Closed): New
Splittypes (e.g., specific share) can be added by extendingSplit.L (Liskov Substitution):
EqualSplitworks whereverSplitis needed.I (Interface Segregation): Not heavily used, but interfaces are clean.
D (Dependency Inversion):
ExpenseManagerdepends onSplitabstraction.
Last updated