Composing functions in JavaScript
Tags: javascript, composition, functional, ramda
Published: 2021-03-16 12:12:43

---
title: Composing functions in JavaScript
published: true
description: Taking functional programming approach to pipeline functions in JavaScript
tags: javascript, composition, functional, ramda
//cover_image: https://direct_url_to_image.jpg
---

Recently I read an article about using [Pipeline style in JavaScript](https://betterprogramming.pub/whats-a-pipeline-style-in-javascript-2084b66133f0).
An article described how to pipe functions together so data flows through all of them.
What I've missed in this article was functional programming taste.
Let's go a step further and add some FP flavor.

## Using pipelines in \*nix shell

Imagine *nix command line where we want to find all `index.js` files in a certain directory. When we will get a list of files we would like to count them.
Let's say we got source code placed inside `src/`. 
It's a trivial example but explains how we can use pipe commands (using `|`) in *nix shell to pass data through them.

To achieve what we want we have to execute the following command:

```
tree src/ | grep index.js | wc -l
```

Where:

- `tree` recursively lists directories (in the example I limit it to `src/` directory)
- `grep` is used to filter results (single line) with provided pattern - we want only lines that contain `index.js`
- `wc` (word count) returns newline count, word count, and byte count. Used with `-l` returns only the first value so the number of times our `index.js` was found

Example output from the above command can be any number, in my case, it's `26`.

What we see here is how data is passed from one command to another. The first command works on input data and returns data to the second one. And so on until we reach the end - then data returned by the last command is displayed.

## Using pipelines in JavaScript

We can achieve a similar thing in JavaScript. 
First, let's build a function that serves for certain purpose mimicking shell commands.

```javascript
// node's execSync allows us to execute shell command
const { execSync } = require("child_process"); 

// readFiles = String => Buffer
const readFiles = (path = "") => execSync(`tree ${path}`);
// bufferToString = Buffer => String
const bufferToString = buffer => buffer.toString();
// makeFilesList = String => Array
const makeFilesList = files => files.split("\n");
// isIndex = String => Boolean
const isIndexFile = file => file.indexOf("index.js") > 0;
// findIndexFiles = Array => Array
const findIndexFiles = files => files.filter(isIndexFile);
// countIndexFiles = Array => Number
const countIndexFiles = files => files.length;
```

Let's see what we got so far:

- `readFiles()` function executes `tree` command for provided `path` or in location where our JS file was executed. Function returns Buffer
- `bufferToString()` function converts Buffer data to String
- `makeFilesList()` function converts received string to array making each line of text separate array element
- `isIndexFile()` function check if provided text contains `index.js`
- `findIndexFiles()` function filters array and returns new array with only entries containing `index.js` (internally uses `isIndexFile()` function)
- `countIndexFiles()` function simply counts elements in provided array

Now we got all the pieces to do our JavaScript implementation. But how to do that? 
We will use _function composition_ and the key here is using _unary functions_.

## Function composition

**Unary functions** are functions that receive _exactly one parameter_.

Since they accept one argument we can connect them creating a new function. This technique is called **function composition**. Then data returned by one function is used as an input for another one.

We can use `compose` function that you can find in the popular functional programming library [Ramda](https://ramdajs.com/docs/#compose). 
Let's see how to do that...

```javascript
// returns function that accepts path parameter passed to readFiles()
const countIndexFiles = R.compose(
  countIndexFiles,
  findIndexFiles,
  makeFilesList,
  bufferToString,
  readFiles);

const countIndexes = countIndexFiles("src/");

console.log(`Number of index.js files found: ${countIndexes}`);
```

Note: we can actually compose functions without even using `compose` function (but I think this is less readable):

```javascript
const countIndexes = countIndexFiles(findIndexFiles(makeFilesList(bufferToString(readFiles("src/")))));

console.log(`Number of index.js files found: ${countIndexes}`);
```

As you can see function composition allows us to join functions and don't worry about handling data between them. Here's what we have to do without using composition:

```javascript
const filesBuf = readFiles("src/");
const filesStr = bufferToString(filesBuf);
const filesList = makeFilesList(filesStr);
const indexFiles = findIndexFiles(filesList);
const countIndexes = countIndexFiles(indexFiles);
```

## Compose vs pipe

As you might have noticed when using `compose` we need to pass functions in the opposite order they are used (bottom-to-top). 
It's easier to read them in top-to-bottom order. That's the place where `pipe` comes in. It does the same `compose` does but accepts functions in reverse order.

```javascript
// even though not takes functions list in reverse order 
// it still accepts path parameter passed to readFiles()
const countIndexFiles = R.pipe(
  readFiles,
  bufferToString,
  makeFilesList,
  findIndexFiles,
  countIndexFiles);

const countIndexes = countIndexFiles("src/");

console.log(`Number of index.js files found: ${countIndexes}`); // same result as before
```

It depends just on us which one method we will use - `compose` or `pipe`.
Try to use one you (and your colleagues) feel better with.

### Bonus: use full power Ramda gives you

We can use other Ramda methods to even more shorten our code. This is because all Ramda functions are **curried** by default and come with the "data last" style.
This means we can configure them before providing data. For example `R.split` creates new function that splits text by provided separator. But it waits for a text to be passed:

```javascript
const ipAddress = "127.0.0.1";
const ipAddressParts = R.split("."); // -> function accepting string

console.log(ipAddressParts(ipAddress)); // -> [ '127', '0', '0', '1' ]
```

Enough theory 👨‍🎓
Let's see how our code could look like in final (more FP style) form:


```javascript
const { execSync } = require("child_process");
const R = require("ramda");

// readFiles = String => Buffer
const readFiles = (path = "") => execSync(`tree ${path}`);
// bufferToString = Buffer => String
const bufferToString = buffer => buffer.toString();
// isIndex = String => Boolean
const isIndexFile = file => file.indexOf("index.js") > 0;

const countIndexFiles = R.pipe(
  readFiles,
  bufferToString,
  R.split("\n"),
  R.filter(isIndexFile),
  R.length);

const countIndexes = countIndexFiles("src/");

console.log(`Number of index.js files found: ${countIndexes}`);
```