How often do you think, “This code is unreadable!” while trying to understand code that someone else wrote? A lot of things can contribute to unreadable code. Sometimes it’s simply a matter of what you’re used to. Other times, code can be made more readable just by rearranging its structure.
Ever been involved in a code formatting war, where each member of your team has strong opinions about how code ought to be formatted? It feels like such a waste of time (“But if everyone would just do it my way…”).
In these situations, it can be invaluable to use a tool that handles all the code formatting automatically — even enforcing it as part of your development process by using git hooks, pull-request checks, or whatever is appropriate.
I use prettier, which can integrate with your editor to run every time you save. I like that prettier has its own point of view and, therefore, very little configuration. Many code formatters have way too many options (and yet, never enough to get the code just the way you want it), which turns the formatting war into a formatter-configuration war.
A tool like prettier will take time to get used to, but eventually, you’ll appreciate not having to spend so much time thinking about formatting. And in the meantime, there are other things you can do to improve readability.
Onomatopoeia for Code
Onomatopoeia describes a word whose vocalization imitates the sound of the thing it describes. For example, the word “buzz” sounds similar to the actual sound of buzzing.
Certain code patterns make me think of this effect — not that code makes a sound, but that its structure can resemble its intent. This sort of code tends to be easier to scan and understand quickly.
Say you want to check if a number is within a specific range. Some languages have nice range support that lets you write something like
if n in 1..100. But in many languages, you are left with an ordinary comparison like
if (n >= 1 && n < 100). This just doesn’t flow as nicely and could instead be written in a more natural reading order:
if (1 <= x && x < 100). Some languages (like Python) will meet you in the middle, allowing this to be simplified further to
if 1 <= x < 100).
Similar to ranges, code related to the order of things is easier to read when its representation matches its intent. Consider a function that determines whether a date is after another one:
Which date are we expecting to be the later one? If you think about it for a moment, you might assume you could read it as “someDate isAfter anotherDate.” But this would mean that when the test is true, the later date is written before the earlier date. Anyway, at this point you’re no longer scanning the code, you’re parsing it in your head. And without looking at the documentation, you could still be wrong!
We could improve this by (again) writing the parts in a more natural reading order:
In this case, it’s obvious that (when the function returns
anotherDate comes after
Another option would be a fluent interface, which helps improve readability by describing a flow of data in the order that it occurs. Consider how passing results through typical function calls ends up reversing the order:
Of course, you could use intermediate variables to make this more legible. But a well-designed fluent interface would eliminate the need for that as well:
// Intermediate variables resultOfOne = stepOne(dataForOne) resultOfTwo = stepTwo(resultOfOne, moreDataForTwo) result = stepThree(resultOfTwo) // Fluent interface result = stepOne(dataForOne) .stepTwo(moreDataForTwo) .stepThree()
|>) makes fluent interfaces standard practice:
stepOne dataForOne |> stepTwo moreDataForTwo |> stepThree
The next time you find some code unreadable, think about whether some structural changes could improve its readability. And then consider whether some standard tooling could help take formatting off your mind.