The Template Pattern is underused
While a large portion of the Gang of Four software patterns are rendered useless by the dynamic nature of Ruby, one that stands the test of time is the Template Pattern.
Simplicity is king.
Simplicity is the stalwart of good software development. In every case, a responsible developer will search for the simplest solution to a problem.
The beauty of the Template Pattern lies in its simplicity. While the full description is verbose and sleep inducing, the pattern is very simple: Enable easily configurable behavior by separating the steps of a process into (sometimes empty) methods that a subclass can override. Here's a quick example:
module SandwichMaker
def make_sandwich
assemble(find_bread, find_filling, find_condiments)
end
def find_bread; "Wonder"; end
def find_fillings; "Ham"; end
def find_condiments; "Mustard"; end
def assemble(bread, filling, condiments)
# control robotic arm... whatever.
end
end
class NormalSandwich
include SandwichMaker
end
class BolognaSandwich
include SandwichMaker
def find_fillings
return "bologna"
end
end
Inheritance, method overriding… This should look totally familiar and fairly boring. But the outcome is perfect: The BolognaSandwich
class can make its namesake without resorting to a DSL, blocks, meaeeaeaetaprogramming, or whatever. It's just a bunch of methods.
We should totally do this shit!
Let's look at another one of my favorite tools, Inherited Resources. Here's a snippet from one of my Inherited Resources controllers:
class NotesController < InheritedResources::Base
def create
create! do |success, failure|
success.html { redirect_to some_other_url }
end
end
end
Now, personally, I find this DSL to be fairly terrible. What's with the create!
method inside the create
method? The template pattern would have been a better approach:
class NotesController < InheritedResources::Base
def url_for_redirect_after_successful_create
some_other_url
end
end
It's totally clear what that method does, there's zero magic going on, and the implementation would likely be much simpler.
By the way: anyone who has an issue with a method name that long can go back to Perl.
Cautions
There are some issues to be aware of when using the Template Pattern.
The main issue with implementing a useful and readable template is in determining just where to break out behavior into overrideable methods. Give the end user too few hooks, and at some point they will be forced to override the entire method. Include too many hooks, and your implementation is littered with method calls - increasing maintenance costs.
Another place where the Template Pattern falls short is when behavior must be chained. A great example of this is in ActiveRecord
callbacks. You can override before_save
, but doing so is generally recognized as being an antipattern, since all the behavior that should happen at that time must be crammed into that method. The "right way" of adding callbacks is through the before_save :method_name
calls. They chain onto each other in a graceful and maintainable fashion.