Skip to content

Instantly share code, notes, and snippets.

@omgreenfield
Last active June 28, 2018 05:11
Show Gist options
  • Save omgreenfield/5fc8e4ca8156bd784e57eba45efaf146 to your computer and use it in GitHub Desktop.
Save omgreenfield/5fc8e4ca8156bd784e57eba45efaf146 to your computer and use it in GitHub Desktop.
Method driven execution

TLDR

  • 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

Meat and taters

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:

Example 1

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.

To summarize:

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:

Example 2

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.

To summarize:

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:

Example 3

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:

  1. Set up variables/information we need
  2. Then print the desired information to the screen

Example 3 reads bottom-down in the opposite direction:

  1. The desired outcome
  2. Detail into how the desired outcome is determined
  3. Another level deeper into detail..
  4. ... 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.

To summarize:

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

Conclusion

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment