I want to make an analogy between the software we write and cars.
To start, I want you to imagine a house, maybe somewhere kind of rural, that has a big, fenced-in plot of land. On that land are sitting some old cars. You can tell they are old not just because the style of cars changes over time, but also because of the fading paint, the spreading rust, and layers of dirt and dust.
A similar thing happens to code that is left to sit. The code we write is always in decay.
For a car, if we are not actively maintaining it, cleaning it, refurbishing it, replacing parts, and driving it around, then it is going to wither away. Similarly, if we fail to maintain and update our code and ensure it runs, then it is going to deteriorate in its repository or on that remote server.
It seems counter-intuitive to say. Surely, if you get code working, it should continue to work forever. Unlike an actual car, code is not exposed to the elements and its parts don't experience wear and tear. Right?
The reality is, the plane of technology that we build on is always in motion. It is moving forward. It is accumulating new mass and shedding the old, deprecating parts of itself. For that same reason, the technology that we build has to stay in motion as well. We have to actively maintain it for it to not also wither away.
That all sounds a bit abstract, so let's put it in concrete terms. Let's say I built a Rails app ten years ago with the latest tech. I have a widely supported version of Ruby and I'm using a popular NoSQL database. I use a third-party provider for the database and I deploy the Rails server to a reliable platform like Heroku. Let's say the app does everything it needs to. It will continue to do so for years to come. It is essentially feature complete. With nothing to change, there is nothing to maintain. Right?
The plane of technology is always in motion.
New versions of Ruby are released, and support and security patches are eventually phased out for the old versions. The same goes for Rails. Heroku isn't going to support everything forever; they need to keep up with modern releases and not let their maintenance surface area expand too broadly. The same goes for that NoSQL database. New versions come out, old ones fade into the background and so does support from third-party providers.
All of the software that underlies this app is evolving and improving, and we aren't taking advantage of any of that. And as time and releases pass by, the harder of a task it becomes to make those upgrades. Our Ruby version may opt us out of pulling in newer, now-standard dependencies and we may find ourselves needing to manually back-patch an existing broken dependency. And in the longer run, we see that the infrastructure that supports our app may eventually have to pull the rug right out from under us.
Code decays. We can't ignore that. The longer we let it sit, the harder it is to maintain. Software has a lifecycle and upgrades have to be part of that if we want it to survive.