Wednesday, June 6, 2012

Extract Method or Extract Class?

There's been a recent mini-revolution to what I think about refactoring.

For a few years now my most common refactoring was Extract Method. Got a big method? Extract sub methods. Got a deeply nested method? Extract each level into a new method. Got any other problem? You should probably look for methods to extract.

I've change my mind; these days I'm all about Extract Class, or more accurately Replace Method With Class. Got a big method? Cut out it's body and paste it into a new method on a new class. Got a deeply nested method? Well... I guess Extract Method still works better for that one. Got any other problem though? Just pick the largest method (or #region for you C# folks) and extract it to a new class.

Why the sudden change of mind? Recent real world experience that is best explained with bulleted lists within a matrix:



Extract Method Extract Class
Mess Unless there's a lot of duplication that you can quickly remove, the class size stays about the same.  Immediately reduces the class size by moving code to a new class. The compiler will tell you what it depends on and what depends on it.
Power You get a new method:
  • you can call it with different parameters
You get a new class:
  • you can instantiate it with different parameters
  • you can subclass and override it
  • you can pass it around
  • you can move related behavior to the same class
  • you can shift the burden of resolving dependancies to an IOC container or factory
Concepts Small, local, procedural:
  • encapsulates a local series of statements
  • tends to aid in procedural thinking
  • few design patterns are simple methods
Large, project-wide, object oriented:
  • encapsulates a bounded-context-sized role or responsibility
  • tends to aid in object oriented thinking
  • many design patters are objects
  • moves responsibility to the new class thereby increasing cohesion of the original class

or, in prose form: Extract Class immediately reduces the amount of code you have to worry about, improves cohesiveness of the remaining class, and gives you familiar object oriented techniques to work with.

Of course it's good to see if related methods could be extracted into a new class after extracting a method and it's probably good to break up the monster method after hiding it in a new class. I just found it much easier to make progress when I relied on extracting large methods to new classes first.

3 comments:

  1. To be fair, you can also override new methods; and pass them around. ;)

    I actually don't mind overly long methods or classes, so I say: do whatever works for your needs-- there really is no right way, but there are working and non-working projects!

    Ebyan "Nolithius" Alvarez-Buylla
    http://www.nolithius.com

    ReplyDelete
    Replies
    1. True; there may not be a right or wrong way but it's always a good day when I find a "more right" way that makes it easier to go from non-working to working software. Although I'll probably change my mind a few years from now....

      Delete
  2. I don't know.
    In large project at work (GIS systems), large classes are results of using big and dictate frameworks, where you cannot move too much outside. Refactor methods seems to be right choice for my kind of project, because I already have too much classes.
    You can say: you have IDE (Eclipse in my case): right! But I have colleague worked in this project for many years (12 people in 4 years so far, now 3 still active). If I refactor too much, what I need is documentation and... documentation is always a problem for a programmer. I don't want to make a revolution in my code, just let him be more readable.

    Tip for the future: maybe I can jsut refactor and extrac in some classes little portion of code, not in "core" classes? And start from that? I will think about that, thanks!

    ReplyDelete