A few years back, Mike worked at Initech. Initech has two major products: the Initech Creator and the Initech Analyzer. The Creator, as the name implied, let you create things. The Analyzer could take what you made with the Creator and test them.
For business reasons, these were two separate products, and it was common for one customer to have many more Creator licenses than Analyzer licenses, or upgrade them each on a different cadence. But the Analyzer depended on the Creator, so someone might have two wildly different versions of both tools installed.
Initech wasn’t just incrementing the version number and charging for a new seat every year. Both products were under active development, with a steady stream of new features. The Analyzer needed to be smart enough to check what version of Creator was installed, and enable/disable the appropriate set of features. Which meant the Analyzer needed to check the version string.
From a user’s perspective, the version numbers were simple: a new version was released every year, numbered for the year. So the 2009 release was version 9, the 2012 was version 12, and so on. Internally, however, they needed to track finer-grained versions, patch levels, and whether the build was intended as an alpha, beta, or release version. This meant that they looked more like “12.3g31”.
Mike was tasked with prepping Initech Analyzer 2013 for release. Since the company used an unusual version numbering schema, they had also written a suite of custom version parsing functions, in the form: isCreatorVersion9_0OrLater
, isCreatorVersion11_0OrLater
, etc. He needed to add isCreaterVersion12_0OrLater
.
“Hey,” Mike suggested to his boss, “I notice that all of these functions are unique, we could make a general version that uses a regex.”
“No, don’t do that,” his boss said. “You know what they say, ‘I had a problem, so I used regexes, now I have two problems.’ Just copy-paste the version 11 version, and use that. It uses string slicing, which performs way better than regex anyway.”
“Well, I think there are going to be some problems-”
“It’s what we’ve done every year,” his boss said. “Just do it. It’s the version check, don’t put any thought into it.”
“Like, I mean, really problems- the way it-”
His boss cut him off and spoke very slowly. “It is just the version check. It doesn’t need to be complicated. And we know it can’t be wrong, because all the tests are green.”
Mike did not just copy the version 11 check. He also didn’t use regexes, but patterned his logic off the version 11 check, with some minor corrections. But he did leave the version 11 check alone, because he wasn’t given permission to change that block of code, and all of the tests were green.
So how did isCreatorVersion11_0OrLater
work? Well, given a version string like 9.0g57
or 10.0a12
, or 11.0b9
, it would start by checking the second character. If it was a .
, clearly we had a single digit version number which must be less than 11. If the second character was a 0
, then it must be 10
, which clearly is also less than 11, and there couldn't possibly be any numbers larger than 11 which have a "0" as their second character. Any other number must be greater than or equal 11.
Mike describes this as a “time-delayed footgun”. Because it was “right” for about a decade. Unfortunately, Initech Analyzer 2020 might be having some troubles right now…
Mike adds:
Now, I no longer work at Initech, so unfortunately I can’t tell you the fallout of what happened when that foot-gun finally went off this year.