An intro to Functional Programming in JavaScript~ (and React and/or Vue)

Fig 1.0 — Dimensions
Fig 1.1 — Some kind of inter-dimensional movement
Fig 1.3 — Waterslides with data as humans

fn(name) = (name + bold)

It’s kind of important that we stop for a moment and look directly at that = symbol. It means, at the moment in time we observed both sides of the equation at once, they were equal to each-other with infinite accuracy and precision. Notice the word at in my statement. I am describing a co-ordinate in space-time. I don’t really need to care where you are while you’re observing the equation. I can tell you with 100% certainty that they are equal at your current location at the moment in time you just looked at the =.

Fig 1.4 — The slope of the tangent is 0 at the vertex
const isBold = (name.bold === true);
const phoneNumberOfDavid = '555-123-4576';if (isBold) await call(phoneNumberOfDavid);
import FibonacciAdapter from 'some-outlet-right-now';const makeLeafOnBranch = (data) => {
const scalingFactor = 1.618;
return FibbonacciAdapter({
action: 'ADD-LEAF',
someRatio: scalingFactor,
someData: data,
});
};
const drawLeaf = data => makeLeafOnBranch(data);const drawBranch = drawLeaf => drawLeaf();drawBranch(data => drawLeaf(data));

Keep this in mind: the penalty of the wrong abstraction is worse than the penalty of no abstraction.

The above quote that I observed once at some moment in time before now is telling us that it’s easier to untangle one function than it is to untangle 45 functions that do pieces of what the original function did. It’s the same but different. 1+1 leads to 2, or 2 leads to 1+1. Your task is to figure out the most concise code that conveys the perfect amount of meaning to make it look like poetry and mathematics had a baby in some data flow with respect to time. The poetry is in the labels, and the math is in the movement with respect to time and the relationships between labels.

const d = a => (a + b + c);
function d(a) {
const startPlusCrap = a;
startPlusCrap += b; startPlusCrap += c; return startPlusCrap;
}

DATA FLOW

Functional Reactive Programming is all about thinking in data flows over time.

In Functional Reactive Programming, you are some data and you can go anywhere one hop at a time — from node to node — from a start to a finish. You can chain these hops, but it’s a special way of thinking. Something is generally always listening and then acting or doing and then triggering. Stuff can listen to events and trigger actions. This whole time, the state integrity must be maintained. Functional Reactive Programming emerges as a way to apply patterns to this kind of stuff. Changes are very formal so no one gets screwed up. Remember — order of operations.

Fig 1.4 — Functional Reactive Programming (FRP)

Directed Acyclic Graph (DAG)

In the React world, you will eventually encounter this thing called a Directed Acyclic Graph. You barely know me, but I love studying nodes and relationships between them. I eat pieces of nodes for breakfast. My digestive system is a unidirectional flow over time.

Fig 1.5 — Directed Acyclic Graph (DAG)
render(
<App />,
document.getElementById('root'),
)

Flow

Data can flow both ways. It may first flow unidirectionally from server to client, and then it may flow back unidirectionally. It’s like a one way street beside a one way street. Some call it a road. Chaos occurs immediately if this flow rule is broken. You wouldn’t send data to the server through your GraphQL get query, or would you? No, you wouldn’t. Data flow is best served unidirectionally. It’s simpler to reason about.

The internet is a series of tubes, and so is your app.

PART ONE — THE IMPORTANT THEORIES

Patterns and Anti-patterns

Study of JavaScript and React brings mentions of anti-patterns into the mix. When a normal human sees things, they have normal knee-jerk reactions. An anti-pattern is a response to something that is a normal but sub-optimal response. Everything comes back to patterns, flow patterns.

Fig 2.0 — Bob Nyegers: he paints nice logic in your neighbourhood.

In JavaScript, things flow the best over time immutably and unidirectionally. Why? Because of live references and dynamic typing.

  • Objects contain data.
  • Functions instigate movement of data.
Fig 2.1 — Mousetrap Board Game
  • Notice how pushing a ball down the stairs is a one-way action as part of an event.
  • Notice how Mousetrap is a series of contraptions and a one-way system. If you ignore every point in time individually at first, you can study the system as if it were in continuous motion (ie: Calculus and deterministic transformation formulas).
  • Notice how each contraption always produces the same result unless you get violent or introduce an unexpected flow over time, like turbulence. Try putting a large fan beside the game and see what happens when you mutate the air pressure values around each contraption.

Deterministic means, “if you put in the same input, you get the same output 100% of the time.”

If I always roll a ball down the stairs, and it always destroys my sister’s Mousetrap game, my mom may not appreciate that pattern, but at least I can tell her it is deterministic.

Live References

In JavaScript, Functions are first-class citizens. What does that even mean? It means that in JavaScript, everything is an Object. Functions are Objects too, so that’s at least confusing, but Functions are a first-class citizen because all JavaScript does is start executing the first line of code and then stops when it’s done. Remember the order of operations? JavaScript just executes functions as fast as it can one at a time.

Fig 2.2 — Pass-by-reference vs. pass-by-value
const sandwich = {
flavour: { confirmed: 'pretty good' },
isTasty: getFlavour(sandwich.flavour),
}
Fig 2.3 — Look at this as if it were a single object that doubles as a function too

Where this becomes dangerous is real-time pass-by-reference analysis.

Remember how the start of a function and the end of the function is the most important time and place. If the end of a function is relying on a live reference, the reference must be correct — or you’re screwed. It’s perfectly valid to take special precautions in your own code to ensure this data is always correct. In my books, you are safe to get excited about trying to protect your data (ie: state: the state of the data at a moment in time when observed).

