How to write software that will keep working for decades without problems

Published on 2021-11-08.

I think that most people in the software industry have been in the situation of running a legacy system that everyone dreads because it was developed on a platform that was outdated a long time ago. In this article I will address the issue of how you develop software that keeps running without fear of breakage even when you upgrade to the latest version of the platform that the system is running on.

There are situations in which breakage is unavoidable, but you can mitigate the risk of breakage substantially if you follow a few basic and important ground rules.

Avoid the hype and the shiny - always choose boring technology

Use "boring" technology. Boring technology is technology that has been battle tested and proven. It is technology that is well understood. This is important because boring technology rarely changes, but even when it changes, you can rely firmly on most of the basic features, which brings us to the next point.

Make custom code

Some platforms and programming languages change even basic functionality without caring about backwards compatibility, and even those that try to be backwards compatible occasionally break because of some unforeseen problem or feature that needs to be addressed - it's almost a natural part of the evolution of software. By avoiding the usage of platform dependent code and instead make your own, you can eliminate this problem almost completely. The more code you make yourself, the less reliant you become on the platform.

Now, I am not saying that you should write a custom version of the entire standard library by yourself, and then use that. What I am saying is simply this: Avoid too much dependency on third party code or code that is subject to deprecation. Some programming languages has a compatibility promise, while others simply doesn't care.

Still, even when the programming language provides you with a specific standard function that you need, if your system depends upon this function for some very important feature, you should consider making your own function and use that instead. This way you eliminate the dependency on the provided function and you can be completely sure that the specific function will keep working even if the standard function gets deprecated.

The downside of this strategy is that it takes a bit longer to develop the software, but the long term benefit can be huge.

Avoid frameworks like the plague

Frameworks adds yet another layer of complexity on top of what is already provided by the standard library and custom code. Very rarely is the added complexity of frameworks justified. Only "toy" software and very small applications can justify the usage of frameworks and the likes.

Libraries are not the same as frameworks, but even libraries can cause major problems. The more complexity you add to a software project the more you risk breaking the software down the line.

Consider how much of a library you really need and consider extracting only the parts that you need or make your own custom functions that provide that exact same functionality.

I have heard the argument that using a popular framework is a must when you're dealing with a team of developers because then everyone will know that framework and understand the software, if you develop your own solution then nobody will understand the software. That is a bogus argument. Being a software developer requires that you're able to understand code. Some code can be more difficult to understand that other code, but it has nothing to do with using a framework.

Many frameworks nowadays have become so stupidly complex that they almost require more time to understand that the underlying programming language.

Document everything

One requirement for making quality software is documentation, so make sure you document everything from the very beginning and make sure you adopt a well defined coding style. That way even a junior developer can investigate and understand the software well.

Running with well documented in-house solutions guaranties that nothing is suddenly changed, removed or added that will break stuff next time you upgrade the platform.

However, some clients just don't get it! They want the solution done yesterday and understand absolutely nothing about the long term consequence. I cannot count the number of times a client has insisted on a quick solution with the following argument:

I understand what you're saying, but we need this done now! Later, when we have made a ton of money, we can concentrate on security, performance and long term support!

In every single situation - without exception - this has turned out to be a disaster.

It's easy and quick to make junk. Quality requires time and deliberation.

Don't worry about breaking the rules

Several times I have seen projects halted to a grind because the developers where thinking a lot about rules and less about solving problems.

Procedural programming is a no go, we must use the object-oriented paradigm.

Adding tons of layers of unneeded complexity as a result.

What kind of design pattern does this problem fit into?

Weeks of work are wasted trying very hard to force everything into specific patterns.