In this post, I will discuss the idea of "good code" and "good practice" widespread in the programming community. What do people mean when they say some code is good, what makes a piece of code good, and, finally - good code "for whom", best practice "for whom". Who exactly is the supposed receiver of the "goodness" quality we assign to this code?
The reason for this heretical, infuriating choice for the most impressive computational system known is simple: the value of a programming language does not lie with inherent elements of the language, but with an interaction between the elements of the language and the properties of the programmer.
Claims of superiority on scientific, rather than aesthetic, grounds must be based on the study of the nature of the programmer. Do people best think of programs as functions? As state machines? As queries and transactions? As a prioritized set of rules? Perhaps in a different way depending on the domain? One thing is certain: If you’re not interested in asking this question and others like it, you cannot define the state of the art for practical programming language design.
You hear it here and there - good code, bad code, bad practice, best practice.
You can google it up. It depends on the language, it depends on the framework, it depends on the year. "Python best practices", "Ruby on Rails best practices", "Js best practices 2022".
I hear "best practice", and I think "best for whom?". Let's dive into this question, but, prior to that, let's take a look at the arguments used to make the claim about the quality of the code in the first place.
Scrambling through my memories, I congealed all arguments programmers use to declare a piece of code "bad" into 3 major categories:
I'd like to draw your attention to the fact that this is not a list of reasons a programmer might criticize a piece of code, this is a list of arguments used while criticizing the code. A programmer might simply want to learn some cute language because they like it, or because it makes them more competitive on the market - and this might be the reason for deeming the old codebase "bad", but it won't be the argument used for proving it's bad.
You shouldn't take these arguments at face value either - if someone says "it's a common practice to use snake_case in Python" (a seeming majority argument), it might well be a shortcut for saying "consistent casing makes it easier to understand the code for the programmers", which is a thinly concealed "worried about the programmer" argument, it's best to follow the principle of charity.
What's interesting about the aforementioned categorization is the following: all arguments from the "Worried about the user" category are objective - it's possible to check which code is comparatively more efficient, and it's straightforward to check whether the code is wrong or compromises security.
It's also easy to fact check the arguments from the "Just so" category - these are bad arguments, and I'd argue you shouldn't use them, but the person using this argument is usually able to source their claims, whether that helps the structure of the argument or not.
I believe the ease of proof is one of the reasons the arguments from either of these categories are used overwhelmingly frequently, even when the real complaint might lie in the second category ("Worried about the programmer" category, where the concern lies in how hard it will be for a programmer to understand or update the code).
For example, if it's hard for you to read nested code (in CSS, for example), you are unlikely to say so directly - you will search for the arguments against nested code that sound more objective, that are easier to verify, and that don't paint you in bad light (it's embarrassing to be admitting to having a hard time understanding code).
You might say that highly nested CSS is inefficient (and you'd be right, in case with CSS, for example, deep nesting might make the CSS file heftier), and that would be the objective claim from the "Worried about the user" category. You might refer to the SASS style guide that advises no more than 3 levels of nesting, and that would be the objective claim from the "Just so" category.
If you are to use the argument from the "Worried about the programmer" category, and genuinely say "this code is hard to understand", however, - then you would only be able to provide the evidence of your own word - this code is hard to understand for you.
The "Worried about the user" arguments (Inefficient/wrong/unsafe code) are objective and frequently strong, but easily fixed.
The "Just so" arguments are, in the best-case scenario, a concealed appeal to consistency, which is in the realm of "hard to understand for a programmer" subcategory, or, in the worst-case scenario, a not particularly interesting or strong argument from authority.
The arguments from the "Worried about the programmer" category are underused, as they are harder to source due to very little research on the topic, and more vague, as we usually leave the "programmer" in question unidentified, - however, "ease of understanding" and "ease of manipulation" is what constitutes code quality in its classic sense, making it the most interesting category to explore.
Let's consider some reasons the code might be hard to understand:
Notice how these arguments, unlike the arguments from the other categories, rest in the interaction of the code with the brain of the programmer. It is clear each of these is subjective - people have vastly varying abilities when it comes to holding a number of variables in their mind - we all have a different working memory, and we all have a different long-term memory.
"Convention over configuration" design paradigm might be more embraced by someone who finds it easier to memorize the said convention. Shorter function names are embraced by people who get easily distracted by too much text. There is a real neurological difference between people for whom attention is a scarce resource, and people for whom long-term memory is a scarce resource. This makes every "this code is hard to understand" argument subject to the following question: hard to understand for whom?
So when we say some code is hard to understand, who do we have in mind as an attempted reader? Let's consider a few possibilities.
The code might be hard to understand:
It might seem obvious that understandability of the codebase is a business question, and the right answer is simply "whatever option is best for this company", which typically translates into "code must be easy to understand for the team working on this project". However, the team working on the codebase is not a constant - we might demand a greater baseline competence from our coworkers, and we might demand a greater intelligence from the new hires. Furthermore, when it comes to open source, we never know who might want to contribute - we have to make a decision on who would be able to understand our code prior to those people joining as contributors.
We saw a switch from solutions that focus on competence to solutions based on inclusivity in recent years. At the same time, we saw a switch from object-oriented programming to functional programming favoritism in recent years - many OOP practices are outright considered bad practices at the moment. This has been explained, partially, by the greater mental load that OOP demands from the programmer - the necessity to keep track of the mutable state of the program in your head.
I believe this switch to be at least partially explainable by the cultural update - we don't believe that programming is reserved for the best of us anymore, it has become a commonplace profession. To give you a sense of what it was like a few years ago, consider the blog post "Skill Disparities In Programming" by Jeff Atwood, the founder of StackOverflow, where he states there are huge disparities in programmer ability, and you should seek other professions if you are not in the top percentiles of coding ability. Compare this to the more recent "Learn to code" movement. Coding turned from the profession you have to fight for, to the profession that most people can do, and find themselves required to do. Correspondingly, our sense of "who should be able to understand this program" expanded, dragging our understanding of what is and isn't a good practice along with this expansion.
I believe the democratization of the coding culture to be a step in the right direction. The notion that most programmers find FP to be less mentally demanding than OOP has never been checked, however - we just converged (and I believe temporarily) on this idea as an industry. Dynamic, collective wisdom might work better than studies on the topic, however we shouldn't lose sight of individual differences that don't reside on a single axis of the mysterious "programming ability". The fact that different people might be better suited to different practices is completely absent from the zeitgeist, and I want us to be more cognizant of this phenomenon.
Next time you feel compelled to say something is a bad practice, consider specifying exactly why this code is harmful, and, if your claim is that this code is hard to understand, consider for whom this code is hard to understand.
Finally, avoid thinking of programmers as residing on a single axis of competency or a single axis of intelligence. Consider for whom exactly this piece of code might be hard to read - for people who have a limited working memory? For people who have a limited long-term memory? For people who rely on the geometric layout of the code to parse it visually? For people who lose track of the flow of the program if they have to read a long variable name?
It might be impossible to check the level of competency of the people who will have to read your code, and it might be even harder to predict their cognitive specs, however it's important to keep in mind as a defining factor for whether the code is understandable, and it's infinitely better than pretending that the current fashion is objectively the best fashion for each and every one of us, the swamp we repeatedly drown in, likely due to the illusion of coding being an exact science.
What might be more understandable code for some people, might be less understandable for others. What might be the best practice for you, might be the worst practice for someone else.
UPDATE: "Software Development and the False Promise of Science" by Richard Marmorstein (link) is an exceptional read on the same topic.