Immutability

Immutability is great because you can relax once you set data in place. You don’t have to worry about data or sandwich flavours getting unexpectedly mangled if someone else happens to observe that single source of truth around the same time.

Immutability can free you from trying to predict the future and recount the past. Who cares where we came from or how we got here. We care where we are going next and how we are going to get there.

If you want some mental imagery, imagine traveling lean vs. hoarding. Remember, we are traveling unidirectionally. We have to supply everything without being wasteful. Data waste translates into extra CPU, memory, and bandwidth usage. It can also create leaky abstractions by leaking out too much information. Be careful out there.

const config = {
title: 'Sandwiches can produce good flavour',
author: 'Alice Bobson',
timestamp: 128364096092,
}
const renderArticle (config) => {
return (
<div>
<h1>{config.title}</h1>
<h3>{config.author}</h3>
<span>Created: {Date(config.timestamp)}</span>
</div>
)
}
renderArticle(config)
const config = {
title: 'Sandwiches can produce good flavour',
author: 'Alice Bobson',
timestamp: 128364096092,
content: 'Today, we added one key to an object, and we found that
our code was easy to test, extend, and maintain.',
}
const renderArticle (config) => {
return (
<div>
<h1>{config.title}</h1>
<h3>{config.author}</h3>
<span>Created: {Date(config.timestamp)}</span>
<div>{config.content}</div>
</div>
)
}
renderArticle(config)
  • Our function expected to be supplied everything it needed
  • We supplied our function with everything it needed
  • We stored everything in a config Object
  • The function performed an action, deterministically
  • Our pattern is very robust
  1. copy the Object to a new one,
  2. stop referring to the old Object,
  3. start using the new Object from that moment on.
const user = {
firstName: 'Alice',
lastName: 'Bobson',
}
// We just learned Alice's age. We need to add it.const userWithAge = {
...user,
age: 1337,
}
return userWithAge
const fn = x => ({ x })

Remember, the shortest, most concise possible code isn’t always the simplest to understand.

Just because something is more concise or more simple looking does not mean it is simpler to reason about or quicker to understand. Have you ever seen code that someone told you is the fastest possible way? Does it look like cryptic garbage that makes your brain hurt immediately? It’s like sending a zip file into someone’s brain and forcing them to unpack it before they can understand.

Fig 2.4 — Ronco Food Dehydrator

Garbage Collection

To understand this deeply, we can re-visit our immutable pen and paper example. If you replaced the old paper with the new paper but you never got rid of the old paper, your home would quickly look like this photo:

Fig 2.5 — Depiction of the JavaScript heap without Garbage Collection

In JavaScript, the execution context is usually a function being executed.

const garbage = () => {
// when you stop referring to me, I will be gone
return 'cool'
}
const generateGarbage = () => {
const createReference = garbage()
if (createReference === 'cool') {
// perform some work
}
// as soon as we arrive here during code execution,
// JavaScript unloads `garbage` from memory
return 'that is very cool'
}

I’ve hidden a secret puzzle in the bolded words above.

Now, we are about to push into some more advanced territory. Imagine it this way, we are coming into this new material here, and I’ve supplied you with everything I think you need to properly reason about this.

Function Composition

This is the meat and potatoes of functional programming, and it’s a secret layer behind reactive programming. After all, you can’t use map, reduce, and filter if you can’t chain them onto the end of a collection of data (ie: an Array) that’s flowing somewhere.

A deterministic function produces the same output when it is given the same input.

In programming, there is a thing called referential transparency. It means, if you swap out a function for its computed counterpart, the application would still function identically. You can’t have referential transparency without a deterministic function.

const ok = 33const getNumber = num => num // returns 33 if you input 33const correctAnswer = 1 + getNumber(ok) + 7console.log(correctAnswer) // returns 41
Fig 3.0 — Function composition
f(g())
  • push
  • put
  • set
  • do
  • write
  • pull
  • get
  • bring
  • collect
  • read
const locationX = 'http://www.com/profile.html'const config = {
name: getProfile('Reader McGee').name,
start: '1337.html',
end: () => next(locationX),
error: () => next('404.html'),
}
// destructuring not used in order to show correlations
const goToLocation = (config) => {
if (config.start !== '1337.html') {
return config.error()
}
return config.end()
}
goToLocation(config)
  1. Where is it going?
  2. What is being returned?
if (today === 'monday') use('multiplication')
if (today === 'friday') use('division')
  1. The function is being supplied what it needs
  2. The data being supplied is dynamic, but the operations in the function are static
  3. The data types are static. We are relying on this fact.
  4. The function returns something
const users = getNumberOfUsers()
Fig 3.1 — Gottfried Wilhelm Leibniz

My brain, Gottfried! WTF were you doing in the year 1700 AD?? Is this real life??

It used to take me two pages to answer one question in Calculus. Keep that in mind when you realize these guys were from 1700 AD.

Fig 3.2 — Luckily, I don’t need to do this in JavaScript

Conclusion

Alright, now we are familiar with composing deterministic functions while immutably flowing one way.

--

--

I prefer to work near ES6+, node.js, microservices, Neo4j, React, React Native; I compose functions and avoid classes unless private state is desired.

Love podcasts or audiobooks? Learn on the go with our new app.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Adam Mackintosh

Adam Mackintosh

I prefer to work near ES6+, node.js, microservices, Neo4j, React, React Native; I compose functions and avoid classes unless private state is desired.