Pourquoi les programmeurs évitent la fonction reduce
En bref
- L'auteur constate qu'en revue de code, les développeurs acceptent volontiers map et filter, mais reçoivent régulièrement des critiques sur l'usage de reduce.
- Les raisons invoquées : inconsistance entre langages, argument accumulator placé différemment selon les syntaxes, performances O(n²) avec les chaînes en Python, et manque de familiarité.
- Le phénomène semble moins prononcé en langages fonctionnels comme Clojure, où reduce devient naturel.
Ce que dit la source
L'auteur rapporte une observation personnelle : dans ses revues de code, reduce reçoit systématiquement des critiques de lisibilité, tandis que map et filter passent sans commentaire. Il propose plusieurs hypothèses : reduce est plus difficile à lire, moins familier, potentiellement moins performant, et moins élégant dans les langages courants (JavaScript, Python, Swift), contrairement à Clojure où il n'a pas constaté cette résistance.
- Les syntaxes de reduce varient drastiquement entre langages : `reduce(initial_acc, callback)` vs `reduce(callback, initial_acc)`, ce qui crée une confusion mémorielle systématique, contrairement aux signatures stables de map et filter.
- Python 2 à 3 : reduce a été dégradé de builtin à functools.reduce() après un incident de performance où une ligne de code utilisant reduce causait des rendus de 30+ secondes dans l'outil de review Google, due à la concaténation de chaînes en O(n²).
- Reduce force le raisonnement global sur l'accumulation et ses états intermédiaires, tandis que map et filter permettent un raisonnement local sur chaque élément isolé.
- Le principe du moindre pouvoir (Principle of Least Power) suggère que reduce ne devrait s'utiliser que quand les abstractions plus simples (map, filter, boucles explicites) ne suffisent pas, pour éviter les mauvaises réinterprétations de patterns.
- Incohérence cognitive : reduce peut retourner n'importe quel type (pas une réduction au sens strict), tandis que map promet une liste, filter promet un sous-ensemble ; cette imprécision sémantique ralentit la compréhension.
- En langages fonctionnels avec attentes théoriques (Clojure, Scala, Haskell), reduce devient naturel car les développeurs maîtrisent la pensée fonctionnelle et la théorie des catégories, ce qui n'est pas le cas en Python ou JavaScript.
Dans les commentaires
Débat nuancé et bien étayé, loin du consensus. Plusieurs commentateurs défendent reduce quand il est justifié, d'autres plaident pour des alternatives ; l'accord porte surtout sur le diagnostic que reduce est un outil puissant mais pas toujours la meilleure abstraction.
- Un commentateur (the_other) défend clairement reduce en production : il apprécie l'encapsulation du traitement dans une fonction nommée et la sécurité contre les mutations externes, contraste qu'il illustre par un refus d'embauche qui lui reprochait son usage de reduce.
- Le débat distingue reduce (résultat du même type que les éléments) et fold (résultat de type différent), montrant que la critique porte surtout sur fold en tant que primitive de bas niveau, ce que les langages avec combinateurs fonctionnels (traverses monadiques, schémas de récursion) pourraient éviter.
- Consensus sur la cause pédagogique : les développeurs formés en langages impératifs ne reçoivent pas d'enseignement en programmation fonctionnelle ou théorie des catégories, d'où une familiarité insuffisante avec les primitives réduire/fold même dans les langages qui les offrent.
- Un cas concret (union de DataFrames Spark) où reduce émerge comme plus lisible qu'une boucle explicite avec déballage, mais l'importation depuis functools en Python reste une friction psychologique.
Alternatives citées : Aucun outil ou fonction alternative nommément critiqué dans les commentaires fournis. Le débat porte sur le choix entre reduce et des primitives plus simples (map, filter, boucles explicites) ou des abstractions plus riches (iterateurs, schémas de récursion en FP), sans mention de bibliothèques tierces.
Notre lecture
L'observation de l'auteur est valide : reduce souffre d'un vrai handicap cognitif dans les écosystèmes impératifs, causé par l'inconsistance syntaxique entre langages, la charge mentale de l'accumulation, et l'absence de formation fonctionnelle chez les pairs. Ce n'est pas un débat sur la performance (Python l'a documenté en 2006), mais sur la clarté de l'intention. Pour les équipes concernées : chercher d'abord des abstractions plus haut niveau (sum, groupBy, etc.), réserver reduce aux cas où l'opération dépasse vraiment map/filter, et si c'est inévitable, l'extraire dans une fonction nommée explicite plutôt que d'en faire un objet d'évaluation. Pas d'action imédiate pour une DSI, mais un bon rappel sur le biais vers le lisible plutôt que le puissant.