We should strive to write perfect code.
At first glance, this seems like a perfectly valid statement, something you would proudly tell others about. I used to be like this, but I came to regret it.
I've always been a conscientious person, and over the years this spiraled into perfectionism. This trait, which sounds much more positive than it is, has tormented me ever since.
As a software engineer, I prided myself on the "perfect" solutions I could come up with. The result? Constantly putting the bar too high, and an unhealthy amount of continuous stress and anxiety. Not something I'd recommend. Something had to change.
Part of me "rehabilitating" from perfectionism was reading about it. One book in particular, Wabi Sabi: Leading a Perfectly Imperfect Life, made a big impression on me. Wabi Sabi is a way of thinking, ingrained in the Japanese culture that broadly means seeing the beauty in imperfection, and recognizing that imperfection is the natural order of things.
This got me thinking about my career and the code I wrote. I realized I got it all wrong. I should strive for perfectly imperfect code instead. Let me explain why.
Perfect Code is an Illusion
Let’s first dispel the illusion: code cannot be perfect.
Outside of some basic metrics, we lack measures to objectively determine the quality of code. Code is subjective. To me, code quality boils down to a gut feeling - one that is honed over many years of experience.
Sure, we have some vague agreement on what quality code entails. It shouldn't be too many lines, it should be easy to read, etc. But interpreting these metrics is still a matter of the person reading it.
The point is code I might find perfect great might be horrific to you and vice versa. Beauty is in the eye of the beholder, and thus perfection eludes us. Attempting to attain it is a futile exercise.
The Fleeting Nature of Perfect Code
Let's say we hypothetically ended up with perfect code. We'd be confronted with the realization that this perfection would be ephemeral. Everything in our industry is in constant flux. New technologies, patterns, architectures, and perspectives emerge all the time, potentially rendering a solution in dire need of improvement. Software is not static, it's organic.
But there is more. As we work on solutions in software our understanding of the problem domain improves, as would our grasp on the codebase. Our perspective on the solution shifts continuously.
Lastly, there is the aspect of our skill. As we improve over time, our sentiment towards solutions changes. If you revisited the code you wrote years ago, would you still consider it good? Most likely you would do things differently now. You changed, even though the code did not. And now the code is no longer considered perfect.
The Greek philosopher Heraclitus expressed this long ago:
No man ever steps in the same river twice, for it's not the same river and he's not the same man.
The Economics of (Im)perfection
In the end, our software needs to deliver value. Ideally, we do this cheaply, effectively, and at a sustainable pace. The ability to constantly deliver value enables the business.
Once again perfection is the enemy. Getting things to "perfect" takes disproportionately more effort than getting them to "good enough." This principle is commonly known as the Pareto Principle which states that 20% of the causes lead to 80% of the results.
Loosely translated this means that 20% of the effort can net us 80% of the outcome. Perfection lies in the stretch from 80% to 100%, which would take up all the remaining effort. Under economic constraints, it makes much more sense to put in 20% and get more than adequate results, as opposed to aiming for that 100%. The challenge is in developing a sense of where you are on this spectrum and balancing appropriately.
Perfection is the Enemy of Progress
Aiming for the perfect result can evoke doubts, overthinking, procrastination, or even inaction. Perfection inhibits progress.
Perfect is the enemy of good - Voltaire
A profound realization in software development is that it is an exercise in learning and exploration of a complex socio-technical system. The complex nature of it all means analysis cannot reveal all the answers. Sometimes we simply need to take a step, reassess from a new vantage point and determine the next step from there.
This all demands experimentation. As engineers were constantly creating, executing, and analyzing bite-sized experiments. Perfection is not conducive to this approach. It prevents it.
For example, I've seen projects where consistency (perfection in a sense) was highly valued. It discouraged us from trying out different solutions in parts of the codebase as that would introduce inconsistency. The motto implicitly was "all or nothing." Many times this resulted in nothing, leaving the code seemingly perfect, even though it was only superficial veneer.
Beauty in Imperfection
Wabi Sabi teaches us to see beauty in imperfection: a brittle autumn leaf or a crack in an ancient vase. These things are not perfect but can have an austere beauty. The same holds for code: if we allow ourselves to look beyond the cracks in the surface, beauty can be found.
Think about all the effort that went into a piece of old or inherited code. Consider the decisions its authors made, and how they might have struggled, having only what information they had at the time. Imagine how that piece of code has been helping the business achieve its goals during its lifetime, and how many metamorphoses it has gone through over the years. You might develop a bit of reverence for that code you were so eager to dismiss at first glance.
Beauty runs deeper than what's easy to observe. Imperfection is strife. Imperfection tells a story. Imperfection is the natural state of the world.
The Long and Winding Road to Imperfection
As software engineers, we are constantly fighting under and over-engineering. It's up to us to find the correct balance in the context we find ourselves in. Useful software will always be a matter of tradeoffs and making progress necessitates imperfection. As much as perfect code sounds like something to strive for, in reality, it is the siren's call luring you into the depths of despair.
The code we write is by definition imperfect. Realizing this took me a long time to accept, but I did. From now on my code will be perfectly imperfect. Hopefully, yours will too.