- Use verbose method names.
- Put the final result at the top of a piece of code instead of the bottom.
- Write like Example 3, not Example 1
Ever since reading a code snippet from an old colleague, I've strongly preferred a liberal amount of method calls to methods with verbose names. When others read my code, I want them to be able to quickly read a few method calls and understand what my the code should be doing from a very superficial level.
Take the following example bit of code that gets the difference in code coverage precentages from the last run of the test suite and the current one in Ruby:
puts "Coverage difference: #{ SimpleCov::LastRun.read['result']['covered_percent'] - result.covered_percent }"
This line of code prints the difference between SimpleCov's last result's coverage percent with the current result's.
I'm not a fan of this coding style. While it does save space, a developer would probably need to read the entire line to understand what is being calculated and which values are used in that calculation.
Sure, you could write a simple comment explaining what it does, but as Martin Fowler says in his book, "Refactoring: Improving the Design of Existing Code", I feel that comments are deodorant for code smells. Writing comments (other than for automatic documentation generation, e.g. RDoc) allows you to cover up a problem with that code that could and should be addressed with some refactor.
Pros:
- Small amount of code
- Cheap on memory
Cons:
- Not particularly descriptive and therefore...
- ... might require someone to read the entire thing
Consider this next example:
current_coverage_percent = result.covered_percent
last_run = SimpleCov::LastRun
previous_coverage_percent = last_run.read['result']['covered_percent']
coverage_difference = previous_coverage_percent - current_coverage_percent
puts "Coverage difference: #{coverage_difference}"
Example 2 has, relatively speaking, much more code than Example 1 and therefore could require more reading.
However, I feel that Example 2 is an improvement in some regards. Because the variable declarations are grouped together, a reader could skip over them to the puts
line to see what is printed. Then, if further investigation is necessary, the reader can trace back to variables' declarations.
What I don't like about this code is that there is very little discerning important code from less-important code. The lack of indentation and the similarity in the structure of the text from line to line makes "at a glance" code reading more difficult.
Furthermore, this code doesn't lend itself to testing units in isolation.
Pros:
- Relatively descriptive
- Visually separates coding activities (declarations from method calls)
Cons:
- More code
- Could take longer to read/digest than Example 1
- Not unit-test friendly
I think this next example has several improvements:
print_coverage_difference
def print_coverage_difference
puts "Coverage difference: #{coverage_difference}"
end
def coverage_difference
previous_coverage_percent - current_coverage_percent
end
def previous_coverage_percent
SimpleCov::LastRun.read['result']['covered_percent']
end
def current_coverage_percent
result.covered_percent
end
I love this coding styling. It starts with the end result right at the top, almost like a TLDR.
In Example 2, the code reads bottom-down:
- Set up variables/information we need
- Then print the desired information to the screen
Example 3 reads bottom-down in the opposite direction:
- The desired outcome
- Detail into how the desired outcome is determined
- Another level deeper into detail..
- ... and so on
If method names are clear enough and following convention (noun method names return data, verb method names perform tasks), readers can extrapolate implementation detail from a single method call.
Furthermore, this code allows smaller unit tests and more granular memoization.
Pros:
- Easy to infer code responsibilities at a glance
- Isolated code units
- Easily memoized
- Code concerns can be visually distinguished easily
Cons:
- More code
- Slightly more memory
- Could take some getting used to
Single easily-readable lines like Example 1 can quickly add up to paragraphs... then pages... then entire modules of code that take a great deal of attention and detail to decipher. Applying these same principles to large code bases can greatly improve transparency and readability in the long run.
I believe writing code with a proverbial TLDR at the top empowers readers to dive as deeply into implementation details as necessary given the specific scenario. It might seem wasteful to turn 1 line of code into 20, but I think if done right, it can far outweigh the benefits of code brevity.