Well done. I thoroughly enjoyed your post. Function pipes are awesome, but they do have drawbacks. While they make the flow or steps of the algorithm obvious they also obfuscate some of its workings. Bob Martin, citing Kent Beck, in his Clean Code book, has written that "one of the more powerful ways to make a program readable is to break the calculations up into intermediate values that are held in variables with meaningful names." So while pipes make for elegant and succinct code, it could be argued that your very first imperative style code example is more "readable".
I think that in comparison, function pipes can also be harder to debug.
I'm not trying to make a case against using pipes but merely to point out that there are some tradeoffs in using them. In any case, I liked your implementation and enjoyed reading your well written article.
I completely agree with your assertion about readability. The same code can be broken down and refactored in many ways to satisfy different requirements. In this article, my design goal was to come up with a way of expressing a hierarchical view of operations so that you first see the forest, then the trees. You do sacrifice the ease of debugging in this case, but that could be mitigated by inserting various tap functions into the composition that would serve as observation or debugging points.
Another tool that could help alleviate the problem of intermediate results and aid understaing is to leverage a type system like TypeScript, which provides annotations for well-typed functions. This allows you to observe the shape of objects by hovering over different parts of the composition. I was thinking of writing a follow-up article that would illustrate how that would cover the gap with this approach.
I wouldn't use this approach to teach clean code to a beginner, though, there's too much to unpack here. Simple imperative code, as in the first example, would have been the example I would have used, and there are more important principles to cover first.
For further actions, you may consider blocking this person and/or reporting abuse
We're a place where coders share, stay up-to-date and grow their careers.
Well done. I thoroughly enjoyed your post. Function pipes are awesome, but they do have drawbacks. While they make the flow or steps of the algorithm obvious they also obfuscate some of its workings. Bob Martin, citing Kent Beck, in his Clean Code book, has written that "one of the more powerful ways to make a program readable is to break the calculations up into intermediate values that are held in variables with meaningful names." So while pipes make for elegant and succinct code, it could be argued that your very first imperative style code example is more "readable".
I think that in comparison, function pipes can also be harder to debug.
I'm not trying to make a case against using pipes but merely to point out that there are some tradeoffs in using them. In any case, I liked your implementation and enjoyed reading your well written article.
Thank you, those are good points you raise. ☺️
I completely agree with your assertion about readability. The same code can be broken down and refactored in many ways to satisfy different requirements. In this article, my design goal was to come up with a way of expressing a hierarchical view of operations so that you first see the forest, then the trees. You do sacrifice the ease of debugging in this case, but that could be mitigated by inserting various
tap
functions into the composition that would serve as observation or debugging points.Another tool that could help alleviate the problem of intermediate results and aid understaing is to leverage a type system like TypeScript, which provides annotations for well-typed functions. This allows you to observe the shape of objects by hovering over different parts of the composition. I was thinking of writing a follow-up article that would illustrate how that would cover the gap with this approach.
I wouldn't use this approach to teach clean code to a beginner, though, there's too much to unpack here. Simple imperative code, as in the first example, would have been the example I would have used, and there are more important principles to cover first.