Home

Awesome

Escape from Callback Mountain v2.6.0

Build Status

Refactoring JavaScript w/ Functional River Pattern

I am a big fan of Functional Programming and Modular JavaScript. This project's goal is to demonstrate the latest Functional Promise patterns, while taking you through a refactor of real world callback-based NodeJS/JavaScript.

What is the Functional River pattern?

It is an async & sync version of the Collection Pipeline pattern.

Your parameters/data represents the water, and functions form the riverbed.


Roughly speaking, my definition of pipeline is a sequential series of chained functions where arguments line up with return values (using Array methods, Promises, or similar). Key to my adaptaion is using named functions.

This ultimately results in your code reading like a step-by-step story.


Compare these 2 examples:

// ❌ Non-Functional River / Collection Pipeline Code ❌
const formatScores = scores => scores
  .map(x => x * 2.0)
  .map(x = x.toFixed(2))

// ✅ Functional River Code ✅
const formatScores = scores => scores
  .map(double)
  .map(formatNumber)

Let's look at a more complex example, with asynchronous requirements added in the mix...

Comparison: Callbacks vs. Functional River

See both Before and After examples below.

Before

Node-style Callbacks w/ Nesting

Note: This is intentionally reasonable callback code. Even if nested. Not trying a straw-man attack.

callback-mountain-before

After

'Functional River' Pattern

callback-mountain-after

<!-- #### Functional River Highlights ![Functional River Highlights](https://user-images.githubusercontent.com/397632/38474143-e96bf632-3b57-11e8-8589-cbe3b3782d1a.gif) -->

The technique I demonstrate hopefully illustrates the Functional River pattern:

Functional River Goals/Benefits:

Note: The Functional River Relies on ideas from Lisp to SmallTalk - adapted to a JavaScript world. Apologies to Promise Resistance Leader Brian Leroux. For alternative patterns please read my more detailed article demonstrating 4 JavaScript Composition Techniques (with Examples)

Have feedback, fixes or questions? Please create issues or Pull Requests. Or DM me at twitter @justsml.

If you feel this subject has already been exhauted, please see my post Beating a dead horse?

Key Steps

  1. Step 1: Break Up The Big Functions - read the code: PR #2: Flatten Functions
  2. Step 2: DRYer Code - read the code: PR #3: DRYer Code
  3. Step 3: Cleanup Code - read the code: PR #5: Post Cleanup

Pros & Cons

Pros

Cons

Pattern Showdown

View Callback Comparison

Summary

It's perhaps true that an overly-done flat & modular JS Project can feel more disorganized over time. New practices & approaches must be explored (from monorepos, to breaking up modules when-needed to meet org/dev/deployment needs).

Project and code discipline is just as important as it's always been. Also, the community is still developing consensus around Functional JS patterns, immutability and overall project organization.

When done right, one of Functional River's greatest strengths is the ability to relocate & rearrange modules with low risk. If this still feels risky, your modules are probably still too entangled (coupled).


Ultimately my goal is to better understand & advance Modular + Functional JS patterns. Hopefully I can interest some of the skeptics along the way :crossed_fingers:


Please Star this project ❤️


Wiki Contents

Wiki Main


Credits & Inspiration

I highly recommend reading (or watching) every single link here.


v2.0 Released

Escape from Callback Mountain Key Updates

  1. README now more focused on the Functional River pattern.
    • Counter-examples are still included in ./src, just not featured on README.
  2. There's an updated production-ready library Functional Promises which grew out of the feedback & research from this Project.