The Art of Readable Code
by Dustin Boswell & Trevor Foucher
This post will be describing some of the key points in the book “The Art of Readable Code: Simple and Practical Techniques for Writing Better Code”. The PDF can be found in the company’s public file folder under personal and career development. Or just ask and someone on the web team can send it your way!
Fundamental Theorem of Readability
The main point of “The Art of Readable Code” is to write code that has optimal readability. Code should be written to minimize the time it would take for someone to understand it.
To fully understand code (in a perfect world), one must be able to:
- Make bug fixes
- Add features
- See how it interacts with the project as a whole
Below I will outline some of the main qualities of “readable code” as defined by the authors. There are several other topics they discussed, but I encourage you to read the book if any of these items sounds interesting or meaningful to you.
Accurate Naming
A variable or function name should:
- Be the equivalent of a tiny comment
- Be specific and precise
- Be longer for large scopes
- Convey information
- Avoid general terms
- Attach important details like units
// Avoid single letter names
let n = 'use name instead'
// Avoid acronyms
let cra = 'no clue what this means'
// Avoid abbreviations
let cat = 'cat or category?'
// Avoid meaningless names
let foo = 'what is foo standing in for?'
Aesthetic Improvements
In order for your code to be scanned by a peer or easily editable, consider implementing the following:
- Consistent layout patterns
- Group related lines into code blocks
- Try to eliminate duplicate code — DRY method (Don’t Repeat Yourself)
- Aim for straight edges and column alignment
For a visual reference of how the above methods can be used to make more aesthetically pleasing code, please examine the two code blocks below. Same code, but the second is much easier to skim and understand what is happening.
def suggest_new_friends(user, email_password):
friends = user.friends()
friend_emails = set(f.email to f in friends)
contacts = import_contacts(user.email, email_password)
contact_emails = set(c.email for c in contacts)
non_friend_emails = contact_emails - friend_emails
suggested_friends = User.objects.select(email__in=non_friend_emails)
display['user'] = user
display['friends'] = friends
display['suggested_friends'] = suggested_friends
return render("suggested_friends.html", display)
def suggest_new_friends(user, email_password):
# Get the user's friends' email addresses
friends = user.friends()
friend_emails = set(f.email to f in friends)
# Import all email addresses for this user's email account
contacts = import_contacts(user.email, email_password)
contact_emails = set(c.email for c in contacts)
# Find matching users that they aren't already friends with
non_friend_emails = contact_emails - friend_emails
suggested_friends = User.objects.select(email__in=non_friend_emails)
# Dispaly these lists on the page
display['user'] = user
display['friends'] = friends
display['suggested_friends'] = suggested_friends
return render("suggested_friends.html", display)
Meaningful Comments
Comments can vastly improve the readability of your code when employed correctly. Here are a few Do’s and Don’ts of commenting laid out by the authors.
DON’T Comment:
- Facts that can be easily derived from the code itself
- Just for the sake of commenting
- To compensate for bad naming
DO Comment:
- Relevant and explanatory thoughts (For yourself as you go along, as well as for future devs)
- Flaws and needed improvements (Ran out of time? That’s ok, but leave a TODO of what needs to be done)
- What a constant variable does and why (Especially if it is being used throughout the code)
- Functional summaries
- “Big Picture” or how it interacts with the system if there is no formal documentation
Breaking Down Giant Expressions
If you find yourself digging through a huge function, consider how you can break this down into smaller and more manageable pieces.
- Limit if statements to no more than 2 values (when possible)
- Simplify logic
- Use “explaining variables” to grab values
Look through the code below and compare the changes made. Which is more readable to you?
let update_highlight = function (message_num) {
if ($("#vote_value" + message_num).html() === "Up") {
$("#thumbs_up" + message_num).addClass("highlighted");
$("#thumbs_down" + message_num).removeClass("highlighted");
} else if ($("#vote_value" + message_num).html() === "Down") {
$("#thumbs_up" + message_num).removeClass("highlighted");
$("#thumbs_down" + message_num).addClass("highlighted");
} else {
$("#thumbs_up" + message_num).removeClass("highighted");
$("#thumbs_down" + message_num).removeClass("highlighted");
}
};
let update_highlight = function (message_num) {
let thumbs_up = $("#thumbs_up" + message_num);
let thumbs_down = $("#thumbs_down" + message_num);
let vote_value = $("#vote_value" + message_num).html();
const highlight = "highlighted";
if (vote_value === "Up") {
thumbs_up.addClass(highlight);
thumbs_down.removeClass(highlight);
} else if (vote_value === "Down") {
thumbs_up.removeClass(highlight);
thumbs_down.addClass(highlight);
} else {
thumbs_up.removeClass(highlight);
thumbs_down.removeClass(highlight);
}
};
Create and Find General Purpose Code
Do you find yourself using the same or similar functions over and over again? Good news, the book covered this in-depth. I found this section particularly enlightening because I use a lot of the same JavaScript functions for accessibility, like trapping the focus in a modal. Something like this can be super useful throught the project, not just on one component.
- Extract generic code into separate functions
- Easier to improve function over time without affecting large swatches of code
- Compile relevant code into utilities
Misc Helpful Advice
- Code should be organized so that it is doing one task at a time
- Know your libraries so you’re not re-creating functionality that already exists
- Only implement essential features — this helps you avoid over-engineering a project
- Question and break down project requirements
- Componentize your project into manageable pieces
- Keep project as small and lightweight as possible for longevity
Conclusion
“The Art of Readable Code” has a lot of great tidbits and examples that you can employ in your code. I recommend reading the book if you want to start building good practices now. If you liked what you learned here and want to get even more advanced, consider reading “Clean Code” by Robert Cecil Martin.