From Five Lines of Code by Christian Clausen

This article delves into when a function should call a method on an object or pass it on as an argument.


Take 40% off Five Lines of Code by entering fccclausen into the discount code box at checkout at manning.com.


Our First Rule, Why Five Lines

To answer this question we introduce the most fundamental rule in this book: Five Lines. This is a simple rule stating that no method should have more than five lines. In this book Five Lines is the ultimate goal, because, adhering to this rule alone is a huge improvement.

Rule: Five Lines

Statement

A method should not contain more than five lines, excluding { and }.

 Rule: Either Call or Pass

Statement

A function should either call methods on an object or pass it on as an argument, not both.

Explanation

Once we start introducing more methods and passing things around as parameters we can get uneven responsibilities. One function might both be doing some low-level operations, such as setting an index in an array but then also passing the same array on as an argument to a more complicated function.

This is difficult to read because we need to switch between low-level operations and highlevel method names. It is much easier for us to stay at one level of abstraction.

Consider this function to find the average of an array. Notice that it uses both high-level abstraction sum(arr) and the low level arr.length.

Listing 1. A function to find the average of an array

  
 function average(arr: number[]) {
   return sum(arr) / arr.length;
 }
  

It violates our rule. Here is a better implementation where we have abstracted away how to find the length:

Listing 2. Before

  
 function average(arr: number[]) {
   return sum(arr) / arr.length;
 }
  

Listing 3. After

  
 function average(arr: number[]) {
   return sum(arr) / length(arr);
 }
  

Smell

The statement “The content of a function should be on the same level of abstraction” is so powerful that it is a smell in its own right. However, as with most other smells, it is hard to quantify what it means. Let alone how to execute on it.

It is trivial to spot whether something is passed as an argument, and as easy to spot if it has a . next to it.

Intent

When we introduce abstraction by extracting some details out of a method, this rule forces us to also extract other details. This way we make sure that the level of abstraction inside the method always stays the same.

References

To help achieve this rule you can attempt refactoring Extract Method.

You can also read more about the smell “The content of a function should be on the same level of abstraction” in Robert C. Martin’s book “Clean Code”.

That’s all for this article. If you want to see more, you can preview the book’s contents on our browser-based liveBook reader here.