10 best practices for highly-readable code
It is a fact that code is read far more often than it is written. This is why it is so important to make it readable.
Sooner or later, someone will read your code and try to understand its purpose. That someone could even be you! And you might be puzzled by what you wrote just a few months earlier, either because it’s no longer fresh in your mind, or because you didn’t make it easy to read.
I had the opportunity to attend a presentation by Jason McCreary (@gonedark) on best practices for writing code. While none of it was revolutionary, I found it was a good reminder of code-writing ground rules.
Jason made a list of 10 coding practices to keep in mind so that you, or a future programmer, can swiftly and intuitively follow your code. Look at it this way: if your code is immediately understandable, down the line, it could save the week-end of a post-production support colleague – or even your own.
Formatting
So many standards, so many possibilities. Who cares about tabs versus spaces, or Allman versus K&R. The main thing is to adopt a standard (for example, PSR12), then stick to it. Code sniffers and IDEs are great at detecting code standard violations and help to maintain a clean, consistent codebase. Be exacting, be consistent.
Dead code
If your code is dead, delete it!!! Go through all those commented blocks, unused variables and unreachable code. Treat your program like a tree: cut off the deadwood to support new growth and avoid risk.
Nested code
When following principle number one, if your code ends up so deeply nested that it starts beyond your screen width, you should review your method. Of course, nested conditions are part and parcel of any code, but, even if you write sub-functions, remember that future programmers may not have access to the diagram you had in front of you to code your conditions! Unravel nested code by using guard clauses, early returns or aspects of functional programming.
Using objects
This primarily concerns PHP programmers, but also applies to other languages. The idea is to use objects instead of tables. The most obvious example in PHP is using tables to pass a variable number of variables.
Big blocks
We all know that a 500-line block is just wrong. So don’t do it! Ever! If your block reaches a critical length, take the opportunity to refactor it into a more readable, less complex block.
Naming
“Foo” is a variable name for classroom exercises, not for real-life programming.
If your getWeekReport
function provides a monthly report, it’s misnamed.
If your getReport
function provides a weekly report, then you should rename it getWeekReport
.
If you can’t think of a name, just continue coding, and leave it until later. Never run after names: they’ll come to you in time.
Removing comments
This may be rocking the boat, but consider the following:
- DocBlocks are not comments; we want them and need them.
- Code that needs to be explained, needs to be improved.
$today = date(); // Set today date
: a classic example of unnecessary comments.- Comments are sometimes justified; for example, when they explain a business rule.
- Better no comment than a faulty comment!
- At the end of the day, comments don’t matter, since only code is executed. So only code really matters.
Challenge yourself to re-write your code so it needs no comments.
Reasonable returns
Code readers must be able to easily understand what the function returns. Some prefer one single return per function. Others group functions by type of return (for example, all the if … return true
functions at the beginning, then all the if return false
functions).
Don’t kick problems down the line; for example, return null
functions, which mean that the null
case will have to be dealt with later on.
Rule of three
This was a new concept for me, and I found it interesting. This is how it goes:
- If I ask you what comes after “2”, you’ll be hard-pressed to find the answer. It could be 3, 4, or even 1 or 2.1.
- If I ask you what comes after “2, 4”, you might hazard a guess.
- But if I ask you what comes after “2, 4, 16”, you’ll figure out it’s 256.
That’s the rule of three.
In programming terms, it means that your code should follow a set logic. Avoid code that goes “2, 4, 6, 27”. It might be right and do what it needs to do, but it’s counterintuitive for a human reader.
n the same vein, if your code goes “2, 4, call function DonextStep
”, it could be unreadable. It means that you may have to duplicate your code. This runs counter to the DRY principle... ¯\_(ツ)_/¯
Symmetry
To keep it simple, let’s just say that if you have two functions, create and update, then they should always follow the same parameters and return the same type of variable.
Function update (User user) : boolean success
Function create(User user) : boolean success
Rather than:
Function update (int userId, User user) : boolean success
Function create(Array[]) : User user
If you’d like to dig deeper, Jason McCreary has released BaseCode, a guide in which he elaborates on these principles and illustrates them with many practical examples (available for $29 on his site). You can also take a look at the screencasts on his YouTube channel.
Happy coding!