Raise your hand if you’ve ever looked at a your codebase and uttered one or more of the following:
- Hm, should get to that TODO at some point.
- I’ll love deleting that chunk code when we finally sunset the feature.
- We’ll just move this over now, and then when the time comes refactor and move it to the right place.
- I don’t even know what this is for.
I can’t remember when I didn’t dislike some part of a codebase I tried to understand or contribute to, from repositories built from hundreds of engineers over decades, to open source plugins and projects I’m trying to integrate, to my own toy projects I’m just trying to get up-and-running.
At times, I was annoyed by unnecessary structure; other times, bad practices and overwrought patterns; and once in a while, random snippets that appear out of nowhere and are follow some untraceable piece of application logic. It’s given me the attitude, upon trying to understand a new chunk of code, to expect that some parts suck but to live with its faults.
In other words, I approach code pessimistically. I suspect most of us do.
So how do I/we view code in a more optimistic light? My engineering instincts say that good code, like a good product, ought to be minimally viable. Unfortunately, minimal code (also like minimal products) never survive initial contact: new features are added, new libraries used, new pages A/B tested and turned on for production, and the old stuff just sits in the background, withering away in its own pool of bygone execution cycles.
Even when we take time to comb through the system looking for broken tests and dubious modules, there is always trepidation in fixing a piece and not knowing the full impact of the changes made; it’s certainly easier just to keep that one old string class, in case some critical path happened to link to it and would otherwise explode all over the user’s indignant face. Years later, we’ll wonder about whether this sucky string class will have spawned suckier child string classes and infested the system with their low-level suckiness.
Maybe a more productive way of looking at the problem is to think about code as an evolving entity, and evolution is an effective if messy process. It runs counter to engineering intuition, but maybe the waste and the extraneous blobs of code are necessary to support a product that is itself evolving, with changing requirements and clientele, whose raison d’être is itself not wholly well-defined. Maybe the messiness1 of reality demands reflection in code.
In that case, I guess I should be happy.
For the more scientifically inclined, entropy.↩