Maintenance Free Software

Please note: This article is only available in English.
In software design one metric seems to be undervalued: the cost of maintenance.

This post has been on my list for quite a while. I hope I can transport at least some of my thoughts into one coherent piece of writing. I know that the topic covered here is quite complex and has indeed many facets that need to be discussed in order to get a clear picture. So please bear with me in the following paragraphs.

Maintenance in the world of software is the act of taking care of a system. This can be required by manually performing a job (e.g., disk cleanup) or by making updates to configuration (e.g., change of URLs). It may also be important due to software bugs (e.g., crashes or security vulnerabilities). In any case this act has to be performed regularly. Adding features or enhancing the product is not included in regular maintenance. The duration and frequency of the involved activities determine the cost of maintenance.

So far so good. Ideally, our software should be maintenance free. We all know that this ideal world does not exist. Bugs will occur. Complicated or unforeseen things will happen. Requirements will change. So is the title a lie? Yes - in some sense it is. Maintenance free software does not exist, but I insist that we can a lot to live the dream. The question is what can be done and how we can impact current maintenance cost by writing new software.

For me a maintenance free software is one that does either not add any new maintenance duty to the system or which even lowers the overall cost of maintenance. A very simple example would be using serverless architecture. Here the cost of maintenance of the infrastructure is zero. However, we have added some other costs - like being more dependent on the provider, which leads to potentially required changes when the provider forces an upgrade on the hosted infrastructure. Also overall the architecture may not be the best fit for our problem, which is why complexity and other metrics may be worse than previously. All in all we may benefit here, but this is pure speculation and largely depends on the problem we try to solve.

Another example is the DRY principle. This one is broken in most companies / software systems I know. Rarely, this is a problem from the developers. Usually, the problem starts with the product owner or the management board. They insist on crappy formats such as Word to deliver some documentation. In the end we have a mixture of (Word) documents, code, and interface designs. As an example consider the definition of an plugin system based on JSON given in a Word document. The code managing the system is written in JavaScript, i.e., compilation errors won't happen. All bugs are either caught via (automatic at best, otherwise manual) testing or in production. Still, the whole API is laid out via a Word document. Here, typos are common. Even if no typos would be in there: A change in the API needs to be reflected in the document. A simple JSON schema could have been used in multiple places:

  • Checker to validate that a plugin is correct
  • Source for generating the documentation
  • Boilerplate to start new plugins

Therefore documenting things in code (here a JSON schema) would have solved all things in just one place.

The list goes on. Besides DRY we could also investigate how KISS could lead to less maintenance. The same arguments could then be used to see how SOLID works. Finally, once we see how valuable SOLID is Functional Programming is not far. But this all would go too much into the coding area. Of course, in my opinion coding can potentially solve all these problems, but this opinion may be too radical and inaccurate to be explored correctly. Instead, I now want to argue in favor of lightweight systems.

We now went through two examples that illustrated that maintenance free (i.e., maintenance optimized) software may be the result of choosing a better architecture or following key principles to avoid hidden dependencies or syncing problems. The third point tackles the dependency graph. The key factor to use containers (e.g., Docker) for me is an elegant solution to the dependency problem from the operations point of view. Consider a large software system that is built by one company (delivering the binaries) and operated by another company (taking care of the environment). Naturally, the two have to work very closely together. In reality, there will be a boundary. So the company making the deliverables has to create their own test environment. It will be very similar to the real environment(s), however, the differences are subtle and not documented. In order to do deployments a document is used (here we go again!). The document needs to created, updated, and verified. There will be mistakes, misunderstandings, and long deployment times (steps need to be followed manually). Arghs! The solution is simple. Each component that is created will be delivered with a container definition. The container defines all steps to be successfully created including all steps required for provisioning (e.g., firewall rules).

Having everything in code is super. One can write programs against the code to obtain more information (e.g., which ports are all used?). One can always be sure that the code works (automated testing + reproducible actions). And best of all: One can always execute the program. Example: What if a service needs to be duplicated? Instead of doing another deployment (following the document as outlined in the example), one would only need another service (automatic variant) or one command (manual variant) to perform another deployment. Easy!

So why are we so keen on having maintenance heavy software everywhere? Why do some companies still prefer versioning their software, e.g., 2.1.189 when in fact its either version 189 (it's an app after all!) or 62.7 (follow semver, no matter what)? I think the answer lies somewhere in the triangle of fear ("I did something and now 10 other things happened"), lack of knowledge ("I did not know about JSON schema"), and protection ("the risk of changing this component is too high"). In any case it is costing money and preventing some good things.

So what can we take away? When a new software component is written - always try to make it integrate seamlessly. If it can replace an existing component - great! If it duplicates work - bad... In the end every software component will require maintenance: make it worthwhile!

Created .

References

Sharing is caring!