From June 2013 through mid-February 2014, I have worked almost exclusively on rewriting our town’s water billing system. It works in conjunctions with our AMR system. That system serves as a store and forward mechanism, which sends meter configuration changes to our hosted application, and also collects daily reads for every water meter in our “district”.
We chose Perl for the implementation language, but even more important than the implementation language were the choices we made to avoid special casing and to make things flexible. Here is one example, a meter that measures the amount of water your home or business uses, is completely different from a fire service line. A fire service line is required to provide a separate source of water to fire suppression sprinklers.
Despite these differences, our software treats these two entities similarly. Every meter has a row in the meter table, and every fire service also has a row in the meter table. With this, software can go look up the charge for a fire service line, just as if that line were a meter. This avoided special casing in the main software, and, what I’ve found over the years is when data can be treated similarly, there are fewer checks and things that can go wrong in software. One way of looking at this is the special casing moves from conditional testing in software to the data itself.
In the case of a meter or a fire service, the data contains the decision-making. A column in the meter table contains a value, that if not present means the data represents a meter. If a known value is present, the data represents a fire service line. There are fewer checks in the software.
This isn’t a unique discovery. I certainly didn’t invent it. It just seems hard to practice when you are under a tight deadline for a project, but it seems to pay off handsomely at the end.