Designing BillParty offline-first: constraints as features
BillParty is a small app for splitting group expenses — a trip, a flat, a night out. It has no server, no login, no cloud sync. That sounds like a list of missing features. It's actually the whole point.
The constraint
I wanted BillParty on F-Droid, which means fully free software and, for this app, no network at all. No Firebase, no analytics, no calls to anyone's server. At first that reads as a limitation. But a hard constraint forces clarity: if the data can never leave the phone, a lot of design questions answer themselves.
Constraints clarify
No backend means no accounts to create — you open the app and use it. No sync means the state lives in exactly one place, the organizer's phone, so there's no conflict resolution to agonize over. Sharing becomes a snapshot — a text summary or a QR code — instead of a live, multi-device stream. For settling up after a trip, a snapshot is exactly right, and it's private by default because the data simply never travels.
What looked like "Splitwise but worse" turned into a genuinely different product: one that works in airplane mode and never asks anyone to sign up.
The architecture that falls out
With no network, the interesting code is all domain logic, so that's where the design energy goes. The core is pure functions — splitting an amount, computing balances, simplifying who-pays-whom — with money stored as integers so the math is exact. SQLite sits at the edge as a detail; the domain doesn't know or care that it's there.
The lesson I keep relearning: a constraint isn't the enemy of good design. Handled honestly, it is the design. The thing you can't do quietly tells you what the product should be.
Related notes
Why I built SendDock instead of paying for email tools
Transactional email and waitlist tools quietly turn expensive. SendDock is my answer: an open-source platform you can self-host and actually own.
Tests as living contracts
A good test suite isn't a safety net you tolerate — it's the executable specification of what your system promises, including the properties that must always hold.