Git Product home page Git Product logo

escape-from-callback-mountain's Introduction

Escape from Callback Mountain!

Build Status

Refactoring NodeJS/JavaScript - a 2017 Guide

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.

Side-by-side Comparison: Callbacks & Promises

image

The technique I demonstrate is what I call the Functional River pattern. Your input/parameters/data is the water, and the code forms the riverbed. More or less. It is an async+sync version of the Collection Pipeline pattern.

To the Haskell pros out there, before you flame me for not defining 'monad', this is meant to be a more welcoming place. So forgive me if I skip the overblown theory & jargon.

Functional River Goals/Benefits:

  • Higher level logic implemented with multiple smaller single-purpose functions, assembled to read like a story.
  • Reduce bugs by eliminating ad hoc logic. (e.g. one-off transformations, untested validation)
  • Use same interface for both synchronous & asynchronous code. (promise.then(value => alert(value)))
  • Prefer immutable, stateless code as essential building blocks.
  • Less elaborate, modular code is naturally more reusable.
  • Easier to move logic around - rebundle simple functions as needed to create new higher-order functions.
  • Increased testability - eliminate hidden logic.
  • Substantially faster code readability - versus methods which muddles the important parts, and further hides ad hoc error/glue code.

Note: Relies on ideas from Lisp to SmallTalk - adapted to a JavaScript world. Additionally, I happen to use Bluebird Promises. Apologies to Promise Resistance Leader Brian Leroux. For alternative patterns please read my more detailed article demonstrating 4 Functional JavaScript Techniques (with Examples)

Have feedback, fixes or questions? Please create issues or PRs. Or just complain at me on twitter @justsml.

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


Example Task:

Authentication Method

Here's a rough visualization of our function: image

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

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

  • Less ad hoc code results in:
    • More uniform code between different teams & developers,
    • Performance tooling & refactoring is an appreciably better experience,
    • More certainty about code correctness,
    • Higher code reuse.
  • 100% Unit Testability
    • Unit tests uniquely prove you found, understand, AND resolved a given bug,
    • Faster bug resolution process,
  • Flatter code hierarchy == less filler to remember

Cons

  • Performance. I've run some micro-benchmarks - it's not awesome. However, 3 important things:
    1. It's not meaningfully slower in real world applications.
    2. If it is necessary, performance analysis & tuning is a much improved experience. Smaller functions make it easier to see where slow code lurks - especially if you profile unit tests.
    3. As more people adopt these patterns, things will improve. V8/Chrome has been impressively fast at optimizing for emerging patterns.
  • Debugging can be more difficult. Though I have updated my dev tricks to debug this style of code, even without the confort of Bluebird's error handling. I'll add more sample scripts for this later.
  • Something new to learn. Deal with it, you're a developer.
  • If you have an existing project with lots of code, the unfortunate reality is: Refactors Suck.
  • EventEmitter- & Stream-based code is not improved much, if at all, using this technique. Look into RxJS
    • Ongoing experiments include simple closures, extend Promise with EventEmitter, or using Bluebird's .bind to inject variable state into the Promise chain. (I know, "ugh side-effects, gross." PRs welcome.)

This area of Functional JS patterns, and consenus around it's best practices has plenty room to go.

Concerns

Some really smart people out there have pointed out potential problems with over-modularization.

image

While true of most coding patterns, an overly-done flat & modular JS Project can feel more disorganized over time. 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 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.


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


Please Star this project ❤️


Wiki Contents


Credits & Inspiration

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

escape-from-callback-mountain's People

Contributors

justsml avatar dannyfritz avatar

Watchers

James Cloos avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.