Friday, September 25, 2009

Why make methods small and do one thing?

I've been reading the ObjectMentor blog, and it's got some fun stuff in it. The one I particularly liked is how do you know when a function does "just one thing" - the answer - extract methods until you can't extract any more.

Now, I know there is the feeling of - why should I waste all this time writing lots of tiny little functions? But after trying it for a bit, I'm convinced, for two main reasons (although I am sure there are more):

When you write small functions, each one is eminently readable.  You look at it, and in an instant you understand what it does and its intent.  You don't have to "decode" the method to understand the intent - it just tells you.  I think this is essential - when you understand a code's intent, you can also understand if it is doing what you want it to.

Discovering New Classes
When you extract functions, sometimes you run into this situation where you are passing umpteen (meaning more than two) parameters into the function.  To me, particularly when the list of parameters is long, this indicates the need to extract a class which encapsulates all this data you're passing around.

And I often find once I've extracted the class, it clarifies the design for me.  You have an idea of a design, but you should really let the design reveal itself to you, and this is one of the great ways I have found that happening.

Also, often once a class is extracted, I can see how it can be used elsewhere - I have a new unit of reusability.

Anyway, I recommend keeping an eye on the ObjectMentor blog, there's good stuff there.


Jani Hartikainen said...

If you really do have a large method it is helpful to extract smaller ones from it, but I think if the extracted ones start being just a few lines and only used by the ex-big method, it's worth considering whether there's really any value.

Many little methods can add complexity, if they're not *really* necessary.

Andrei Badea said...

Personally I didn't buy into this "do one thing" advice. This article shows how bad it can get. The problem with the myriad of small functions is that they hide code patterns. The equals() method in the article above is quite readable to me, because it does more or less what any equals() would do: return -1, 0, or 1 in corner cases, otherwise compare the values. In the refactored version there are so many methods that I find it quite hard to tell how they work together.

Unknown said...

Good to hear from you, Andrei! :)

I'm not sure if the article is a good example, and yes, you can't apply any rule like a dumb machine. But in general I have found the principle very helpful. If you read a method and its behavior is not clear by reading it, then it needs work. One approach is to refactor out methods that explain what they're doing. The less clear the behavior of a method is, the more likely one is to break it when you change it, or not use it correctly.