These days, I spend a lot of time automating, debugging, and fixing the various components that make up Jimdo’s internal PaaS, which ultimately serves the 15+ million websites of our customers.
My team knows that reliable processes are essential. To that end, we continuously make our infrastructure code more robust, tune our monitoring and alerting setup, and run GameDay exercises on a regular basis.
We’re the team that has been building and running the PaaS – we own it – and this is unlikely to change soon. For that reason, we strive to keep the platform as simple as possible, while being aware that a certain amount of complexity is necessary for our systems to do anything useful.
Of course, we still do enjoy creating new things from time to time; we’re programmers, after all. For example, we love to build new automation tools and add service features to improve observability and scalability.
On the other hand – and this is the crucial point – we also care a lot about doing the opposite:
- Deleting superfluous code
- Removing features
- Deleting documentation
- Closing stale pull requests
- Throwing away Git branches
- Destroying cloud resources
- Decommissioning projects
In other words, we try hard to get rid of anything that isn’t needed.
I know that more often than not, reality looks somewhat different:
- Projects are on a tight schedule and cleaning up is not considered a priority.
- The “DevOps department” has lost sight of server costs and no one has an eye on unused cloud resources.
- Developers, in general, are more keen to work on new features, whereas deleting unfinished experiments isn’t half as much fun.
Sounds familiar, doesn’t it?
While the benefits of terminating unused cloud servers should be obvious to anyone who’s paying the bills, it might not be so clear otherwise. What exactly is so bad about developing more features, more tools, and therefore more code? Why bother deleting anything?
The fact of the matter is that code is a liability. You and your teammates are responsible for each and every line of code you produce.
As Jeff Atwood put it so eloquently in his popular blog post, The Best Code is No Code At All:
Every new line of code you willingly bring into the world is code that has to be debugged, code that has to be read and understood, code that has to be supported. Every time you write new code, you should do so reluctantly, under duress, because you completely exhausted all your other options.
On top of that, the Lean Enterprise book offers these valuable insights:
At first, we should propose solutions that don’t involve writing code […] Software development should always be a last resort, because of the cost and complexity of building and maintaining software.
Only spend time and effort on test automation for products or features once they have been validated. Test automation for experiments is wasteful.
Our most productive people are those that find ingenious ways to avoid writing any code at all.
Less code means less complexity, which means less bugs, which means less unexpected outcomes in production. Remember: simplicity is a prerequisite for reliability. The more complex a system, the more difficult it is to build a mental model of the system, and the harder it becomes to operate and debug it.
Code that has no purpose is a major source of distraction, confusion, and communication overhead (“Hey Mathias, what’s the point of this function parameter we don’t use anywhere?”). It’s poor practice to comment out unused code, or worse, to gate it with a feature flag. Today’s version control systems make it easy to revert any changes; there’s no reason not to remove dead code and other bloat, such as outdated documentation and pull requests that haven’t been updated in months. In the wise words of Kent Beck: complete it or delete it.
(Just to be clear: it’s totally possible to produce fewer lines of code by writing clever code. Don’t be clever either. It will make the code even harder to understand.)
Deleting many – sometimes hundreds or thousands – lines of code is indeed extremely satisfying. It’s a worthwhile investment of time, one that comes very close to the joy of building, at least for me.
A couple of weeks ago, we finished the migration from Dkron to Nomad for running all periodic batch jobs of our PaaS. It was a lengthy migration to say the least (operating Nomad in a highly-available fashion in AWS isn’t trivial). So I did one particular thing to keep me motivated: I created a pull request in which I prepared all changes to our infrastructure code required to decommission Dkron and its dependencies – weeks before actually pulling the plug on the stack and throwing away the 1000 lines of code for provisioning it.
Believe it or not, but this pull request – the prospect of reducing the overall complexity of our infrastructure – kept me excited about the project until the very end.
And yet there’s a much better solution we would have preferred: not doing all this work in the first place, but rather outsource the task of running periodic jobs to a hosted service provider with a paid support plan. Unfortunately, there’s no Nomad Enterprise (or something comparable that fits our needs) yet, so for now we’re left with the operational burden.
I hope this will change because the best code is no code at all.
Let’s acknowledge this fact by saying “no” to code more often than “yes”.