Template Method rocks but Higher Order Function can do the trick

Marco Nicolodi
Qualyteam Engineering
5 min readJan 28, 2019
Photo by rawpixel on Unsplash

I love object orientation, and C# implements it in a very elegant manner, but since I do lots of JavaScript, sometimes I do mess with some functional stuff. It bothers me when people say functional programming is hard… It’s just different! Also, it’s not like Object Oriented Programming (OOP) is THAT easy. You have Design Patterns, SOLID (and solid is composed by SRP, OCP, LSP, ISP, DIP), inheritance, encapsulation… so why sometimes functional programming seems to fail to show its value? I think maybe the lack of real world examples makes OOP developers doubt the usefulness of it. After all, even though currying is awesome, no one needs it to sum two numbers!

In this short article, I’m going to show an elegant functional solution to a real-world problem and its OOP equivalently elegant solution, from an OOP developer perspective.

The Problem

At Qualyteam we have lots of scripts related to DevOps. As the number of scripts grew, our team had to reach for npm/docker/kubernetes/build/migration scripts in files, wikis, and documentations spread around. To solve this problem, we’ve built an internal CLI using Node JS (I will write an article about it soon!) to avoid this search hassle and free our talented developers to keep delivering our amazing products.
One of the CLI’s feature is to allow a developer to choose a test spec file to run:

This is the function that shows this option dialog:

We pass a directory as a parameter. At line 2, the filesystem.list helper returns a string array containing all filenames within that directory. We use this file array as options to a prompt dialog, at line 9. The chosen file is then returned.

After a few days of usage, we’ve come with the idea to let developers choose a Docker image to build. We wanted to use the same function, but the directory containing the Dockerfiles also contained other files not related to Docker, hence the filesystem helper needed to support filtering, returning only .Dockerfile extensions. We’re expecting to just pass a matching parameter to the filesystem.list helper, but we’ve found out that another helper, the filesystem.find, was the only function that supported filtering. We could then use a conditional statement to choose between either filesystem.listor filesystem.finddepending on if we want to choose all files or all files matching a blob pattern:

We’ve added an additional matching parameter to chooseFileand a conditional statement to switch between filesystem helper functions. Conditional statements are evil. They seem to solve everything but they often let the hell lose. We’ve added complexity to our function, and disrespected the Open Closed Principle (OCP):

Software entities should be open for extension, but closed for modification.

There’s no way we could extend the use of this function by adding support for another filesystem helper, and we’ve actually modified it to fulfill the new requirements.

Object Oriented approach

I know how I would solve this problem elegantly with Object Oriented Programming. I would make use of the Template Method design pattern.

Template Method description on Refactoring Guru:

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.

This is a C# representation of the above chooseFile function, using the template method pattern:

The abstract FileChooser is our superclass class that defines the algorithm’s template. Note that the Choose is a public method. This is the method that’s going to be called by the client classes. It defines the algorithm template and a step that each subclass should implement, the Find(Request request) abstract method. Each superclass will override it to implement this method, using the right Filesystem helper:

We’ve managed to solve the problem without a conditional statement! Both finders just override the file fetching algorithm step. Notice how none finders define a public method. The client classes would actually call the abstract class public Choose method, which would call the subclasses Find algorithm step. This is called The Holywood Principle:

Don’t call us. We’ll call you

Back to the functional land

Ok, but that’s in the cozy OOP land. We’re using JavaScript ❤ now, so let’s go functional! How would we achieve the same level of OCP compliance without adding another conditional statement?

Higher Order Function to the rescue

A Higher Order Function is a form of function composition in which a function either receives another function as a parameter or returns a function. Javascript’s map, filter, and reduceare examples of Higher Order Functions.

Take filter, for example. It can filter an array given any predicate, and we don’t use inheritance for that. We just pass our predicate, which is a function that returns a boolean, as a parameter, and the filter function will iterate over the array to return only the values that fulfills our predicate.

But how could we use a Higher Order Function to solve our problem? We can pass the filesystem helpers result as a function to the chooseFile function. Remember these conditionals?

Let’s split them into two functions:

Now let’s turn our old chooseFile into a Higher Order Function:

Now our chooseFile function receives a finder function as a parameter and returns another function. It doesn’t know the finder fetches the files within a folder and is open for extension since it allows any finder to be passed in.

To those unfamiliar with ES6 arrow function syntax, this is the same as:

https://gist.github.com/MarcoNicolodi/4e4941deccfa28a5ac8863a9e3ed8769

To avoid having to pass the finder every time you need to choose a file, we can leverage function composition:

Here’s the whole solution:

Summary

Our functional solution using a Higher Order Function achieves the same as our OOP solution using the Template Method design pattern. It’s open for extension and closed for modification, since it accepts any finder, and has a single responsibility, since it will not change if a finder requirement changes.

Higher Order Function is a basic concept in functional programming, and you use it a lot if you code in JavaScript. For more details you can dive deeper with the amazing Eloquent Javascript Ebook.

--

--