Class Methods Part III - Structural Duplication

This post in a series on class methods in Ruby focuses on removing structural duplication.

Whether it’s called OnceAndOnlyOnce or DRY good developers should agree that in the overwhelming majority cases duplication in software is a bad thing. Duplication comes in many forms. The simplest to identify (and remove) is actual text duplication. More difficult to find (and remove) is duplication of concerns. Ruby class methods can help with the middle ground between these to extremes. Take accessors. Writing Ruby like this is grounds for the revocation of one’s programming license…

So what’s the responsibility of the weapon method? How about the climbing_instrument method? Both methods basically have the same concern, exposing access to instance data. Arguments about the wisdom of breaking encapsulation in this way aside, the Ninja class is breaking the DRY principle. This concern, exposing instance data, is so common in fact that Ruby defines a class method on Module whose purpose is to dynamically define instance methods which expose instance data.

I call the sort of duplication eliminated by attr_reader structural duplication. When otherwise well factored code features heavy structural duplication, one sees methods where the words are different, but the whitespace is exactly the same. Class methods, particularly when combined with convention and metaprogramming, are a clean way to remove this sort of duplication.

Take for example an initialized value…

This sort of initialized value is prone to a classic bug. The ninja can never be disarmed…

Useful as this may be to snake_eyes, it’s clearly not the intent of the disarm method. The fix is straight forward…

The weapon method redefines itself to be a simple attr_reader the first time it is accessed, it then initializes and returns @weapon.

Now assume that Ninja needs climbing instrument initialized in the same way…

Once again we can see a clear violation of DRY in the ninja class. The logic for defining initialized attributes is duplicated across the weapon and climbing_instrument methods. This logic can usefully be factored to a class method…

There are a couple points worth discussing here. One is the implicit trade off made by this sort of class method. A certain degree of readability has undeniably been lost in the pursuit of removing duplication. Readability is one of the most important aspects of code quality, and changes that reduce readability should not be entered into lightly. My inclination is to err towards readability for a very small amount of local duplication, and quickly switch towards slightly less readable better factored code when duplication surpasses minimal levels.

The other item worth exploring is where the attr_initialized method should live. The interpreter must see the method definition before the class method can be used. An alternative to cluttering up the class definition with the class method is to squirrel it away in a module. This results in a very clean Ninja class…

This touches on the concept of simplexity. The Ninja class hasn’t actually been made simpler, the complexity has simply been hidden off somewhere out of site. That said, once can certainly make the case that housing the attr_initialized method with the Ninja class is a severe violation of the Single Responsibility Principle. In general, I recommend moving these class methods out to a separate module, and leaving the class definition free to express the domain intent.

Thanks to John Hume and Jay Fields for their input and thoughts on structural duplication and class methods. For more examples of of this class method usage, see this post by Farooq Ali. As always, thanks for reading.

WordPress database error: [Table 'geyerindustriesblog.wp_comments' doesn't exist]
SELECT * FROM wp_comments WHERE comment_post_ID = '13' AND comment_approved = '1' ORDER BY comment_date

Comments are closed.