Under the Hood

Requirements & constraints: what Fable had to be

Before any architecture, the forces that shaped every later decision. Fable is a group-expenses app, which sounds simple until you write down what 'simple' actually demands: money that's exactly right forever, a mobile client on flaky networks that you can't hot-patch, one developer's time and a near-zero budget, and real users who split dinners on trains. This opening chapter states the functional and non-functional requirements and the hard constraints — and shows how each one is the reason a later chapter chose what it chose.

Requirements & constraints: what Fable had to be

Every architecture is downstream of its requirements and constraints, and the honest way to read the rest of this series is to know the forces first — because almost every decision in the later chapters is forced, not free. Fable is a group-expenses app: people in a group (a trip, a flat, a couple) log shared expenses, the app tracks who owes whom, and people settle up. Splitwise-shaped. That one-line description sounds trivial, and the gap between how simple it sounds and what it actually demands is the whole reason there's anything to write about.

Functional requirements: what it does

The core, stripped to essentials:

  • Groups & membership — create a group, add people, everything scoped to a group.
  • Expenses — log a shared expense, split it among members (equally, by exact amounts, by percentage, or by shares), with one or more payers.
  • Balances — compute who owes whom, correctly, at any time.
  • Settlements — record that a debt was actually paid, with both parties agreeing.
  • Chat — a per-group conversation, because expenses happen in a social context ("who's paying for dinner?").

And the things Fable added around that core because a trip is more than a ledger: receipt photos and media, trip plans (the "Stash"), a generated trip recap, location sharing, polls. But the ledger is the heart — everything else is a companion to it.

Non-functional requirements: the properties that actually shaped the design

These matter more than the feature list, exactly as the interview framework insists, because they're what dictated the architecture:

  • Correctness above all. The entire product promise is that "you owe Priya ₹1,433.34" is exactly right, forever. A social feed can be slightly stale; a money ledger cannot be slightly wrong. This single requirement is why Fable is strongly consistent, single-writer, stores money as integers, and treats idempotency as non-negotiable.
  • Mobile-first, on hostile networks. Users add expenses on trains, in restaurants, in basements — on connections that drop mid-request. The app must feel instant (optimistic UI) and never lose or double-record a write when the network eats a response. This forced client-generated ids, idempotency keys, and persist-then-deliver chat.
  • Real-time where it matters. A shared expense should appear on everyone's screen immediately; a settlement confirmation should update both parties at once. Hence WebSockets.
  • Low latency, felt. Every screen should open fast — the Singapore→Mumbai migration happened because it didn't.

The constraints: the walls the design had to live inside

Requirements say what to build; constraints say what you're allowed to spend building it. Fable's were tight and specific, and they're the reason it looks the way it does:

  • One developer. Every piece of operational complexity — a service to run, a cluster to babysit, a datastore to back up — comes out of one person's time. This is the single biggest force toward simplicity: managed Postgres so I don't run failover, no message broker, no microservices, a single VM. Not because I don't know the distributed options — because I know what running them costs a solo maintainer.
  • Near-zero budget. The app launched targeting ~₹0/month for the first few hundred users, which drove the all-free-tier initial stack and the R2-for-zero-egress media choice. Cost was a first-class design input, not an afterthought.
  • A deployed mobile client I can't recall. Old app builds live on users' phones for months, so the API can never break backward compatibility within a version. The client is the constraint that makes the API contract rigid.
  • Store-compliance is mandatory, not optional. App stores require moderation, reporting, and blocking for any app with user content — so those shipped as requirements, not nice-to-haves.

The requirements-to-architecture map

Read the rest of the series as answers to these forces:

Requirement / constraintWhat it forcedChapter
Money exactly right, foreverInteger money, ledger-as-projection, idempotencyData model, Expense engine
Correct under concurrencyAdvisory locks, state machine, strong consistencySettlement flow
Mobile on flaky networksClient ids, idempotency keys, optimistic UIData model
Real-time updatesWebSockets, persist-then-broadcastReal-time chat
One developer, low budgetManaged Postgres, single VM, no brokerInfra evolution
Deployed mobile clientBackward-compatible versioned APIAuth & API design
Low latency, feltCo-located DB, CDN mediaInfra evolution

Interview takeaway

When a prompt lands ("design a splitting app," "design a wallet"), resist jumping to boxes. Do what this chapter does: state the functional core in a sentence, then spend your energy on the non-functional requirements and constraints, because those are what actually determine the design. "It's a money ledger, so correctness beats availability and I'll go strongly consistent" and "assume a small team and tight budget, so I'll favor managed services and one database until forced off them" are the sentences that show judgment. And name your constraints proudly — a design justified by its constraints reads as senior; a design that ignores them reads as a whiteboard fantasy. The rest of Fable, Deconstructed is what happened when these particular forces met real code; it starts properly with the high-level architecture.

Go deeper

Check yourself

Answer out loud, as if an interviewer asked. If you hand-wave, reread that section.

  1. State Fable's functional core in one sentence, then list the non-functional requirements, and explain why the latter shaped the architecture more than the feature list.
  2. The "correctness above all" requirement rules out a whole class of designs a social feed would happily use. Which class, and what three concrete decisions does it force?
  3. Give three specific architecture decisions that the "one developer" constraint forced, and explain why each is about operational cost rather than technical ignorance.
  4. Why does a deployed mobile client make the API contract rigid in a way a web frontend does not?
  5. Explain the claim that constraints made Fable better-designed, not worse. How do tight constraints enforce the exact discipline the interview framework rewards?
  6. For a "design a wallet" prompt, what would you state before drawing any boxes, and why is naming constraints a senior signal?