A Functional Pipeline Example
Tags: javascript, functional, pipeline, intermediate
Published: 2020-09-02 18:25:36


## Method Chaining (MC) vs Functional Pipelining (FP)

![functional pipeline example](https://dev-to-uploads.s3.amazonaws.com/i/ilssnfm2qq4sh03dqbk9.png)


# Notes on MC vs FP
Notice that the two approaches are very similar. If you can grok the MC, then you can also grok the FP approach

### MC cons:
- can only use the built-in methods.
- cannot control the abstraction level.
- very object-oriented (intermingles data and behavior).
- weakly-typed.

### FP pros:
- full control to use any custom function.
- you control the abstraction level. Notice in this example the FP funcs are are still domain agnostic but perform higher level, commonly reused behaviors. Notice 4 of the FP funcs are abstracted perfectly, because they take no args. There are 2 funcs that take args so I could abstract those from `filterNotStartsWith` to `excludeComments`. Also from `replaceByRegex` to `replaceNewlineWithDoubleAmpersand`. I haven't done this because they are not very popular behaviors, but the FP pipeline would read even more **fluent**.
- separates data and behavior by using free (non-class bound) static funcs.
- runtime-enforced strongly-typed.


## Source Code Examples

pipeBase
```js
/*
@func
a non-typed pipe
- that can dynamically handle sync or async funcs

@usage
this is a util func of the typed pipe funcs

@param {...Function} fns - one or more funcs spread to an arr of funcs
@return {(v: *) => *} - the first func in the pipe takes in any data, and the last func returns any data
*/
export const pipeBase = (...fns) => v => {
  return fns.reduce((r, fn) => { // r = result or output of fn call
    if (isPromise(r)) {
      return r.then(fn);
    }
    return fn(r);
  }, v);
};
```

pipeStr
```js
/**
@func
a strongly-typed pipe that is invoked with a supplied str

@clientcode
const p1 = pipeStr(f1, f2, f3);
p1("");

@param {...Function} fns
@return {(s: string) => *}
*/
export const pipeStr = (...fns) => s => throwIfNotStr(s) || pipeBase(...fns)(s);
```


1.
```js
/**
@func
split by \n chars

@notes
use forceSingleNewline() beforehand if str contains multiple blank lines in a row

@param {string} s
@return {string[]}
*/
export const splitByNewline = s => s.trim().split("\n");

```


2.
```js
/**
@func
trim each str in arr of strs

@notes
if the elem is a str, trim it
- otherwise leave it as is

@param {string[]} a
@return {string[]}
*/
export const mapTrim = a => a.map(s => isStr(s) ? s.trim() : s);
```


3.
```js
/**
@func
only remove empty str elems in an arr

@notes
applies trim() before comparing

@param {string[]} a
@return {string[]} arr with empty elems removed
*/
export const filterOutEmptyStrs = a => a.filter(s => isNotEmptyStr(s));
```

4.
```js
/**
@func complement
from the supplied arr, remove the elems that start with the supplied str chunk

@param {string} chunk
@return {(a: string[]) => string[]}
*/
export const filterNotStartsWith = chunk => a => fil(s => !s.startsWith(chunk), a);
```

5.
```js
/**
@func
make a single str where each elem is placed on a new line

@param {string[]} a
@return {string} concatentated
*/
export const joinByNewLine = a => a.join("\n");
```


6.
```js
/*
@func
replace a substring with another substring in a haystack of text

@cons
use the g flag to remove all matches
- otherwise it will just replace the first and return
case sensitive

@param {RegExp} n needleRegex
@param {string} r replacement
@return {(h: string) => string} // haystack -> a copy of the haystack with the needles replaced with the new values
*/
export const replaceByRegex = (n, r) => h => h.replace(n, r);

```


final FP pipeline usage
```js
/**
@func util
supply a template string of bash commands
- and return the logged output

@param {string} a line-separated chain of bash commands
@return {string} chain of commands separated by &&
*/
export const chainCmds = pipeStr(
  splitByNewline,
  mapTrim,
  filterOutEmptyStrs,
  filterNotStartsWith("//"), //exclude comments
  joinByNewLine,
  replaceByRegex(/\n/g, " && "), lStr,
);
```



an example feature usage
```js
lBashExecChain(`
pwd
git config -l --local
git show-branch
git status
git stash list
git stash --include-untracked
git pull
git stash pop
lerna bootstrap
`);
```

## Final Notes

- This is not a fully working feature example because all the code is not present in this post. The focus of this post is to show a functional approach to software design.

- There are some naming conventions that are very intuitive. I've listed common abbreviations used in JavaScript here:
https://dev.to/functional_js/popular-abbreviations-in-software-development-4ikk


## P.S.

If you have any questions, let me know.