Why I store money as integers
There's a bug that shows up in almost every app that handles money before someone
stops to think about it: 0.1 + 0.2 === 0.30000000000000004. Floating point was
never designed to represent currency, and the moment you start adding, splitting,
and rounding amounts, the errors compound.
So on every project that touches money, I make the same early decision: store amounts as integers in the smallest unit — cents, or in Colombian pesos, just whole pesos.
The rule
- The domain never sees a
float. - An amount is an
intin the smallest currency unit. - Formatting to
$1,234.50is a concern of the edges (the UI), never the core.
Why it matters
When money is an integer, equality is exact. "Is this plan settled?" becomes
every balance === 0 — no epsilon, no "close enough". That single property makes
the rest of the system honest: the split function can guarantee that
sum(shares) === total, and the settle-up algorithm can trust the numbers it's
handed.
This is the same idea as domain at the core, infrastructure at the edges. The representation that keeps the math correct lives in the center; the pretty, locale-aware string is a detail of the boundary.
It's a tiny decision. It's also the kind of decision that's painful to reverse once balances are wrong in production — so I make it on day one.
Related notes
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.
Make decisions reversible
You can't reliably predict the right call. So optimize for cheap mistakes: prefer decisions you can walk back over ones you have to get right the first time.