Hello, and welcome back to the blog.
Today I want to answer a question I recently received from Esther Felicies on Twitter. The question is, what do I consider to be clean code? I thought this would be an excellent opportunity to discuss the topic and provide some examples.
Quite often software engineers make the mistake of underestimating the total time spent reading code. Writing clean code is having empathy for your future self and others as it ultimately makes it easier and quicker for anyone looking at your code to understand and work with it. We spend far more time reading code than I do writing it, so why not make reading code a better experience?
What I aim for when writing code is a high signal to noise ratio and code that is as self-documenting as it can be. The signal we want others to see should be clear without being distracted by noise. The goal is to write code that is concise, expressive, and adheres to a single responsibility at a time.
So then, what exactly is this noise I’m referring to? It comes in different waves, here are a few examples:
- High cyclomatic complexity
- Zombie code
- Irrelevant comments
- Poor naming (classes, methods, variables)
- Large, incohesive classes
- Mixing of responsibilities
Projects become messy quickly and quietly. At first, it may seem like everything is fine because it’s working, but if we’re not active in writing clean code, the codebase will begin to rot over time. It will become increasingly more difficult to change. Modifications that should take you a day might take a few days, then a few weeks. Eventually, you’ll be unable to estimate anything reliably because all certainty is lost.
Today we’re going to look at just one aspect of writing clean code: naming. Specifically, I’ll talk about, in order, how I name classes, methods, and variables. I’m covering naming first because it’s a great place to get started to make your codebase more understandable, even before tackling other aspects of making your code clean.
I posted a poll on Twitter, somewhat jokingly, asking which of these classes do you create and immediately realize you’ve totally given up on naming? I gave the options Common, Utility, and some manager. At the time of this writing, you can see the winner so far is a manager.
These class names are so generic that you could put practically anything you want there, and that’s what will happen. We should be intentional about the names of classes to express their responsibility. Otherwise, we’ll be asking ourselves, “Common to what?”, “Utility for what”, “Oh, a manager? I guess I’ll put anything here since it’s managing the thing”.
These are not the questions you want yourself nor others to be asking about your classes. Given the choice of creating a new class with a better name over adding code in one of these poorly named classes, you should bet these poorly named classes will get all the love because it’s easier to be lazy about it. When naming classes, be specific as to the methods and data. If it’s acting upon a particular type, like a User, then consider calling the class User. If it’s to access some data, consider naming the class a repository.
Do what makes sense to clearly connect the name of the class with its data and behavior. There’s no good reason to create massive generically named classes.
Let’s move on to naming methods. First and foremost, methods should clearly indicate what they do by their name alone. If I have to navigate to the method and read it to understand the intent, the name needs refactoring.
Sometimes you can tell that a method is doing too much just by reading the name. Have you ever seen a method with an “And”, “Or”, or an “If”? Oh yeah, you know there be dragons there.
As with naming classes, don’t name methods in such a way that would leave a reader to ask “what”. Here are some examples.
Process — Process what?
Done — What’s done?
Get — Get what?
Start — Start what?
Some frameworks will have functions like this, but understanding those functions and their purpose is an inevitable part of developing the application atop a framework. Let’s focus on the code we have control over. Here’s how we could improve the names above in the context of some inventory processing unit.
Think about the context we’re given just by having more descriptive names. Although I may know nothing about the application or where these methods live, I have the context that we’re dealing with some type of inventory processing from a queue that can be dispatched.
With variables, you want to follow the same basic guidelines we’ve already discussed. It should be obvious what’s intended to be store in the variable by its name, but there are some additional warnings I would give as well.
There’s no reason to abbreviate variable names today. Gone are the days where you need to look in the documentation for what a function does because it’s practically impossible to infer the intent based on the name. Let the variable name be verbose if it’s necessary to make it more readable in context.
There’s no reason to declare all variables at the outermost scope of a method. Instead, we should use Mayfly lifetime variables, meaning we declare/initialize them as close as possible to their usage and let them fall out of scope as soon as we no longer need them.
Another issue I see often is the naming of boolean variables. For example, it’s common to see variables with names like
status. We know boolean variables store true and false, but these variable names don’t read like true or false statements. Instead, we could name these variables
isActive. Think about the readability in the context of a condition:
if (isSignedIn) over
if (isBusy) over
There’s a lot more to writing clean code that naming, but taking the time to name your classes, methods, and variables well will go a long way to making your code more readable.
If you’d like to see more posts about clean code, let me know in the comments. If you’re interested in other topics, like clean architecture, I’d be happy to cover them as well.
Until next time, take care.