La gestion des dépendances est un gros problème dans la POO pour les deux raisons suivantes:
- Le couplage étroit des données et du code.
- Utilisation omniprésente des effets secondaires.
La plupart des programmeurs OO considèrent que le couplage étroit des données et du code est tout à fait bénéfique, mais cela a un coût. La gestion du flux de données à travers les couches est une partie inévitable de la programmation dans n'importe quel paradigme. Le couplage de vos données et de votre code ajoute le problème supplémentaire que si vous souhaitez utiliser une fonction à un certain point, vous devez trouver un moyen pour que son objet atteigne ce point.
L'utilisation d'effets secondaires crée des difficultés similaires. Si vous utilisez un effet secondaire pour certaines fonctionnalités, mais que vous souhaitez pouvoir échanger son implémentation, vous n'avez pratiquement pas d'autre choix que d'injecter cette dépendance.
Prenons comme exemple un programme de spammeur qui gratte les pages Web pour les adresses e-mail puis les envoie par e-mail. Si vous avez un état d'esprit DI, en ce moment, vous pensez aux services que vous encapsulerez derrière les interfaces, et quels services seront injectés où. Je vais laisser cette conception comme un exercice pour le lecteur. Si vous avez un état d'esprit FP, en ce moment, vous pensez aux entrées et sorties pour la couche de fonctions la plus basse, comme:
- Saisissez une adresse de page Web, affichez le texte de cette page.
- Saisissez le texte d'une page, affichez une liste de liens à partir de cette page.
- Saisissez le texte d'une page, affichez une liste d'adresses e-mail sur cette page.
- Saisissez une liste d'adresses e-mail, affichez une liste d'adresses e-mail dont les doublons ont été supprimés.
- Saisissez une adresse e-mail, envoyez un e-mail de spam pour cette adresse.
- Saisissez un e-mail de spam, affichez les commandes SMTP pour envoyer cet e-mail.
Lorsque vous pensez en termes d'entrées et de sorties, il n'y a pas de dépendances de fonction, uniquement des dépendances de données. C'est ce qui les rend si faciles à tester unitairement. Le calque suivant vous permet d'alimenter la sortie d'une fonction dans l'entrée de la suivante, et peut facilement échanger les différentes implémentations selon vos besoins.
Dans un sens très réel, la programmation fonctionnelle vous pousse naturellement à toujours inverser vos dépendances de fonction, et donc vous n'avez généralement pas à prendre de mesures spéciales pour le faire après coup. Lorsque vous le faites, des outils tels que des fonctions d'ordre supérieur, des fermetures et des applications partielles facilitent l'exécution avec moins de passe-partout.
Notez que ce ne sont pas les dépendances elles-mêmes qui posent problème. Ce sont les dépendances qui pointent dans le mauvais sens. La couche suivante peut avoir une fonction comme:
processText = spamToSMTP . emailAddressToSpam . removeEmailDups . textToEmailAddresses
Il est parfaitement normal que cette couche ait des dépendances codées en dur comme celle-ci, car son seul but est de coller les fonctions de la couche inférieure ensemble. L'échange d'une implémentation est aussi simple que de créer une composition différente:
processTextFancy = spamToSMTP . emailAddressToFancySpam . removeEmailDups . textToEmailAddresses
Cette recomposition facile est rendue possible par un manque d'effets secondaires. Les fonctions de la couche inférieure sont complètement indépendantes les unes des autres. La couche suivante peut choisir celle qui processText
est réellement utilisée en fonction d'une configuration utilisateur:
actuallyUsedProcessText = if (config == "Fancy") then processTextFancy else processText
Encore une fois, ce n'est pas un problème car toutes les dépendances pointent dans un sens. Nous n'avons pas besoin d'inverser certaines dépendances pour les faire pointer toutes de la même manière, car les fonctions pures nous y obligent déjà.
Notez que vous pouvez rendre cela beaucoup plus couplé en passant config
par la couche la plus basse au lieu de la vérifier en haut. FP ne vous empêche pas de faire cela, mais cela a tendance à le rendre beaucoup plus ennuyeux si vous essayez.