We Added One Order Status And Four Hundred Trade Accounts Went On Stop

by Serguey Shinder

In November 2024 we started letting trade customers collect from our branches. The order system needed one new status for it, Collected, meaning the customer had signed for the goods at the counter. We added it, the branch screens used it, and for six weeks nothing appeared to be wrong.

Then our credit team noticed the number of accounts on stop had roughly doubled. An account goes on stop automatically when what a customer owes us, plus what they have ordered and not yet received, passes their credit limit. About four hundred builders and electricians had their orders held, most of them good payers, several of them furious, and none of them anywhere near their limit by any sensible reckoning.

The calculation that decided what counted as not yet received had been written in 2016. It took every order whose status was not Delivered, not Cancelled and not Returned. That was a perfectly accurate description of the world in 2016. Collected was not on the list, so every collected order stayed outstanding forever, and because collected orders are invoiced at the counter, each one was counted twice, once as an unpaid invoice and once as goods still on their way. Customers who collected regularly drifted towards their limit a little more every week.

Nobody had made a mistake you could point at. The person who added Collected had no reason to read the credit code. The person who wrote the credit code could not have known Collected would exist. Between them sat a rule written as a list of exceptions, and a list of exceptions makes a decision about every value nobody has invented yet. It decided, silently, that collection was a kind of not delivered.

When we went looking, we found thirty one places in the code that compared an order's status. Nineteen were written the same way, as everything except these.

We rewrote every one of them as a decision over the full set of statuses, with no catch all at the bottom, so that adding a status now stops the build in every place that has to decide what it means. The first time somebody added one afterwards, a status for orders held for a delivery slot, the build failed in twenty three places, and he spent a morning answering twenty three questions he would otherwise have answered in production. We also wrote a test that runs every status through every decision and fails if any of them is unhandled.

The four hundred accounts were released the same afternoon, with an apology from our credit manager to each one. The rule I took from it is short. When code says everything except these, it is making promises on behalf of people who have not joined the company yet.

– Serguey Asael Shinder

Leave a Reply