Compare
Symptom
Human

Several classes implement near-identical algorithms that differ only in a few specific steps. The shape is duplicated in every class; the shared structure is convention rather than code; adding a step to the algorithm shape means editing every class in lockstep.

Agent

Duplicated algorithm skeletons across N classes the agent must verify in lockstep on every shape edit. The shared structure is invisible to static analysis; the agent cannot prove that all N implementations follow the same shape from source alone.

Goal
Human

The base class owns the algorithm's skeleton as a concrete method (the template method). Each variable step is an overridable method (hook). Subclasses fill in only the steps that differ; the shared skeleton lives in one place.

Agent

One template method in a base class the agent reads to understand the algorithm shape. Per-subclass reasoning collapses to 'which hooks does this subclass override'; cross-subclass verification of skeleton consistency is structural.

Before the pattern

class JavaScriptBuilder {
build() {
this.fetchSource();
this.compile();
this.runTests();
this.package();
}
fetchSource() { return git.clone(this.repo); }
compile() { return run('npx tsc'); }
runTests() { return run('npm test'); }
package() { return run('npm pack'); }
}
class PythonBuilder {
build() {
this.fetchSource();
this.compile();
this.runTests();
this.package();
}
fetchSource() { return git.clone(this.repo); }
compile() { return run('python -m py_compile .'); }
runTests() { return run('pytest'); }
package() { return run('python -m build'); }
}
class GoBuilder {
build() {
this.fetchSource();
this.compile();
this.runTests();
this.package();
}
fetchSource() { return git.clone(this.repo); }
compile() { return run('go build ./...'); }
runTests() { return run('go test ./...'); }
package() { return run('tar -czf project.tar.gz .'); }
}
// build() skeleton + fetchSource() duplicated across every builder.
// Adding a 'lint' step in the pipeline = 3 edits in lockstep.

After the pattern

class Builder {
build() {
this.fetchSource();
this.compile();
this.runTests();
this.package();
}
fetchSource() {
return git.clone(this.repo);
}
compile() {
throw new Error('subclass implements compile');
}
runTests() {
throw new Error('subclass implements runTests');
}
package() {
throw new Error('subclass implements package');
}
}
class JavaScriptBuilder extends Builder {
compile() { return run('npx tsc'); }
runTests() { return run('npm test'); }
package() { return run('npm pack'); }
}
class PythonBuilder extends Builder {
compile() { return run('python -m py_compile .'); }
runTests() { return run('pytest'); }
package() { return run('python -m build'); }
}
class GoBuilder extends Builder {
compile() { return run('go build ./...'); }
runTests() { return run('go test ./...'); }
package() { return run('tar -czf project.tar.gz .'); }
}
Example source: Illustrative example written for this site in the spirit of Design Patterns (Gamma, Helm, Johnson, Vlissides, Addison-Wesley, 1994), chapter 5. The book uses an Application/Document framework with skeletal initialization; this JavaScript adaptation uses a per-language build pipeline because the fixed-shape, variable-step structure is recognizable and the Pull Up Method savings show clearly.
Pressure
Human

Duplicated algorithm skeletons are the worst form of Duplicated Code — the duplication is in shape, not just in code text. Adding a new pipeline step (e.g., 'lint') is Shotgun Surgery; one missed subclass produces a pipeline that's silently incomplete.

Agent

Skeleton duplication forces every pipeline-step addition to edit N subclass bodies, with token cost scaling linearly in the subclass count; a missed subclass is a structurally-invisible bug that ships when the affected variant is the less-exercised one in the test suite.

Tradeoff
Human

Inheritance couples subclasses tightly to the base class's skeleton; subclasses cannot easily reorder, skip, or insert steps without breaking the contract. The base class's hook set is the spec; subclasses cannot evolve independently without coordinated edits.

Agent

Inheritance binds the agent to a vertical hierarchy: every edit to the base class implicitly affects every subclass, and the agent must verify cross-subclass invariants on every hook addition. Stack traces span base + subclass methods; investigating one runtime error often requires reading both.

Relief
Human

Skeleton lives in one place; new steps land as a single edit; subclasses are small and read as 'here are the variable bits.' The algorithm shape becomes a structural commitment, not a convention; the type system can enforce hook implementations on every subclass.

Agent

Skeleton edits scope to the base class file; per-subclass edits are bounded by hook implementation; the type system enforces hook presence (where languages support it) catching missed subclasses at compile time.

Trap
Human

When the template method's skeleton stops describing what every subclass actually does — when subclasses need conditional skipping, reordering, or alternate paths — inheritance becomes a straitjacket. At that point reach for Strategy or a builder-style pipeline that constructs the algorithm shape from composable parts rather than inheriting it.

Agent

Hook proliferation — base class with 10 hooks each subclass overrides — turns the parallel hierarchy into the same N×M cell-verification problem the pattern was supposed to solve, only spread across more files. Watch for 'template method with > 4 hooks' as a sign the abstraction is over-reaching.