Byte-sized functional programming: Composition over inheritance for functions, too
A popular refrain in object-oriented code is to favor object composition over inheritance. It offers more flexibility, less overhead, and ends up being easier to reason about. The same concept applies to functions, too!
A common pattern is to have a function that does some work and then calls another function, which does some work and calls another function, and so on. The problem is that the first function then cannot be used or tested without the entire chain of other functions it calls. This is the function equivalent of "inheritance."
Instead, we can compose functions, that is, pipe them together. Instead, take the output of the first function and pass it to the second, then take the second's output and pass it to the third, etc. That way, each of the functions can be reused, tested, and understood in isolation, then we can stick them together like LEGO blocks to build whatever series of steps we want.
That is, instead of this: