Overview
Martin Fowler has the feeling that loops are an outdated concept. He already mentioned them as an issue in his first edition of “Refactoring: Improving the design of existing code” book, although there were no better alternatives at that time. [1] Nowadays, languages provide an alternative - pipelines. Fowler, in his 2018 book (third edition), suggests that anachronistic loops should be replaced by pipeline operations such as filter, map, or reduce [2].
Indeed, loops can sometimes be hard to read and error-prone. This might be unconfirmed, but I doubt the existence of a programmer who has never had an IndexError at least once before. The recommended approach would be to avoid explicit iterator loops and use the forEach or for-in/for-of-like loop that takes care of the indexing, or Stream pipes. Still, one should consider whether he is not about to write Clever Code and check if there is already a built-in function that will take care of the desired operation.
I would abstain from specifying all the loops as code smells. Loops have always been and probably are still going to be a fundamental part of programming. Modern languages offer very tidy approaches to loops and even things like a List Comprehension in Haskell or Python. It is the indexation part might be the main problem. Of course, so are long loops or loops with side effects, but these are just a part of Long Method or side effects code smells.
However, it is worth taking what is good from functional languages (such as streams or the immutability of the data) and implement those as widely as possible and conveniently, to increase the reliability of the application.
Causation
It is impossible to easily overwrite the information given in the old books or video tutorials, which was pretty standard due to the lack of any other alternatives. People have learned that type of looping and may not even suspect that there are alternatives until they find them. Similarly, developers who come from older languages, which do not yet offer such facilities, can use explicit iteration habitually.
Problems
In contrast to pipelines, loops don't provide declarative readability of what is precisely being processed.
Example
1const examples = ['foo', 'bar', 'baz'];
2for (let idx = 0; idx < examples.length; idx++) {
3 console.log(examples[idx]);
4}1const examples = ['foo', 'bar', 'baz'];
2let bar_in_examples = false;
3for (let idx = 0; idx < examples.length; idx++) {
4 if (examples[idx] == 'bar') {
5 bar_in_examples = true;
6 }
7}
8console.log(bar_in_examples); // trueRefactoring
- Replace Loop with Pipeline
- Replace Loop with built-in
Sources
- ORIGIN
- PARENTAGE2018 · ISBN 978-0201485677