Functional Programming in JavaScript and React (Part Two)

PART TWO — THE IMPORTANT FACTORS

The way I would like you to approach these next parts is to imagine the type of things you should and must care about in order to be an extreme baller logic spewing machine. I will get you primed up now. State. Everything revolves around state. The millisecond your state gets mangled, you are toast.

State integrity is the most important thing in every app.

Imagine you had a calculator that forgot which number it was at or it accidentally returned the wrong number. It would pretty much be the absolute worst calculator ever made, unless it was TrollCalculator.exe. In that case, it could be among the best at what it was designed for.

  1. An app can be viewed as an Object, at a moment in time when observed
  2. An app probably requires state
  3. An app can respond to any event we specify
  4. An app can initiate or facilitate any action

Reactive Programming

Before we get to the meat of these styles, we must talk about functional programming and reactive programming.

It’s a matter of describing ancestors first so that children make sense. We need the context awareness.

Note: Adobe Photoshop has context awareness with its Healing Brush. This means you can drag the brush through an area, and Photoshop calculates optimal blending of adjacent pixels.

Function as an Object (FaaO)

I just made up that acronym. It’s not important. When I say Object, I mean a thing or node that could be connected to another node. JavaScript happens to excel when it comes to objects that can efficiently double as functions.

const executable = () => {
executable.hello = 'world'
return executable
}
// LOOK AT IT
console.log(executable)
// => { [Function] hello: 'world' }
// EXECUTE IT
console.log(executable())
// => { [Function] hello: 'world' }
const function = () => {}const object = {}const array = []

Encapsulation

?

Sole Responsibility

Note how I didn’t say single responsibility. This can be confusing for people. A function should be responsible for approximately one idea. An idea could consist of more than one thing. A Function called getUserData() sounds like it is only doing one thing. Introducing another ideas, may sprinkle a bit of chaos into the idea of getting user data. A function may also processUserData()which is still doing approximately one idea, but there is room to do more as long as it’s related to processing user data. Ignore any subpar naming conventions. Naming stuff is hard.

Top 3 Symbols

Our above FaaO app is a pretty simple app. You can look at it or execute it, but there are two key takeaways: Objects have properties, meaning you can look at them and observe facts at the moment of observation. Objects can also have methods, meaning they can perform actions or respond to events. In JavaScript, you can go ahead and execute that Object.

  1. State
  2. Actions
  3. Events

State

Apps generally require state management, but what is state:

  • memory
  • knowledge of current moment

I would go as far as to say that state is the single most important aspect of every app.

State is the one thing that must be kept accurate and precise. Therefore, we need an official process that ensures state can maintain integrity. This is your first lesson about reactive programming. If changes to state are involved, there must be a strict process to handle propagation of changes.

  1. Immutability
  2. One-way flow

Scary Stuff

One-way flow of information is great because it keeps interactions simple. One-way is simpler than two-way. This helps us reason about what the app is doing. It allows us to manage state in one direction. Things can be modeled with a start and a finish.

Fig ?.? — Arrive alive

Actions

Apps can perform not only actions but also operations. Operations are the big brother of actions. For example, I could calculate that 1+1=2 but if I never tell anyone, there will be no action. When I talk about actions, I generally mean containers that are responsible for performing work — functions. An action usually has a start and finish. Functions also usually do.

If you want to perform an action, you probably want to execute a function.

Events

If actions are analogous to talking, events are analogous to listening. If you are listening, you may be recording changes to state as they occur. Therefore, events probably trigger state updates. Actions can trigger state updates as well, however.

const birthdayParty = {
startTime: 5,
endTime: undefined,
}
const birthdayParty = {
startTime: 5,
endTime: undefined,
location: { ...address },
}
const driveToLocation = async (location) => {
return handleDriveCar(location)
}
driveToLocation(birthdayParty)
.then(badExperience => forEveryone(badExperience))
birthdayParty.location = { ...differentAddress }
  1. Shared mutable state existed
  2. Asynchronous behavior existed
  3. A mutation action occurred in parallel with another action
  1. Event emitters and observers
  2. Semaphores
  3. Callbacks (continuation-passing style)
  1. State
  2. State changes
Dinosaurs beginning to respond poorly to change

Radical Quote: An app’s response to change is the most important factor towards maintaining state integrity.

This is where the reactive part of Functional Reactive Programming comes from. The program is reacting to changes and not screwing anything up, preferably in crazy asynchronous conditions. This makes perfect sense in the real world where wall feeds get updated while scrolling and where cancel buttons are pressed during actions and events. State is the crown jewel, and it must be protected like an infant human must be in the real world.

  • Traveling one way is good
  • Traveling downhill at the most efficient pace without pooping our pants is good

Streams

I don’t want to talk about streams too much, but they are important to mention during reactive programming conversations. What is a stream literally? Ignoring the velocity of flow, it is a channel that water is flowing through.

Do you know what else can flow through channels?

Data.

  • Security concerns
  • Data loss
  • Bugs

Where & When

When doing asynchronous programming, the more simple and flat the list of steps, the less likely you are to encounter a problem. Your goal is to setup functions so that you don’t have to care about anything besides when and where to call them. They handle everything correctly based on what you supply them. If you examine React using this magnifying glass, you will see.

Formal Change Process

