Functional Refactoring in JavaScript

in Too Much Detail

Yesterday, one of my colleagues asks me to help him to get the “functional” solution of a simple programming challenge: the advent of code day 2.

Edit: to be clear, that example is obviously overkill (and this is why it is subheaded “in too much detail”), but this is about the journey, not the goal :).

I don’t pretend to be an expert in functional programming, but I hope you’ll find interesting to have the different steps and thoughts that have guided me during this refactoring.

In this exercise, we have to compute the total surface area needed to wrap boxes (which have different sizes). Knowing the surface of one box is computed by the following formula (from the problem statement):

2*l*w + 2*w*h + 2*h*l + smallest side surface

And we will assume that our input has already been converted to an arrays list:

[ [l, w, h], [l, w, h], … ]

First let’s start with the classic procedural solution:

The first thing we notice is the accumulation through the total_surface variable, which is symptomatic of a missing reduce function:

Let’s extract each operation to its own function for a better separation of concerns:

I don’t really like the sides function because it does three times the same thing. It’s time to replace it with a recursive alternative:

Same mixed feelings with the content of the box_surface function, it looks like a reducer is missing:

Now we can delete the smallest_side function and put it in box_surface. And in the same time, remove the unnecessary parenthesis:

Since sides return an array, and box_surface make a reduction on it. We can extract the reduce instruction from the box_surface function:

Ok, but there is something we really love in the functional world: to have only pure expressions (that mean no { } characters to define lambda function’s body).

It is not possible here because box_side is used twice at line 9. So, let’s create a simple function apply to handle this:

We notice this apply function really looks like an IIFE:

At least, we can extract the boxes.reduce function (lines 7–8) and replace the box_surface function.

Now, we have only simple expressions to compute all the required steps:

Compare it with the original procedural code:

To be clear, this is not production code nor “best practice”. This is about solving a simple exercise with the most (to absurdity) functional idioms: only pure expressions and no duplications.
Of course, the readability is worst, but the idea was to show the thought process and the techniques involved.