Cooking Up a Good Template Method

The software concept of “raising the level of abstraction” has improved my skill and creativity in cooking, by teaching me to think about recipe components in terms of their properties and functions. Practicing abstraction-raising in cooking feeds back to help me with coding; for example, keeping me from going astray the other day with the Template Method pattern. This post is more about coding than cooking. The cooking’s a metaphor. (The cake is a lie.)

Abstract Cooking

My skill with cooking grew from rote recipe following to intuitive creation when I started to think of it in terms borrowed from software: raising the level of abstraction.

Consider a week-night skillet dinner. If I told you to heat canola oil in a cast-iron skillet, saute slices of onion and chunks of chicken seasoned with salt and pepper, and toss in bell peppers cut into strips, you could probably follow along and make exactly that. But that’s pretty limiting. If instead I described the process as using a fat to conduct heat for sauteing a savory root, a seasoned protein, and some vegetables, then you could use that as a template, and make a week of dinners without repeating yourself.

Let’s dive into that step of using a fat for conduction, because it is a cool and useful bit of food science. To cook, you need to get heat onto food. The medium can be air, liquid, or fat. Each creates different results, hence the terms baking, boiling, and frying. When you toss cut-up bits of food in a skillet with oil and repeatedly jostle them, you’re sauteing (“saute” means “to jump”), and that oil is playing the role of the fat, which is conducting the heat. If you’ll pardon the metaphor, CanolaOil implements the IFat interface.

It’s useful to think of cooking this way, because if you know the properties of the various cooking fats, you can choose the right IFat implementation for the job. Canola oil is heart-healthy and stands up well to stove-top heat. Olive oil has wonderful health benefits, a bold flavor, and an intriguing green color, but those attributes are pretty much obliterated by heat, so save your expensive EVOO for raw applications like salads and dips. Butter makes everything taste better, browns up beautifully, but is harder on the heart and will burn at a low temperature; temper it with an oil like canola to keep it from burning. Peanut oil stands up to heat like a champ, so it’s popular for deep frying. Armed with this kind of knowledge, I don’t need to check a recipe when I’m cooking; I just think about what I’m trying to accomplish, and choose the right implementation.

Pam Anderson’s How to Cook Without a Book got me thinking about food this way, and Harold McGee’s On Food and Cooking provides a feast of food geekery to fill in all the particulars.

Template Coding

Thinking about food this way, raising the level of abstraction, guides my thinking about code. My meal preparation follows the Template Method pattern, as does a class my teammate and I needed to modify recently.

In this example, our application sends instructions to various external systems. The specifics of how those systems like to hold their conversations vary between systems. However, the series of steps, when phrased in our core business terms, remain the same. You do A, then you do B, then you do C, in whatever way a particular instance likes to do A, B, and C.

Here’s my class with its template method, translated back to the dinner metaphor:

    3     public abstract class SkilletDinner

    4     {

    5         public void Cook()

    6         {

    7             HeatFat();

    8             SauteSavoryRoot();

    9             SauteProtein();

   10             SauteVegetables();

   11         }

   12 

   13         protected abstract void HeatFat();

   14         protected abstract void SauteSavoryRoot();

   15         protected abstract void SauteProtein();

   16         protected abstract void SauteVegetables();

   17     }

But lo, I encountered an external system that needed to do one extra little thing. I needed a special step, just for that one instance. Like dinner the other night, where the vegetable was asparagus, the fat was bacon (oh ho!), and the final step was to toss some panko breadcrumbs into the pan to brown and toast and soak up the bacony love.

How do I extend my template method to accommodate an instance-specific step?

One idea that floated by was to make the method virtual, so that we could override it in our special instance. But we still wanted the rest of the steps, so we’d have to copy the whole method into the new instance, just to add a few lines. Also, anybody else could override that template, too, so that when they were told to do A, B, and C, they could totally fib and do nothing of the sort.

    3     public abstract class SkilletDinner

    4     {

    5         public virtual void Cook()

    6         {

    7             //Note: The Cook template method is now virtual,

    8             //and can be overridden in deriving classes.

    9             //That’s not good.

   10             HeatFat();

   11             SauteSavoryRoot();

   12             SauteProtein();

   13             SauteVegetables();

   14         }

   15         protected abstract void HeatFat();

   16         protected abstract void SauteSavoryRoot();

   17         protected abstract void SauteProtein();

   18         protected abstract void SauteVegetables();

   19     }

   20 

   21     public class LazyDinner : SkilletDinner

   22     {

   23         public override void Cook()

   24         {

   25             OrderPizza();

   26             //We’re overriding the template and *cheating*!

   27             //Although, if it’s Austin’s Pizza,

   28             //maybe that’s okay…

   29         }

   30 

   31         private void OrderPizza()

   32         {

   33             //With extra garlic!

   34         }

   35 

   36         protected override void HeatFat() { }

   37         protected override void SauteSavoryRoot() { }

   38         protected override void SauteProtein() { }

   39         protected override void SauteVegetables() { }

   40     }

That LazyDinner class isn’t really a SkilletDinner at all; its behavior is completely different. No, that option flouts the whole point of the Template Method pattern.

