One of the talks I do explains how ‘simple’ in the K.I.S.S.1 principle is not the same as ‘easy‘. Sometimes the easy option can introduce complexities into the system that become detrimental and actually introduce complexity. The simplest example is testing. Not testing is the easy option; but it introduces uncertainty and complexity into your system that will be difficult to pin down at a later date.
That said easy and simple are not mutually exclusive, which is an important thing to remember, especially when you’re caught in the throws of trying to fix a supposedly simple problem.
I spent far too many hours yesterday trying to write an install script for one of our components. The underlying issue is simple: “As someone installing the component, I want the configuration files to reflect the idiosyncrasies of my setup so that I can compile the code”. Or, if you prefer BDD format: “Given I am installing the component, when I perform the compile step, then the compilation should work”.
It all boils down to a bindings file which specifies the location of a couple of libraries and includes. The defaults specified in that file don’t work on everyones system, although they do work on live2.
My salutation was to write some code that iterated through the files, check if any were missing, and if so, prompt the user to give the correct locations. Great, except the format of
bindings.gyp is such that I needed to take a complex structure, flatten it, inject extra details so the user prompts made sense, and then reconstruct the complex structure from the flat one. Not wanting to hard code the format I then disappeared up my own backside with specially crafted config files and mappings from that to the format used by
nearly 200 lines of code in, deep in callback hell with grave concerns about whether my script would even pass code review I discovered some pretty nasty bugs that meant that minor configuration changes to a live server would cause an automated deploy to suddenly require user input, which we didn’t want. Adding logic to provide an override to this would make things even more complex and my nice, simple solution was disappearing out of reach.
It was then that it hit me that I was providing the wrong solution. This is something that really needs to be set once per environment and then left. It’s not going to be used a huge amount of time, it doesn’t need to be gold plated. With that in mind I wrote a simple shell script that checked for the presence of an environment variable. If the variable existed, use the bindings file it points to, if it doesn’t, use the default; simples.
All told, with error handling and everything, the script is 21 lines long. Not only that, but it provides a nice way to handle upgrades to the environment in live without having to redeploy.
1 Keep It Simple Stupid – in a nutshell, don’t overcomplicate things.
2 Something we wanted to maintain.