Extracting methods for readability (or not)

I was recently involved in yet another discussion at work on the topic of extracting methods from larger methods just for readability. Just like I identified before it seems to be a trust issue; you don’t trust that a method does what it says it does. We have to respect that people have different preferences but I started to think if the both extremes are really equivalent making it only a preference issue. This is what I came up with.

The benefit of breaking a large method up just for readability is that those extracted methods may actually be reused in the future. Another benefit is that when you look at any given method it is short and simple. If I remember correctly the human brain can hold around seven things in memory. So in order to remember large amounts of data we group data. The typical example is remembering a sequence of numbers. If you try to remember the sequence 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 as individual numbers it will take ten “memory blocks” in your brain which is probably more than you can handle. So instead you’ll group the numbers and remember 123, 456, 789, 10 and the fact that the first numbers should be split up. That only takes up five memory blocks. Since it’s actually a sequence you will probably even optimize this into just one memory block; “a sequence from one to ten”. I think breaking up your larger methods into smaller methods achieves the same thing. This means that if you don’t know what a method that is being called does you can always look it up and from that moment it is only one memory block for that whole function. So even if you think breaking up large methods is worse for you, when you try to understand something that is broken up it should be fairly easy to follow the flow with today’s IDEs.The opposite however is not true I think. A large method have to be broken up into blocks by the reader every time regardless of if that is your preferred way or not. In this case you never get any help to break the method down into smaller pieces that are easier to understand.

This however does not mean that you should always break methods up I think. The litmus test is that if you extraction of methods means you end up with a lot of methods that have a lot of arguments. In my opinion such an extraction will not improve readability of your code. Does that mean you should keep the method? Well actually I think this is a sign of something larger being wrong so you need to rearrange things more because every method extracted should be an improvement.

Comments (2)

  1. David says:

    "The litmus test is that if you extraction of methods means you end up with a lot of methods that have a lot of arguments."

    If the method you're breaking up has lots of local variables which get in the way of extracting methods (because they become parameters in the extracted methods) it is often possible to turn them into fields so that they can be passed implicitly between the component methods rather than explicitly. Feathers' Working Effectively With Legacy Code describes one such refactoring as Break Out Method Object where the monster method becomes a method on a new class on which its local variables become fields.

    Sometimes it takes a few goes to get it right but it's often been a very informative thing to try. The new class frequently becomes an important bit of your system that you'd never considered as a separate entity before.

  2. Stefan Nystrom says:

    Lots of good stuff here and this spurred some thought for me since I've often been in similar situations. The argument that the extracted methods can be reused in the future is fairly weak by itself. The simple counter argument is that once I have the code duplicated, I can break it out at that point. There are however in my opinion a couple of reasons this is bad. First of all it's harder to find the duplicated code if it's deep within a method. In my experience so far, I have only seen one developer who was able to do this consistently and well. The second reason is a little more subtle: It leads to methods with varying levels of abstraction. A method that is not consistent in the level of abstraction is harder to read. I believe this is covered in "Clean Code":


    Slightly related to the topic of methods with a lot of arguments. I think it's really important to follow the method extraction with class extraction when appropriate. Just as methods tend to grow, classes tend to grow. Realizing that when some arguments are used together in several places, it is a signal that a class needs to be created has often made a design problem just fall into place for me.