The Composed Method implementation pattern

2009-06-28

Infoq is one of my favorite sources for reading general-purpose stuff on software development. Some time ago they published an excellent presentation: 10 Ways to Improve Your Code by Neal Ford. I just loved it. The first practice it focused on is the composed method implementation pattern, one of the most fundamental development practices I can think of.

It was formally described a lot of years ago, as a pattern, in Kent Beck’s book Smalltalk Best Practice Patterns. I havent’t read this book yet (it is arriving in my next Amazon’s order). Sincerely I don’t know anything about Smalltalk but people usually say that this book is recommendable for anyone interested in good programming practices. I’m sure I will enjoy it. I expect it to be better than Implementation Patterns, also by Kent Beck. While not a bad book, I thought it was going to be much better. In this book, it is said that you should:

Compose methods out of calls to other methods, each of which is at roughly the same level of abstraction

I don’t know why but I tended to call this implementation pattern as factorized code. I think it has to do with the fact that the first time I realized about its importance was reading Martin Fowler’s Refactoring book. It was a lot of years ago but I remember that in some section (I guess it was in the extract method refactoring pattern) the book said that when you have in your code something like this:

void someMethod(){
  //do some stuff
  line 1
  line 2
  line 3

  //calculate some other stuff
  line 4
  line 5
  line 6

  //do final stuff
  line 7
  line 8
  line 9
}

You should refactor to something like this:

void someMethod(){
  doSomeStuff()
  calculateSomeOtherStuff()
  doFinalStuff()
}

void doSomeStuff(){
  line 1
  line 2
  line 3
}

void calculateSomeOtherStuff(){
  line 4
  line 5
  line 6 
}

void doFinalStuff(){
  line 7
  line 8
  line 9 
}

It said that, instead of having a sequence of comments and lines of code, you should extract lines of code to methods with proper names. This way you could also remove comments, as they were redundant. If I remember something of the Refactoring book, is how impressed I was about Fowler’s coding style (the catalog is full of Java code samples).

In my first year at the University, we were taught about procedural programming. I remember being told that when you designed a program, you had to divide high-level routines into calls to lower-level ones. By doing this recursively, you obtained a tree, where leafs represented primitive routines.

Watching the way many people code it seems that this fundamental principle has simply being lost. It seems like if with objects, you only have to take care of carefully design the public contract of objects and their relations. While this aspect is very important, you have to pay a lot of attention to the design of internal code.

Although this pattern may seem very simple, applying it correctly is not as simple as saying you should divide methods into small steps. I think there are three fundamental properties that should rule methods design:

  • Cohesion
  • Clear interfaces
  • Symmetry

Methods should be highly cohesive. This means that methods should focus in a single responsibility or functionality. This property comes from the software quality field, usually applied to modules or classes. Applying it when designing methods implies that you shouldn’t have methods that do many things from the point of view of the client that is using it. Who is the client depends on the abstraction level where the code is being invoked. Could be another class o just a private method inside in the same one. A method that receives five parameters is usually a bad smell.

Methods should have clear interfaces. In Writing Solid Code Steve Maguire says that the signature of all methods (functions in those days) should be clear enough in order to understand what the method is supposed to do, without any other kind of documentation. Signature means the name of the method as well as of the parameters it receives and returns (and their types). Achieving this involves many things but without cohesion is just impossible.

The book shows a good example of how a method should not being designed: the C realloc() function. It just does many things with a very obscure interface, which you won’t understand without the documentation. The book also contains a very representative example from the physical word, the candy machine interface problem: when the candy machine offers numbers for both selecting products and displaying their prices. Methods should not offer a candy machine interface.

The composition of methods should also be symmetric. The steps a method is divided in should be at the same level of abstraction. Abstraction is a construction that a person does in order to understand something. Jumping from one level of abstraction to another requires mental effort. If you have to keep jumping between different levels of abstraction in order to understand some code, it will be far more difficult to understand.

In conclusion, while this pattern will improve the quality of your software, I use it because for me it is easier to program this way. It is just the principle of divide and conquer working. I usually code methods following a top-down approach. Writing the top level methods calling lower-level methods before they exist. This way I can directly project the structure of steps that I, like a human, have in my head. Other people prefer to write the code without decomposing it first, and then refactorize to extract methods (I think this approach is far less effective).

Anyway I think that if you apply this practice exhaustively, along with using proper names for naming identifiers, your code will be like a 400% better.

No comments yet.

Write a comment: