skip to content

What smell does the refactoring "Form Template Method" address, what are its mechanical steps, and what are its main drawbacks?

level: middleimportance: should knowfreq 38%

answer

  1. same step ORDER, different step bodies
  2. extract steps → align sequences → pull up skeleton
  3. abstract steps vs defaulted hooks
  4. superclass owns order, subclass owns details
  5. costs: inheritance slot, fragile base class

basics

~20 s

It targets sibling subclasses whose methods do the same steps in the same order but differ in a few step bodies. You make the steps identical in shape, pull the shared sequence up into the superclass as one method, and leave the differing steps as overridable hooks.

solid answer

~50 s

Form Template Method (Kerievsky, building on Fowler's Extract/Pull Up Method) tackles duplicated *algorithm skeletons*: two or more subclasses implement the same overall procedure with the same step order, but individual steps differ. Mechanics: extract each conceptual step in every subclass into its own method with the same name and signature across siblings; make the step sequences textually identical; unify signatures/return handling; then pull the sequence method up to the superclass, leaving the varying steps as abstract or defaulted hook methods, and pull up any steps that turned out identical. Now the order of the algorithm exists once. Drawbacks: it locks you into inheritance (single-inheritance languages spend your one base class), creates a fragile base-class coupling where subclass authors must know which hooks are required and what invariants hold between them, and hurts testability of hooks in isolation. Where composition is preferable, the same duplication can be removed with a Strategy or higher-order function.

go deeper

for a junior

Say it removes duplication where subclasses repeat the same sequence of steps; the shared sequence moves to the parent and the differing steps become methods subclasses implement.

for a middle

Give the mechanics in order (extract steps with matching names, align sequences, pull up the skeleton, declare abstract vs hook steps) and note the tests-green-per-step discipline.

for a senior

Cover the trade-offs: fragile base class, one inheritance slot, hook proliferation, constructor/hook hazard, and when Strategy or function parameters are the better destination.

for a principal

Frame it as a coupling decision — inheritance is a compile-time, hard-to-reverse contract exported to every subclass author, including other teams; prefer composition at module/library boundaries and reserve Template Method for tightly held internal hierarchies.

## The smell **Duplicated algorithm skeleton across siblings.** Two subclasses each have a `generate()`: ``` HtmlReport.generate(): openTag(); writeTitleHtml(); writeRowsHtml(); closeTag() CsvReport.generate(): writeHeaderCsv(); writeRowsCsv(); ``` At first glance these look different, but re-read them at the right altitude: both do *prologue → title → rows → epilogue*. The **order and the intent** are duplicated even though the bodies differ. That is the specific duplication Template Method removes; ordinary Extract Method can't, because no two lines are literally identical. Why it matters: when the algorithm gains a step ("every report must emit a checksum after the rows"), you must edit every subclass and can silently miss one, or insert it in the wrong position. ## Definitions - **Template Method pattern**: a superclass method defines the *invariant* skeleton of an algorithm and calls out to steps; subclasses supply the varying steps. Fowler's phrasing: "the superclass owns the order, the subclass owns the details." - **Hook method**: a step the subclass may override; if it has a no-op or default implementation, overriding is optional. - **Abstract step**: a step the subclass *must* implement. ## Mechanical steps 1. **Cover with tests** for each subclass's full output. 2. **Extract Method for each conceptual step**, in each subclass, choosing the *same name and signature* across siblings (`writeTitle()`, `writeRows()`). Nothing moves yet; each subclass now reads as a list of step calls. 3. **Align the sequences.** Reorder where safe, and introduce empty step methods where one sibling lacks a step, until the step-call sequences are textually identical. This is often the hardest part — it may require pushing a difference *down* into a step body (e.g. making a step that writes nothing). 4. **Unify signatures and shared state.** If one sibling passes a writer and another uses a field, normalize. 5. **Pull Up Method**: move the now-identical sequence method into the superclass; make it the template method. 6. **Declare the steps** in the superclass — abstract where every subclass differs, defaulted (hook) where most share behavior; **Pull Up** any steps whose bodies turned out identical. 7. **Consider making the template method final/sealed** so subclasses override steps, not the skeleton. Run tests after every step; each one is behavior-preserving on its own. ## Trade-offs and edge cases - **Inheritance cost.** In single-inheritance languages the base class slot is spent, and the subclass can no longer be reused outside this hierarchy. Composition-based alternatives (pass step functions, or a Strategy object holding the varying steps) keep that flexibility, at the cost of a parameter object. - **Fragile base class.** Changing the skeleton or the calling contract silently breaks distant subclasses. Document (and, where the language allows, enforce) which hooks are mandatory, what state is valid when each is called, and whether hooks may call back into the template. - **Hook proliferation.** If you keep adding `beforeX()/afterX()` hooks, the skeleton stops being readable and the class becomes a framework of its own — a sign that the variation belongs in composed objects. - **Don't call overridable methods from a constructor.** A base constructor invoking a hook runs before the subclass's fields are initialized — a classic source of null/uninitialized bugs in class-based languages. - **Testing.** Hooks are usually protected and only reachable through the template, so tests exercise the whole algorithm. With Strategy/functions, each step is directly testable. - **Two subclasses is thin evidence.** Kerievsky's rule of thumb applies: duplication plus a *pressure to change together* justifies the move; two stable classes may not. - **Related destination:** if the differing steps also need to vary *independently of each other or at runtime*, Template Method is the wrong shape — Strategy composition scales better. ## What good looks like afterwards The superclass reads as an executable outline of the algorithm; each subclass reads as a short list of the details it supplies; adding a step is a one-place change; and no subclass can accidentally reorder the algorithm.

  • When would you use composition instead of Template Method to remove the same duplication?
    When the varying steps must change at runtime, vary independently, be reused across unrelated hierarchies, or be unit-tested in isolation; when the class already needs its one inheritance slot; or when the hook count is growing. Then keep one concrete class holding the skeleton and pass the varying steps in as a Strategy object or as functions/lambdas — same 'order defined once' benefit without subclass coupling.
  • Why is calling an overridable hook from a base-class constructor dangerous?
    Because in most class-based languages the base constructor runs before the subclass's field initializers and constructor body. An overridden hook invoked there sees uninitialized subclass state — nulls, zeros, or partially built collaborators — producing bugs that only appear for certain subclasses. Initialize first, then have the caller invoke the template method explicitly.

A recipe card that says: preheat, prepare base, add filling, bake 40 min, cool. The card (superclass) fixes the sequence; each specific pie (subclass) only fills in 'prepare base' and 'add filling'. Change the bake time once, on the card, and every pie follows.

saying these in an interview costs you the question

  • "Template Method just means having an abstract base class" — the defining property is that the superclass owns the algorithm's step ORDER.
  • Applying it to two methods that merely look similar but have genuinely different orders/intents, forcing a false skeleton.
  • Letting subclasses override the template method itself, which destroys the invariant the pattern exists to protect.
  • Adding before/after hooks indefinitely until the base class is an unreadable mini-framework.
  • Ignoring that inheritance is a stronger, less reversible coupling than composition.

context