What is Clean Code

Every software engineer mentions how clean your code should be. There are even principles and design patterns for this: DRY, SOLID, object oriented programming, functional programming. Everyone will tell you, a junior developer, that your code is not clean. They will implore you to write clean code, so it is readable and more easily extensible. With clean code, it becomes easier for even you to work with the codebase in the future.

Most career software engineers should know when they right dirty code, often referred to as spaghetti code where I come from. People will tell you the importance of clean code, for the umpteenth time, as though you were not aware of your guilt. Every time I look at the code of a senior software engineer, I am reminded of my crimes. When I dig into other engineers’ code, ready to extend it with new features, the ease reminds me of how differently I write my own code. How dirty mine is. And no matter how many times I refactor, I can not make it as clean as I would like. Like a sinner hoping bathes will bring me salvation.

I envy beautiful code. Someone I work with writes beautiful, easily extensible code, and I dreaded every moment I had to make changes. I tried to make as little changes as possible, the same way you would while trying to step in the exact same places another as stepped, to avoid making a mess. I knew my functions were too long. The solution I was told was to make my functions to only one thing. But in a sense, every function does only one thing if you take a wide enough perspective. And if you take a narrow enough perspective, every function does multiple thing (a variable assignment alone being one thing by itself). And in some cases, ugly code is unavoidable. I knew my names were horrible. fetchData, repeated in more files than I remember. What data was being fetched? If I did not know, how was anyone else to know? And my indentation, horrific, like an amateur killer hastily leaving the murder scene. Everyone believes you know what clean code should be like, but just refuse to do it. Or you do not know that code should be clean, and can do it once you become aware. But it is similar to how we know good art, even though we cannot create it. And just like art, we can learn to write cleaner code. First, we need to find people to tell us what clean code is and how to create it.

I’ve been reading Robert C. Martin’s A Handbook of Agile Software Craftsmanship. It is the first real understanding I am finding over what clean code is like. True, my code was cleaner before I started the book than a year before. But it was like wading through mud to reach a spring when there was a bridge over the mud; significantly more difficult. I fought tooth and nail (mentally) for every piece of knowledge I gleamed of clean code. I attempted to copy and copy, anxious to write code without a template, until my code could be similar. I killed whatever hint of a personal style was in me. And I tried to follow rules, sometimes unsuccessfully, even in situations I might have been better off discarding the rule. One day, I decided to let go of my torment. And what better way to free yourself than through enlightenment? So I began reading.

A Handbook of Agile Software Craftsmanship’s beginning carries a scribble - “The only valid measure of code quality: WTFs/minute.” There is a corresponding image of doors with the word “code review” on it. The good code has two exclamations of “WTF”, while bad code has five exclamations, with different variations of it. This is an apt explanation. To begin understanding what clean code is, it is probably important to first understand that even the most elegant code will have its nasty parts. Because reading code is hard, no matter how nicely it is written. Much like responsibility is difficult, no matter the ideals we wrap them in. Our job is to do the best we can to make that experience less difficult, as much as we can.

I have read many definitions of clean code and three qualities stand out for me: readable, easily extensible, and performant. Clean code should be easy to read, with one commentator saying it should read like good prose. If another software engineer glances at the code, they should have an idea of what is going on. The same way you glance at the middle of a book, and have an idea of the protagonist’s danger. It should be easily extensible. Any contributors should find it easy to add features atop it and reuse the parts without feeling like they are wading through a mess. And efficiency, which is often underrated. If a software engineer attempts to improve upon clean code, they should find themselves where they started, with greater appreciation for the initial engineer. This way, there is no temptation to make a mess of the code for greater efficiency.

I am not trying to teach you to write clean code. Instead, I am merely imploring that you join me in my attempt to find the path to clean code myself. Maybe then, we can both write slightly better code. I am attempting to focus on basics that will yield exponential value. The easiest things that will solve 90% of my problems. The ones I’ve noticed are:

  1. Naming things;
  2. Currying and composition;
  3. Comments;
  4. Formatting code;
  5. Successive refinement; and
  6. Following conventions.

