Template method pattern in real case
Tue 11 Jun 2019

Have you ever heard Template Method pattern? We thought we know it but we might be wrong. I just found a secret, a meaning of this pattern. Template method supported by inheritance. So what is template method? 

This is definition we grab somewhere on internet (lol) but it's true.

Template Method is a behavioral design pattern that defines the skeleton of an algorithm in the superclass but lets subclasses override specific steps of the algorithm without changing its structure.

Thanks to https://refactoring.guru/ I took this picture from them.

I might want to change some steps of specific flow to get different result. However it's still build_house method which is interface method.

By doing this we can limit the number of interface methods.

That is good! We only build sufficient interfaces. No more, no less. That makes it easy for developer to code and easier to newbie to understand the system, avoiding duplicate code (not same code but do same thing).

We wrote code to solve thing perfectly. The trouble is that we need to vary the middle of code (method or code block in general). Sometimes we need to to this, sometimes we need to do that at middle and even adding new code in future. so why don't we separate this function to many smaller functions? The problem is that. No matters, we can do that but we need to have a main function to gather those functions and involving them continuously. However. For example.

def main_function

Sometimes we want to involve func4 instead of func2. How? Furthermore, we would want to extend this function in future by making some changes at func2 (middle) position. Something worse we can do at that time:

  • modifying main_function (1)
  • adding if statements at position of func2. (2)
  • adding yield (callback) at position of func2. (3)

(1) this is worst case we need to avoid. Modification means taking risk.

(2) this would make this function gross, not clean.

(3) this is hard to manage code. Because we might make duplicated code or even more messy. Callback code block is like the parameter. Thus, we have to provide this block every we call the function. In other hand, we might do same things at many places where we involve main_function - give the same block. So that we have template method.

Let's firstly have a look on this code.

module HackerNewsServices
  ATag = Struct.new(:title, :href)

  class Crawler < Base
    PATH = 'table.itemlist tr.athing td.title a.storylink'.freeze
    META = {
      image: 'meta[property="og:image"]',
      excerpt: 'meta[property="og:description"]'

    def latest_news(opts = {})
      collect_a_tags(limit: opts[:limit]).each_with_object([]) do |a, res|
        data = get(a.href)
        res << HackerNew.new(title: a.title, image: image(data), excerpt: excerpt(data))


    def image(data)
      data.at(META[:image]).try(:[], 'content')

    def excerpt(data)
      data.at(META[:excerpt]).try(:[], 'content')

    def collect_a_tags(opts = {})
      data = get.css(PATH)
      limit = opts[:limit] || data.size
      data.take(limit).collect do |a|
        ATag.new(a.text, a['href'])

    def get(href = nil)
      Nokogiri::HTML(open(href || url))

    def get_src_link_preview(html)
      data = Nokogiri::HTML(html)
      return nil if data.css('img').empty?

    def get_external_content(data)
      img = data.at('meta[property="og:image"]')
      desc = data.at('meta[property="og:description"]')

We can see that there are a ton of code (private methods). By the way, we think about leaving a room for future. The code need to be easy for extending, DRY and readable. If we want to make changes, we make only smallest changes to meet requirements. This is code after refactor.

module HackerNewsServices::Crawlers
  class NewsList < Base

    def data(opts = {})
      atags = collect_tags(limit: opts[:limit]).collect do |tag|
        create_element tag
      block_given? ? yield(atags) : atags


    def create_element(tag)
      raise NotImplementedError

    def collect_tags(opts = {})
      raise NotImplementedError

    def get_html(href = nil)
      Nokogiri::HTML(open(href || url))

Source: https://github.com/nctruong/news-reader/blob/master/app/services/hacker_news_services/crawlers/news_list.rb

These are template methods:

  • create_element
  • collect_tags

We are planing to do things. We put these methods into a context and allowing to implement these ones later - template, by using inheritance we have to implement these methods. If not, it would raise Exception.

Using abstract class to define template methods (abstract). Using subclasses for implementations.

However, we should consider carefully about using this pattern. Remember another pattern:

Using composition instead of inheritance - My words but same meaning.

I like to make something belongs to me. You should do that too. It's like when we solve problems. Let's say in our words about problem. It proves that you deeply understand it. Inheritance would increase the connections (big ball of mud).

Thank for reading!