I know some of you are already thinking: this rascal is about to talk about Redux. Well, I go news for you — that is correct. People don’t use Redux because they love adding brutal to understand addons into an app. They use Redux because it proposes a series of mechanisms that guarantee the app never gets confused about a state change.

Network Calls

I’ve intentionally stayed mostly away from talking about things like network calls and asynchronous disk I/O because I only want to pile so many hundred new ideas into your brain at once. When you make a network call for some data, the server could respond with different output even though you gave it the same input.

Concurrency

Stacked on top of that, concurrency brings with it indeterminism. Why? Race conditions. If you always fire off three guns at the same time, there is no guarantee that all three bullets will hit the ground at the same time. Remember, wind, pressure gradient force, small birds — things you cannot account for may become a significant factor and result in unreliable results.

Pass-by-Reference & Garbage Collection

In JavaScript, two things are critically important to understand if you and I hope to write apps that care about proper memory use. These two things are related in that one helps with storing in memory and the other helps with cleaning the memory out.

Pass-By-Reference

This can be explained in one quick animated GIF:

Fig ?.? — Live reference

Garbage Collection

If you are maintaining references to things, you can quickly observe them, but you can also forget to release them from memory. This is garbage collection. When a function is done executing and there are no more references to that function, your app forgets about that function and dumps it out of the memory. It gets garbage collected. The City comes and takes that garbage away.

Functional Programming

Functional programming is essentially about breaking your program into manageable chunks but not just any chunks. A good chunk is probably based on an event or an action.

  • before actions or events
  • during actions or events
  • after actions or events

3 Phases of a Function

  1. Detection and Collection Phase
  2. Packaging Phase
  3. Delivering Phase
  • Power: Ability to complete a large body of work quickly
  • Torque: Ability to quickly start or stop work
  • Short term memory: Knowledge of context and working parameters
  • Long term memory: May be used alongside work or memory

Continuation-Passing Style (CPS)

This is a style of programming that is cleverly disguised as callbacks in JavaScript. The shortest possible definition involves a function waiting until it gets a signal to continue to the next function. You’ve seen it before. You’ve heard of callback hell. You’ve also seen it be consistently useful when you want some code to let some other code know when it is ready.

Monad

[define]

  • Pure functions
  • Side effects
  • Referential transparency
  • Immutability

Pure Functions

Side Effects

Immutability

I’m going to tell you right now, composing functions does not work in asynchronous environments when state is unpredictably changing. State cannot be assumed correct.

A series of inter-dependent functions is a chain of functions.

The real star of functional programming is composition. You take function that does one thing and call it from another function. Then, you call that function from a third function. Now, you are composing functions.

Composition

Composing functions isn’t a new thing. Without fact checking, I think people have been doing it for thousands of years in Mathematics. You may recall from math class:

  • f of x
  • g of x
  • f composed with g of x
Fig 5.1 — Function Composition
f(g(x))
  1. execute g(x)
  2. then, take the result of that
  3. then, pass that into f()

When writing functionally, you:

  1. declare how your program should respond to various inputs (ie: define what actions the functions do),
  2. declare configuration settings that define what those inputs are (ie: define state at moments in time),
  3. declare when to trigger these functions (ie: define the events your program reacts to).
const person = {
firstName: 'Suzy',
lastName: 'Kawasaki',
}
const config = {
host: '127.0.0.1',
port: 1337,
user: person,
}
const connectToDB = (config) => {
const connection = getDriver(config.host, config.port)
return connection
}

Functional + Reactive = Modular Components

The 3 tenants of modular components:

  • self-contained
  • accepts a Config Object
  • external Side Effects are officially managed
  1. single source of truth store/repository for standalone components
  2. pull packages into any project via NPM or equivalent

Self Contained

Components should be self-sufficient. I would go as far as to say they should be 100% self-sustaining as much as is reasonable. If it’s not self-sustaining, it’s dependent on something. The best components will handle all duties related to a specific event. This works because the component takes ownership of all sub-events and actions related to this event. If another component needs to push or pull anything, there should be an official process on both sides to handle it. Control is specifically delegated.

Config Objects

True to Functional Reactive ways of thinking, a config object should be pushed into the component. The component should require this object. The component uses it to drive all of its functions. Config Objects provide the necessary nutrition for optimal performance. They also allow the component to be used in any project simply by declaring parameters.

const config = {
one: 'value',
two: { complexData },
three: () => functions()
}
const Component = (config) => {
if (!config) throw new Error('Because reasons.')
// config can be used as desired
const { one, two, three } = config
return {
one,
two,
three,
}
}

External Side Effects

Simple, the root level of the component should not modify any external state. There is a permission boundary. These potential side effects occur when the component freely mutates parent state. There should be no reaching into other files and grabbing things. With respect to the Config Object, any required data should probably be pushed into the component. The component could also pull the necessary data in. This would be like a hook that allows the component to ask for state.

const Component = (config) => {
const { onEvent, text, css } = config
return (
<button onClick={onEvent} style={css}>
{text}
</button>
)
}

JSX

I won’t leave you empty handed about JSX after reading all that. My thoughts can be summarized by this quote from Mark Dalgleish:

import { render } from 'react-dom'

Recommended Next Steps

I recommend studying Neo4j because of relationships between data compared to relational databases. It is fundamentally different and a profound upgrade in some ways. I am a great fan of the unstructured data that fits nicely into algorithms and reveals vectors and intensity values.

LET THESE PEOPLE KNOW

@mate0day

--

--

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.