Our nightly reconciliation compares our ledger against a settlement file from a payments partner. It had been quiet for two years. In March it began reporting a difference of a few pence a night, which is exactly the size of thing that gets looked at last.
The job had a tolerance. One penny per order, written in on the day it was built, by someone sensible who did not want to be paged over rounding. So the thing it existed to catch was the thing it had been permitting since it was switched on.
Amounts arrive from the partner as JSON numbers with two decimal places. Our client deserialised them into doubles, because that is what a JSON number maps to by default in the library we use, and because nobody making that decision was thinking about money at the time. A double cannot hold most two decimal values exactly. On its own that is invisible: print it back with two decimals and it is right. The error only shows when you add. We sum the line amounts of an order, apply a tax rate, sum the orders into a daily figure, and round once at the very end.
Across ninety thousand orders in March our totals were out by four pounds and sixty one pence. Two hundred and seventeen individual orders differed from the partner's figure by a penny. One wholesale order with a quantity of eight thousand was out by thirty two pence on its own.
We parse the raw token into a decimal type now, which the library will do if you ask it to, and behind that boundary everything is an integer number of minor units. Rounding happens per line, half up, which is the rule the partner applies and which we now have from them in writing rather than by inference. Our contract tests carry a fixture of awkward values, the textbook ones and the ones out of that month's file.
The tolerance is zero. It failed eleven times in the first fortnight and every one of those was a real difference nobody had been telling us about.
A tolerance is a decision about what you are content not to know, and ours had been made in an afternoon and never once revisited.
– Sergey Shinder
Top comments (0)