Path to functional style: a TypeScript refactoring example
By: Sunny Sun
Tags: Refactoring, JavaScript, Functional Programming

This article talks about how to refactor a function with imperative style into functional style. The function is refactored in a few passes and I will discuss the rationale of the changes.

Imperative vs Functional

Imperative code mutates the application state in a step by step control flow， in contrast to the Functional programming which emphasizes the use of pure functions and avoids data mutation. Functional programming is a form of declarative programming. The declarative approach can make the code more readable and maintainable.

Original code

The following Type Script function is in Imperative style. It take a query param string, and output a array of param key values pair. The function has a few issues:

Too many Temporary Fields which affect the readability and make it difficult to refactor. Loops, which can be replaced by map operator that can perform the same operations in a functional style. Long Method, it smells as we have a reason to expect a shorter version given it is a simple function. Inconsistent naming of variables.

First Pass

The first step is to breakdown the function to smaller functions using Extract Method.

Two functions are extracted

A new function “splitToPair” is extracted to separate the logic of split a single param keyvalue pair. A new arrow function replace the split code statement. This is the first step to move from imperative to functional style, more to come at the next pass.

Second Pass

Now it is the time to replace for loop with map operator, as you can see, the main function is smaller, easier to read and fluent.

Another new change is the splitToPair function, it has been further refactored by extracting the indexOfSeparator function.

Although it looks much better now, there is still room to improve. The main function still smells imperative, as it is step by step.

Final version

Now we chain the functions together in the main function, so it becomes one line. Not only the function becomes compact, but more importantly, it express the intent of the code in a more nature and fluent way.

splitToPair function is further simplified using Destructuring assignment to unpack the returned values from splitString function. If you are not familiar with Destructuring assignment, it is a cool feature come with ES6 which provides a concise way of unpack values from array or object, check it out.

Now compare the original code with the final version, the new code is 10 lines instead of 19.

Not only it is smaller method, but also we have removed most of the Temporary Fields, use map operator to replace Loop, and the name of variables are more consistent.

Final

This exercise breaks the one single functions into four much smaller functions, and the refactored functions are generic functions, so they can be reuse easily.

It is possible to further factor the function with High order functions, i.e., create a higher order function that take the map operator and return a function, so we can the nest the splitString and splitToPair together in a more concise format. But it looks a overkill for this simple method.

Special thanks to Hatem Hosny and Ryan Harrington for their valuable comments. Ryan has created a github repo with Unit test here.

Using Currying and data last approach

Thanks contribution from Tom Bessems

Hope you can pick one or two things from this article. Happy programming!