November 22, 2010

How to Refactor Many Arguments

Originally published 25 May 2007

The following conversation is based on a true story.  The roles are taken from Robert Martin’s Craftsman series.

Apprentice:  Hey, can I ask you something?
Journeyman:  Sure.
Apprentice:  I was looking at a big constructor on one of our domain objects and I saw some groupings and was wondering whether it would be good to create objects for those groupings.  Is there some kind of pattern for that?
Journeyman:  Well first, how many parameters are there?
Apprentice:  72.
Journeyman:  72!?  Wow.  Talk about a code smellPMD's ExcessiveParameterList rule will flip out on this one.  I guess the author mapped those parameters straight from the out-of-our-control XML schema, whose document instances get unmarshalled in order to create the object.  We don’t have to follow suit and create such a flat domain model that matches the schema.
Apprentice:  What do you mean?
Journeyman:  Well, what I really mean is that I'd much prefer distributing the logic among some richer objects.  That is, create more little objects with little methods that do a little of the work.  Not one big object that does it all.  There would be an impedance mismatch between XML and the domain model, but that’s typical because of the technology differences.  I suppose the only benefit of the big constructor approach is the simpler mapping... maybe, but the negatives are much too great.
Apprentice:  What are the negatives?
Journeyman:  Well, for one, trying to list all 72 parameters in the correct order would be a pain.  And trying to understand the object as a whole with all those fields would be difficult.  Here [grabbing his Refactoring book].  You were initially asking about the “Introduce Parameter Object” refactoring.  Read that refactoring.  It can probably give you better details.
Apprentice:  Martin Fowler.  Does he know what he’s talking about?
Journeyman:  Oh yeah.  He’s one of the Masters.  Let’s take a look at the class.  [Brings up the class in the IDE]

public ImportantDomainObject(
   ...
   int x, int y,
   ...
   double min, double max,
   ...)
Well, I can see a few data clumps already.  You see the x and y?
Apprentice:  Yeah.
Journeyman:  That’s probably a Point.  Also, that min and max, that looks like a Range.  What I would do is search for data clumps like these and create objects for them.  Then, see where they’re used in ImportantDomainObject and start moving behavior into the new objects.  Distribute the logic.  We can create a richer domain model this way.  You’ll probably find clumps of these clumps and can follow the same process.
Apprentice:  Okay.  This sounds great.  Thanks.  I’m on it.
Journeyman:  Thank you for recognizing this and taking the initiative to improve the code base.

No comments:

Post a Comment