I was looking at some $WORK code recently. It had a lot of “stuff” in configuration. This seemed wrong to me, but I wasn’t sure why it bugged me. Thinking about it more, I realized that I had developed a set of unarticulated rules that guide my thinking about configuration.
These guidelines are applicable to more than configuration. A setting can be exposed to non-developers through a configuration file, command line switches, environment variables, etc. However, it seems like configuration files are the most common developer error.
Why does this matter? First, moving behavior into configuration increases the complexity of the code. It’s one more thing for someone working on the code to understand. It requires them to understand your configuration format, and how the code translates that configuration into data and acts on that data. A complex configuration file is essentially another piece of code.
Second, it is a potential support burden. Once you’ve exposed something via an external interface, it becomes more difficult to take back. This parallels the notion that a module’s API should be as small and narrow as possible.
Finally, configuration can make it more difficult for a developer to get things running at all.
Here are my guidelines for when to expose a setting to the user:
Ideally, code should be runnable from a source control checkout.
Catalyst provides a good example. Its built-in server is perfect for development, and even builds in useful debugging options. It’s not appropriate for most production setups, but it works great for development.
If a configuration change requires an accompanying code change, it’s not configuration.
In the $WORK code I looked at, there is a version number defined in the configuration. This code builds an XML file, and the version in the configuration defines the version of the associated XML Schema for that XML file. However, if the schema were to change, the code generating the XML would also have to change. Bumping the version in the configuration file without changing the code would mean that the generated XML has the wrong version. The version should be defined as a constant in the code.
Conversely, if this is data that the developer cannot know the right value of when coding, then it should be externally settable. An obvious example is the ip address a daemon should listen on. Note that this doesn’t necessarily require a configuration file. In the daemon case, a command line switch may be sufficient.
If the configuration item is essentially a data structure only the developer understand, it’s not configuration.
Again, back to the $WORK example. The config file defines a massive mapping from database columns to XML attribute names. While in theory this could be configurable, in practice it is so complicated that no one but a developer working on the code has any use for it. This might as well be a constant data structure in the application code.
Avoid configuration. If you’re an expert, then avoid configuration, mostly.
Ultimately, configuration is just another API that someone has to maintain. It adds complexity and bulk to the code. Avoid it whenever you can.