Roadmap › Low-Level Design (LLD) — Object Design, UML and Classic Problems in C# › Module: Classic LLD Problems
Lessons in this course (8)
8. Design expense sharing (Splitwise) and movie ticket booking
AdvancedMediumLesson 8 of 8
Expense sharing: users, groups, expenses split equally/exactly/by percentage (Strategy), balances between pairs, "simplify debts".
csharp
public interface ISplitStrategy { Dictionary<string, decimal> Split(decimal amount, IReadOnlyList<string> users, IReadOnlyList<decimal>? values); }
public sealed class EqualSplit : ISplitStrategy
{
public Dictionary<string, decimal> Split(decimal amount, IReadOnlyList<string> users, IReadOnlyList<decimal>? _)
{
var share = Math.Round(amount / users.Count, 2);
var result = users.ToDictionary(u => u, _ => share);
result[users[0]] += amount - share * users.Count; // put rounding remainder on the first user
return result;
}
}
public sealed class Ledger
{
private readonly Dictionary<(string From, string To), decimal> _owes = [];
public void AddExpense(string paidBy, Dictionary<string, decimal> shares)
{
foreach (var (user, amount) in shares.Where(s => s.Key != paidBy))
_owes[(user, paidBy)] = _owes.GetValueOrDefault((user, paidBy)) + amount;
}
public decimal NetBalance(string user) =>
_owes.Where(o => o.Key.To == user).Sum(o => o.Value) - _owes.Where(o => o.Key.From == user).Sum(o => o.Value);
}Movie ticket booking (BookMyShow): entities Movie, Theatre, Screen, Seat, Show, Booking, Payment. The hard part is seat locking: when a user selects seats, lock them for e.g. 10 minutes; confirm on payment or release on timeout; two users must never book the same seat.
csharp
public interface ISeatLockProvider
{
bool TryLock(Guid showId, IReadOnlyList<string> seats, string userId, TimeSpan ttl); // atomic all-or-nothing
void Unlock(Guid showId, IReadOnlyList<string> seats, string userId);
bool IsLockedBy(Guid showId, string seat, string userId);
}
// Implementation: in-memory with a lock for one server; Redis SET NX PX per seat or a DB unique constraint on (ShowId, SeatId) for many servers.Flow: GetAvailableSeats(show) → TryLock(seats) → create Booking (Pending) → payment → Confirm (Booked, unique row per seat) or release on failure/timeout.