Practical Functional Programming in JavaScript - Side Effects and Purity
Published: 2020-07-02 16:09:55

Edit: This article doesn't do such a great job at communicating what I originally intended, so it [has a revision](https://dev.to/richytong/practical-functional-programming-in-javascript-side-effects-and-purity-revised-420h). I recommend you read the revised version, though I've left this original for historical purposes.

Hello 🌍. You've arrived at the nth installment of my series on functional programming: Practical Functional Programming in JavaScript. On this fine day I will talk about a two-pronged approach to problem solving that makes life easy: **Side Effects and Purity**.

Let's talk about purity. A function is said to be **pure** if it has the following properties:
 * Its return value is the same for the same arguments
 * Its evaluation has no side effects ([source](https://en.wikipedia.org/wiki/Pure_function))

Here's **side effect** [from stackoverflow](https://softwareengineering.stackexchange.com/questions/40297/what-is-a-side-effect):
> A side effect refers simply to the modification of some kind of state - for instance:
 * Changing the value of a variable;
 * Writing some data to disk;
 * Enabling or disabling a button in the User Interface.

Here are some more instances of side effects
 * reading data from a file
 * making a request to a REST API
 * writing to a database
 * reading from a database
 * logging out to console

Basically, all interactions of your function with the world outside its scope are side effects. You have likely been using side effects this whole time. Even the first "hello world" you logged out to the console is a side effect.

In a world full of side effects, your goal as a functional programmer should be to **isolate those side effects to the boundaries of your program**. Purity comes into play when you've isolated the side effects. At its core, **purity is concerned with data flow**, as in how your data transforms from process to process. This is in contrast to side effects, which are only concerned with doing external stuff. The structure of your code changes for the clearer when you separate your programming concerns by side effects and purity.

Here is an impure function `add10`:

```javascript
let numCalls = 0

const add10 = number => {
  console.log('add10 called with', number)
  numCalls += 1
  console.log('add10 called', numCalls, 'times')
  return number + 10
}

add10(10) /*
> add10 called with 10
> add10 called 1 times
> 20
*/
```

`add10` has the side effects of logging out to the console, mutating the variable `numCalls`, and logging out again. The console logs are side effects because they're logging out to the console, which exists in the world outside `add10`. Incrementing `numCalls` is also a side effect because it refers to a variable in the same script but outside the scope of `add10`. `add10` is not pure.

By taking out the console logs and the variable mutation, we can have a pure `add10`.

```javascript
let numCalls = 0

const add10 = number => number + 10

console.log('add10 called with', 10) // > add10 called with 10

numCalls += 1

console.log('add10 called', numCalls, 'times') // > add10 called 1 times

add10(10) // > 20
```

Ah, sweet purity. Now `add10` is pure, but our side effects are all a mess. We'll need the help of some higher order functional programming functions if we want to clean this up.

You can find these functions in functional programming libraries like [rubico](https://github.com/a-synchronous/rubico) (authored by yours truly), Ramda, or RxJS. If you don't want to use a library, you can implement your own versions of these functions in vanilla JavaScript. For example, you could implement minimal versions of the functions we'll be using, `pipe` and `tap`, like this

```javascript
const pipe = functions => x => {
  let y = x
  for (const f of functions) y = f(y)
  return y
}

const tap = f => x => { f(x); return x }
```

We'll use them to make it easy to think about side effects and purity.

 * **pipe** takes an array of functions and chains them all together, calling the next function with the previous function's output. Since `pipe` creates a flow of data in this way, we can use it to think about **purity**. You can find a runnable example in [pipe's documentation](https://doc.rubico.land/#pipe).
 * **tap** takes a single function and makes it always return whatever input it was passed. When you use `tap` on a function, you're basically saying "don't care about the return from this function, just call the function with input and give me back my input". Super useful for **side effects**. You can find a runnable example in [tap's documentation](https://doc.rubico.land/#tap).

Here's a refactor of the first example for purity while accounting for side effects using `pipe` and `tap`. If the example is looking a bit foreign, see my last article on [data last](https://dev.to/richytong/practical-functional-programming-in-javascript-data-last-1gjo).
```javascript
const logCalledWith = number => console.log('add10 called with', number)

let numCalls = 0

const incNumCalls = () => numCalls += 1

const logNumCalls = () => console.log('add10 called', numCalls, 'times')

const add10 = number => number + 10

pipe([
  tap(logCalledWith), // > add10 called with 10
  tap(incNumCalls),
  tap(logNumCalls), // > add10 called 1 times
  add10,
])(10) // > 20
```

We've isolated the console log and variable mutation side effects to the boundaries of our program by defining them in their own functions `logCalledWith`, `incNumCalls`, and `logNumCalls`. We've also kept our pure `add10` function from before. The final program is a composition of side effecting functions and a pure function, with clear separation of concerns. With `pipe`, we can see the flow of data. With `tap`, we designate and isolate our side effects. That's organized.

![thumbs-up-chuck.gif](https://raw.githubusercontent.com/a-synchronous/assets/master/gifs/thumbs-up-chuck.gif)

Life is easy when you approach problems through side effects and purity. I'll leave you today with a rule of thumb: _if you need to console log, use tap_.

Next time, I'll dive deeper into data transformation with `map`, `filter`, and `reduce`. Thanks for reading! You can find the rest of the series on rubico's [awesome resources](https://github.com/a-synchronous/rubico#awesome-resources). See you next time for _Practical Functional Programming in JavaScript - Intro to Transformation_