Our better idea was to make one small change to the template method, adding an extension point. That is, a call to a virtual method which in the base implementation does nothing, and can be overridden and told to do stuff in specific cases.

Back to dinner:

    3     public abstract class SkilletDinner

    4     {

    5         public void Cook()

    6         {

    7             HeatFat();

    8             SauteSavoryRoot();

    9             SauteProtein();

   10             SauteVegetables();

   11             AddFinishingTouches(); //Here’s the hook.

   12         }

   13 

   14         protected virtual void AddFinishingTouches()

   15         {

   16             //By default, do nothing.

   17         }

   18 

   19         protected abstract void HeatFat();

   20         protected abstract void SauteSavoryRoot();

   21         protected abstract void SauteProtein();

   22         protected abstract void SauteVegetables();

   23     }

   24 

   25     public class FancyBaconPankoDinner : SkilletDinner

   26     {

   27         protected override void AddFinishingTouches()

   28         {

   29             //In this case, override this extensibility hook:

   30             ToastBreadcrumbs();

   31         }

   32 

   33         private void ToastBreadcrumbs()

   34         {

   35             //Toss in the bacon fat; keep ‘em moving.

   36         }

   37 

   38         protected override void HeatFat()

   39         {

   40             //Cook bacon, set aside, drain off some fat.

   41         }

   42 

   43         protected override void SauteSavoryRoot()

   44         {

   45             //Minced garlic, until soft but before browning

   46         }

   47 

   48         protected override void SauteProtein()

   49         {

   50             //How about… tofu that tastes like bacon?

   51         }

   52 

   53         protected override void SauteVegetables()

   54         {

   55             //Asparagus, cut into sections.

   56             //Make it bright green and a little crispy.

   57         }

   58     }

This maintains the contract of the template method, while allowing for special cases. With the right extensibility hooks in place, my dinner preparation happily follows the Open-Closed Principle—open for extension, but closed for modification.

I enjoy the way my various hobbies feed into and reflect upon each other. I hope this post has given you some useful insight into the Template Method pattern, or dinner preparation, or both. Look for synergies amongst your own varied interests; it can be the springboard for some truly breakthrough ideas.

Mmm, bacon…

Related Articles:

    About Sharon Cichelli

    I am a Headspring Senior Consultant, developing custom enterprise software for our clients and leading training classes on the latest Microsoft technologies. I blog about .NET development, best practices in agile software development, and my nerdy hobbies.
    This entry was posted in Design Patterns. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
    • http://reboltutorial.com reboltutorial

      Well I call it Robot Flexible Worker :)

    • Jason

      I love it! cooking as a metaphor for coding. And yes, everything is better with bacon :)

    • http://scottbellware.com Scott Bellware

      You could also leave Cook() virtual, override it in the subclass, invoke the base class Cook() in the overridden Cook(), and call any subclass-specific methods from the body of the overridden Cook().

      The AddFinishingTouches() kind of hook thing works in opposition to the Template Method pattern’s intention of having rich semantics. You could call it DoSomethingElse(), or Whatever().

      The point of Template Method is to provide semantically-rich, domain-specific hook methods, and avoid the genericity of lifecycle hook method names like Finish() and Cleanup(), etc.

    • http://www.lostechies.com/members/sharon/default.aspx Sharon J. Cichelli

      Thanks, Scott, and of course I agree with you about choosing semantically rich method names. That’s a great point to emphasize. In the domain of cooking, I do think of toasting panko in bacon fat, or tossing on some pine nuts, or grabbing a sprig of cilantro and a squeeze of lime juice, as “finishing touches.” I suppose you could call it Garnish() (although I think of garnish as cold, like parsley).

      So that’s a good point: I called it “finishing” because my domain calls it such, so push yourself to find domain-relevant names for those extensibility points.

    • http://www.jarrettmeyer.com Jarrett Meyer

      Oh dear God, the amount of extensibility in the yet unwritten PrepareIngredients() method is making me go blind this early in the morning. Some things will need to be dethawed, others cut/diced/minced, and hopefully you don’t need to devein a shrimp.

    • http://MurrayOn.NET/ Mike Murray

      What a pleasant and enjoyable read! I would love to see more novel ideas and concepts such as this one out there on the Interweb!

    • Tom

      Never has reading about object-inheritance made my mouth water! Now for a Brisket template…

      IFat… heh…

    • just so you know

      you seem to have mixed up your healthy foods. canola oil is bad for you (in so many ways) and butter is good for you (doesn’t clog you heart). the research is out there if you think i am lying!

    • Alex Mancilla

      I use to make my analogies and metaphor for sytems with cooking, so i sounds very familiar to me, few months ago while barbecuing with Ryan Svihla, I got the ephipahny of Barbecue Rubs Recipe, basicly you look for a smoky, tangysweet and spicy mix(balanced is good), if you know your ingredients, then you can choose what you want to provide swetness, brwon sugar or piloncillo, also teh hot lelve and spiciness, paprika, cayenee, thai or havanero pepperflakes.
      The same goes software dessign ans pattern, you know interfaces give more clear contracts, absctract class bring their own juice, and allow you to play with it, etc. when you know your ingredients, and the process checkpoints, it is easy to Cook your template or to Code your dinner whatevher works better for you.