I am a keen follower of Robert C. Martin’s Clean Code practice. I have poured over, re-read and argued each point within it with myself, and lost all the arguments to Uncle Bob’s point of view. However, I have a harder time getting the point on function length across to other developers. On function length, simply following Uncle Bob’s guidelines I ended up automatically coding small functions. This happens automatically when you separate out functions at their level of abstraction, but what does that mean?
Level Of Abstraction
Functions do things, and these things can be classified into different levels of abstraction. This classification is divided into three high-level abstractions –
- Flow (if statements and conditional logic)
- Iteration (for and while loops and recursive repetition)
- Assignment (operations that result in assignments)
A function should strive to either be orchestrating the logic (flow and iteration) or doing the logic (iteration and assignment) but rarely and only in the simplest of cases all three. If your function is doing all three, it is doing ‘more than one thing’ and is exhibiting ‘more than one reason to change’ which breaks SOLID design principles. Furthermore, the separation of code into these functions that accurately and unambiguously describe what the function is doing is the ultimate in code documentation, it is documentation with teeth because developers and maintainers will strive to ensure that the function name adequately describes what it is doing, whereas code comments are not likely to be maintained over time.
Separation Between Intention (Flow) and Implementation (Doing it)
After reading Martin Fowler’s recent article in Function Length I have yet another way of explaining the same mental distiction. And I quote directly from his article:
The argument that makes most sense to me, however, is theseparation between intention and implementation. If you have to spend effort into looking at a fragment of code to figure out what it’s doing, then you should extract it into a function and name the function after that “what”. That way when you read it again, the purpose of the function leaps right out at you, and most of the time you won’t need to care about how the function fulfills its purpose – which is the body of the function.
I read as far as that comment and sprung into action writing this article because I realized I had created a new mental distinction and discovered another one of my Code Heroes (Martin Fowler) doing the exact same thing as another of Code Heroes (Robert C. Martin). Only then did I read further, and discovered that more of my Code Heroes (Kent Beck) do the exact same thing; and that Martin Fowler’s personal experiences exactly mirror my own, and I continue to quote from his article:
Once I accepted this principle, I developed a habit of writing very small functions – typically only a few lines long . Any function more than half-a-dozen lines of code starts to smell to me, and it’s not unusual for me to have functions that are a single line of code . The fact that size isn’t important was brought home to me by an example that Kent Beck showed me from the original Smalltalk system. Smalltalk in those days ran on black-and-white systems. If you wanted to highlight some text or graphics, you would reverse the video. Smalltalk’s graphics class had a method for this called ‘highlight’, whose implementation was just a call to the method ‘reverse’ . The name of the method was longer than its implementation – but that didn’t matter because there was a big distance between the intention of the code and its implementation.
Robert C. Martin for so many mental distinctions and Martin Fowler for cementing my resolve to continue on the right path.