The code, like a human child, starts with a clean slate and gets convoluted and opinionated one line, one change, and one requirement at a time. Some have even aptly compared code with living organisms.
Here I present a (somewhat) ordered list of things that I believe make the code “beautiful” in an ideal condition. You may differ, and that is fine too. After all, beauty is a thing of perception and lies in the eyes of the beholder (or the reader of the code in our case).
Some of these could be too good to be true. Writing good code is like optimizing a multi-dimensional problem. And there is always a tussle between “beautiful code tomorrow” and a “working code today”. Mostly, “working code today” wins due to business reasons.
If I try to become an idealist for some time, below would be my list. A practical list would be different, and I will cover that in a follow-up article soon. It is a good question to ask as to why would one even worry about an ideal list then. Well, idealism gives a true north of what we want to achieve. How much of that we achieve depends on multiple practical considerations around changing requirements, timelines, dependencies, people, etc.
So, here is the list.
The code should be readable. If you cannot read my code, well, the future is bleak. But like beauty, readability is also a thing of perception and the team’s comfort level. If the team understands and writes in Java and if I also write in Java, readability may be high. But if the team understands and writes in Java and if I write in Clojure which only I understand, the code is a mystery to others and deserves special negative marks for readability.
The code should be correct. Yes, correctness most important if I had to write and no one had to maintain the code, like ever again. So, readability still is most important for the sake of the future. And correctness comes a close second.
The code should be well tested. Unit, functional and integration tests should try to maintain correctness of the overall system and should break with all sorts of loud noises when they feel change is not correct. A good set of tests increases the confidence to make changes in the future and not break things.
The code should be well-documented: Not just documented, but well documented. And good documentation focusses on “why” a change is being done more than how and what is being done. “How” and “What” can be found by reading the code, but if the “Why” gets lost, the code becomes a liability that others will fear to change since they will fear to break the unknown by introducing even the smallest of changes. Honestly, I was torn between prioritizing well-tested over well-documented code but chose to go with well-tested for 3rd spot because a well-tested code has strongly consistent guarantees over a well-documented code, where documentation could be misinterpreted. Why not both?
The code should be extensible. How many lines of code do I have to change to accommodate future (but reasonable) change requests? Ideally, I want to keep that number to a minimum, but not at the cost of 1, 2, and 3 above.
The code should have good logging and metrics: Does the code have good logging and metrics? If I cannot look at the logs of a system and correlate with what is happening inside the codebase, it becomes difficult for me to maintain that code.
The code should follow certain best practices. But how do we find these mysterious “best practices”? Well, there are multiple ways.
We can look around for established best practices in the eco-system we are using to write code.
And/or we can borrow them from other authors, teams, or companies.
Finally, the team can together collate and develop them collectively as a group.
The idea is to reach to a common set of understandings and conventions to keep the code clean and readable as it evolves. For example, in an object-oriented paradigm, we have things like SOLID, GRASP, etc., and generally, there are a set of design patterns too. I know I know… some folks are strongly against design patterns and other such fancy buzzwords. But if you look a little deeper, you will often find they are not against these design patterns but are against something very fundamental, which brings us to point 8 below.
The code should not be over-engineered. The biggest plight of our industry is that we are spoilt with choices and new, fancy technologies, products, services, design patterns, and buzzwords. I have seen people go overboard with enthusiasm to use these for their new products, thinking they will also learn while developing. Well, I have news. The use of something in production which we have not battle-tested may cost money (and lives too) if things do not behave as expected. The idea is to limit entropy and always take into consideration risk vs. rewards. If the risk is too low (like if I am prototyping something), go all out. If not, think and research hard before launching that new shiny tech to production.
The code should be user-friendly. A user could be the client who uses the code. User-friendly property is a little open-ended term (maybe reliability is better), but the idea is there should be clear and concise contracts for public endpoints, which are well documented with regards to their behavior, input, output, handling of error conditions, and exceptions. It should strive to fail gracefully where it makes sense, and fail with loud noises where that makes sense.
The code should be performant. Why is the performance at the very end? Well, unless we are writing code for a very critical system and have benchmarks to prove that performance is becoming the bottleneck, we should not optimize prematurely.
I have not covered Maintainability explicitly since it can be a very broad and highly ambiguous term. This question has good answers about what makes a code maintainable.
Finally, here is a poem for you (sorry, I am not a poet, but a simple dev).
“Every code is unique.
Every code is beautiful.
Every code can try to reach for the stars.
Every code is correct.
Every code is simple.
But it’s all true for those who wrote and forgot.
In a few months from now,
The world will have changed,
And the reasons utterly lost,
And not even God will know what did the code do after all“
Do you have suggestions for modifying or adding more content to this post? Shoot me an email to email[AT]littleblah[COM].
If you liked this post, please share with others!
If you have any feedback, drop me a mail. My email address is listed here.