Using functional programming to avoid intermediate variables and nested functions
Tags: node, javascript
Published: 2019-09-25 23:21:10

---
title: Using functional programming to avoid intermediate variables and nested functions
published: true
canonical_url: https://www.coreycleary.me/using-functional-programming-to-avoid-intermediate-variables-and-nested-functions/
tags: node,javascript
---

<em><strong>Originally published at <a href="https://www.coreycleary.me/using-functional-programming-to-avoid-intermediate-variables-and-nested-functions/">coreycleary.me</a></strong>. This is a cross-post from my content blog. I publish new content every week or two, and you can <a href="https://www.coreycleary.me/about/">sign up to my newsletter</a> if you'd like to receive my articles directly to your inbox! I also regularly send cheatsheets and other freebies.</em>

Often when we're developing a piece of code, we need to take one starting value and apply several functions to it before we return that value.

Something like:

```javascript
const incompleteTasks = getIncomplete(tasks)
const withoutBlockedTasks = getNonBlocked(incompleteTasks)
const sortedByDueDate = sortByDueDate(withoutBlockedTasks)
const groupedByAssignee = groupByAssignee(sortedByDueDate)
// etc...
```

The problem with this is that it's difficult to read. Whenever you add intermediate variables (`incompleteTasks`, `withoutBlockedTasks`, etc.), you have to track which ones are passed as arguments to the next functions. So you do a lot of variable tracking when you're reading the code. And why create a bunch of intermediate variables if we don't end up using them anywhere else? It feels like a waste.

Sure, if it's only a couple of variables that shouldn't affect readability/understanding the code too much, but when you need to pass a starting value through lots of functions, it can get messy and painful quickly.

One way to get around using intermediate variables is to do something like:

```javascript
groupByAssignee(sortByDueDate(getNonBlocked(getIncomplete(tasks))))
```

...but using nested functions like that makes it <strong>even more</strong> unreadable. And good luck adding debug breakpoints to that!

<h3>Functional programming to the rescue</h3>
Using a functional programming pattern called <em>functional composition</em>, we can get make something that is <strong>much</strong> more readable, without intermediate variables or nested functions.

Something that will make it much easier for those reading your code and reviewing your pull requests.

And everyone wants to be using functional programming these days - it's the cool thing to do now, and for good reason. I've found that just by using functional composition you can get pretty far and get many of the benefits of functional programming without having to learn the other more complex stuff, like what the hell a monad is.

So think of this as killing two birds with one stone! It'll make the code more readable <em>and</em> you'll get to use more functional programming.

<h3>Functional composition</h3>
Rather than <em>first</em> try to explain composition with a definition, let's look at it in code. Our original code, which gets the remaining open tasks per user for the iteration, would look like this:

```javascript
const { pipe } = require('ramda')

// here are the individual functions, they haven't changed from the above,
// just including them so you can see their implementation
const getIncomplete = tasks => tasks.filter(({complete}) => !complete)

const getNonBlocked = tasks => tasks.filter(({blocked}) => !blocked)

const sortByDueDate = tasks => tasks.sort((a, b) => new Date(a.dueDate) - new Date(b.dueDate))

const groupBy = key => array => {
    return array.reduce((objectsByKeyValue, obj) => {
        const value = obj[key]
        objectsByKeyValue[value] = (objectsByKeyValue[value] || []).concat(obj)
        return objectsByKeyValue
    }, {})
}

const groupByAssignee = groupBy('assignedTo')

// this is the magic
const getIterationReport = pipe(
    getIncomplete,
    getNonBlocked,
    sortByDueDate,
    groupByAssignee
)
```

Pretty simple, right? We just put our functions into a `pipe` function... and that's it! And to call the function, it's just:

```javascript
const report = getIterationReport(tasks)
```

<em>Wait, but I thought `getIterationReport` was a variable, not a function?</em>

Here we're using the `pipe` function from the functional programming library <a href="https://ramdajs.com/" rel="noopener" target="_blank">Ramda</a>. `pipe` returns a function, so the value of `getIterationReport` is actually a function. Which lets us then call it with whatever data we want, in this case `tasks`.