These six items are relatively easy to think about and conceptualize. Definitely easier than the many patterns competing for my attention. And while I intend to learn as many patterns as I can, I realize that doing that will take time. So a fair alternative, for now, is to learn the principles behind many of those patterns. Learning those principles will help me avoid 90% of my problems with clean code.

1. Naming Things.

Naming is underestimated. A name carrying power has become so hackneyed that people often forget this. Names are descriptions of an item or person. In fact, they are so important that many cultures have surnames to better distinguish people. Because from the early days, people realized that naming things is important. And that names should, for the most part, be easy to pronounce, sufficiently distinguish, and should not be too long while also not being too short. In my culture, we took it a step further. Parents called their children names that spelt out the kinds of future they wanted for those children. This is what your names should do. It should clearly convey your intention for variables and functions to other software engineers. Take my fetchData function as an example. It was supposed to make an API call to the server in all the places it appeared. However, the data it got was different in each location. There are two clear problems in this: (1) it is ambiguous and (2) is not sufficiently distinguishing. Developers should know the data to expect, so they can have a better idea of what to do with that data. fetchUserAccounts would be a better name if the function fetched user accounts. I also prefer verbs for functions, because they give an idea of an action taking place. On the other hand, I prefer nouns for variables. You can think about multiple names until you settle on one that works, much like you would with a pet, or a child you care deeply for.

2. Currying and Composition.

I have struggled to understand what people mean when they say a function should only do one thing. Ironically, the advise that my function should not exceed 20 lines has been of greater help, even though it is seemingly more ambiguous. When professional software developers say a function should do only one thing, they have a shared understanding of what “one thing” is. So while you struggle to understand whether fetching data you need to send a mail, sending the mail, and saving the data in the database in a database is one thing, since it all has to do with sending a mail, they know that each of those things are different. And how to decide when a function is doing only one thing is something you will struggle with, if you are like me, until you know what professional developers mean by “one thing”. Currying and composition has been a better way for me to interpret this. I believe this explains currying and composition very well, as it was the first time I truly got the concepts: Benign Notes on Composability. However, for the impatient, both concepts revolve around breaking down functions into smaller units, and then calling them within each other. So instead of thinking of whether my function is only doing one thing, I think instead about whether there is any part of my function that I can reasonably pass into another function. And if you name well, and the pieces have sufficiently different name, then you may unwittingly find out that your functions were indeed doing different things when you can give them different names.

3. Comments.

Comments are confusing, because the temptation is to use them too often or not at all. I have not met many developers who use comments often. Then again, if your code is clear, comments should be used sparingly. A bad habit of mine was commenting out code, instead of outrightly deleting it. I will share something I saw on Stack Overflow that has stayed with me. To paraphrase, commenting out code is for those who are too cowardly to trust Git. And I agree. Because I know that code from the past will almost always be accessible in my git commit history. And so, there is really no need to keep pieces of code around that I will likely never use. Also, I have found that comments should be reserved for those particularly nasty parts of code you cannot reasonably do anything about, in which you need to warn others of potential consequences or explain your intent. There is no reason to have comments littering everywhere, especially as the developers it is intended for will likely ignore them if there are too many.

4. Formatting Code.

All I have to say on this is that it makes your code much more pleasant to glance over, improving overall experience and even improving how easy it is for you to spot bugs. Right click your mouse on the document in Visual Studio Code and format the document please.

5. Successive Refinement.

Often, I have found that I struggle so often with how much there is to do, what to do, and what there is to do that I cannot do, that I am left paralysed and doing nothing. And so I have found that successive refinement is the key to surpassing those moments. Just as Rome was not built in a day, your code will likely not be elegant in a moment. Do what you can, from the basics, and work your way through it. If you make the code a little cleaner every time you work with it, you will save the codebase from degradation and will perhaps eventually have elegant code.

6. Following Conventions.

Conventions are the amateur’s way of cosplaying a professional. And if you do it well enough, in some moments, there will be no difference. I understand that conventions will not always be right and there are some situations in which it is better to deviate from them. But nevertheless, you should follow conventions when you can. Conventions is how almost any other developer can go through your code in the future and determine your intention. It is a form of shared language. And before your individual habit triumphs it, there must be enough of a difference that it is worth the extra complexity.