In Clean Code, Robert Martin gives us the following helpful piece of information.
.. [T]he ratio of time spent reading versus writing is well over 10 to 1. We are constantly reading old code as part of the effort to write new code. …[Therefore,] making it easy to read makes it easier to write.
With this in mind, we would like to give you 5 tips on how you can improve your code so it’s more readable.
Let’s say your working on fixing a bug in our project management tool and you run across the following.
Based just on the code above, you can’t know what’s going on in the
rebuild() function. Is it doing something that might be causing the bug? What do
true do? Why is it located where it’s at. Your only solution is to navigate to that function and see what it’s doing but that costs you valuable time and takes you out of the flow of reading the calling function.
When we look at the function this is what we find.
Reading the DocBlock information at the top of the screen helps us a little but reading through the function itself is difficult. The function is doing a lot and its body doesn’t fit on the screen without scrolling on my laptop. We need to do some cleanup.
1. Use Intention-Revealing Names
Naming things is hard but it’s super important that we name everything (functions, classes, variables, etc.) with names that reveal intent and don’t cloud up the flow of reading. It’s worth us taking extra time to think up a name that’s clear and reveals what the function, class, or variable does from the calling function.
Let’s look back at our example function for a minute.
The DocBlock comment says specifically that the “function rebuilds the estimated time to completion base on the incomplete tasks” but to know that you have to either visit the function definition or focus on the function in your editor for a pop-up (if it supports this). Think of how much time would be lost doing this over and over again. To make it easier when we’re reading the calling function we’re just going to rename the function to almost exactly what the comment says.
Then we can replace it anywhere we call it.
Now it’s significantly easier to read but we still don’t know what
true are doing.
2. Keep Functions Short
Now that we’ve renamed our function so it’s easier to determine what it’s doing when we’re calling it, let’s look at how we can make it easier to read on the inside.
The number one thing that you can do to make your functions easier to read is to keep them short. Keeping your function short makes it easier to digest when your reading and helps reduce bugs because there are just fewer moving parts that could go wrong inside the function.
The next version of our
rebuildEstimatedDateBasedOnIncompleteTasks() function has the exact same functionality but we extracted it into smaller functions.
This version contains more functions and more lines but it makes the original function easier to read and debug. It also has the nice side effect that it created all these little helper functions that most likely we’ll be reusing as we develop our application.
3. No Magic Numbers
Magic numbers are any values with an unexplained meaning in your code. This is an extension on #1 in that the values don’t explain their intent and cause confusion.
Let’s look at one of our example functions.
5 exist in this sample with no explanation as to why they’re there and it can be confusing when we (or someone else) comes back to this section of code. What we’re going to do is replace them with a constant that explains what they are.
Isn’t that a lot easier to read? The lines are a little longer but we can more easily process the intent of what those lines are doing.
Getting back to our original function call. We see there’s a magic number there as well.
We can easily replace it as well.
4. No Flag Arguments
A flag argument is an argument that tells the function to carry out a different operation depending on its value. Again, this comes back to intent. What is the intent of
true in our function call here? This is another case where we have look into the function to determine that.
There are two options to make this more readable.
The first is that we could have the calling function first call
rebuildEstimatedDateBasedOnIncompleteTasks() and then our
sendNotificationsAboutNewEstimatedCompletionDate() function. This works but the downside to it is that we’re making it hard to read from the calling function and potentially scattering the same two function calls over and over again in our code and if we need to add another step to this process we might have to manually do it. Doing things manually is hard and potentially error-prone.
The second is to create a new function that does both steps. This adds a function to our
Project class but makes the calling function easier to read and maintain.
We just have to make a small change to our
rebuildEstimatedDateBasedOnIncompleteTasks() function so it returns a boolean indicating if the value was updated and move the
if statement into it’s own function.
5. Stop Using So Many Comments
Most comments are junk and you should stop using them. The “rule” that you should comment your code has wasted people’s time. They tend to be unhelpful or worse out of date so they actually make it harder to understand the code.
Stop Using DocBlock
DocBlock was great. It explains what the function is supposed to do, what it’s parameters are, and what it’s supposed to return. However, now that we have return types and parameter types for functions it’s largely duplicate information we have to maintain that quickly becomes out of date if it was even entered correctly.
Let’s look at the DocBlock on our
When we redid the function we forgot to remove the following line:
That can be removed easily.
We also have these two lines:
The bool is covered by the return parameter and the weeks to check can be incorporated into the variable name.
That leaves us with a single line.
This is essentially the name of the function so we can easily delete it as well.
We just make it easier to maintain this function without sacrificing any information.
Use Functions Instead of Comments
Let’s go back to our original function and pick out this piece.
The comment expresses what the next section does but then we still have read over the next section as we work our way through the code. To make the code more readable we can take the comment and make it the function name of the code we extracted into its body.
This makes it much easier to read.
When Is It Okay To Use a Comment?
So it must be okay to use comments some of the time right? There are going to be cases were the only way to explain why something is happening is to do it in a comment.
We recommend that you only add comments if there is no other way to express that intent in code and you can be sure the comment will stay up to date.
Hopefully, this has helped you in your day to day work. If you feel like you want more you could pick up a copy of Clean Code by Robert Martin where he goes into more examples of how to write your code for reading. It has a lot of information in it and it’s well worth the read.
Header image by @punttim
Scott is the Director of Technology at WeCare Connect where he strives to provide solutions for his customers needs. He's the father of two and can be found most weekends working on projects around the house with his loving partner.