Functional composition, thus, allows us to "chain" together functions to create another function. It's that simple! Instead of having to store the result of each step of transforming our original data like we did with the intermediate variable approach, we just <strong>define what those steps are</strong>.

This:

```javascript
const getIterationReport = pipe(
    getIncomplete,
    getNonBlocked,
    sortByDueDate,
    groupByAssignee
)
```

is so much nicer than this:

```javascript
const getIterationReport = tasks => {
    const incompleteTasks = getIncomplete(tasks)
    const withoutBlockedTasks = getNonBlocked(incompleteTasks)
    const sortedByDueDate = sortByDueDate(withoutBlockedTasks)
    return groupByAssignee(sortedByDueDate)
}
```

<h3>Kinds of composition</h3>
There are generally two kinds of composition - `compose` and `pipe` - <a href="https://www.coreycleary.me/why-is-compose-right-to-left/" rel="noopener" target="_blank">compose being right to left</a>, and `pipe` being left to right.

I prefer using `pipe` as it follows the Western standard of reading left to right (or top down, like we've formatted it here) and makes it easier to understand how your data will pass through each function sequentially.

<h3>On arguments</h3>
Most `pipe` and `compose` implementations will only operate on one argument - "unary" in FP terms. So composition is best fitted for functions that take one value (like our `tasks` here) and operate on that value. Our `getIterationReport` function would, as it stands now, not work if we had to pass in other arguments in addition to `tasks`.

There are ways of transforming your functions to get around this, but that's outside the scope of this post.

Just know that if you're using Ramda's pipe, <a href="https://ramdajs.com/docs/#pipe" rel="noopener" target="_blank">the first function may have any number of arguments</a>, but the rest must be unary. So if you do have one function that requires multiple arguments, put it first in the `pipe`. 

<h3>The data and the result</h3>
Now to complete the rest of the picture, let's look at the data we'll call this function with:
```javascript
const tasks = [
    {
        assignedTo: 'John Doe',
        dueDate: '2019-08-31',
        name: 'Add drag and drop component',
        blocked: false,
        complete: false
    },
    {
        assignedTo: 'Bob Smith',
        dueDate: '2019-08-29',
        name: 'Fix build issues',
        blocked: false,
        complete: false
    },
    {
        assignedTo: 'David Riley',
        dueDate: '2019-09-03',
        name: 'Upgrade webpack',
        blocked: true,
        complete: false
    },
    {
        assignedTo: 'John Doe',
        dueDate: '2019-08-31',
        name: 'Create new product endpoint',
        blocked: false,
        complete: false
    }
]
```

When we call the function, the result will look like:

```javascript
{
	'Bob Smith': [{
		assignedTo: 'Bob Smith',
		dueDate: '2019-08-29',
		name: 'Fix build issues',
		blocked: false,
		complete: false
	}],
	'John Doe': [{
			assignedTo: 'John Doe',
			dueDate: '2019-08-31',
			name: 'Add drag and drop component',
			blocked: false,
			complete: false
		},
		{
			assignedTo: 'John Doe',
			dueDate: '2019-08-31',
			name: 'Create new product endpoint',
			blocked: false,
			complete: false
		}
	]
}
```

As you can see, we filtered out completed and blocked tasks, and grouped the tasks by the developer working on them.

While our task data structure is not super complex, hopefully this helps you see how easily and cleanly we can transform the data using composition and without having to resort to using intermediate variables to store each step of the sequence of transformations.

So the next time you find yourself writing code like:

```javascript
const incompleteTasks = getIncomplete(tasks)
const withoutBlockedTasks = getNonBlocked(incompleteTasks)
const sortedByDueDate = sortByDueDate(withoutBlockedTasks)
const groupedByAssignee = groupByAssignee(sortedByDueDate)
// etc...
```
where you're storing each step result as a variable and just passing that result to the next function, use either `compose` or `pipe` from Ramda or whatever library you choose to make this much easier to read and reason about!

And if you found this post helpful, <a href="https://www.coreycleary.me/about/">here's that link again</a> to subscribe to my newsletter!