Comment tirer parti des paramètres par défaut de JavaScript pour l’injection de dépendances

De nos jours, il est assez courant d’utiliser Dependency Injection, qui permet de coupler les modules d’un projet de manière lâche. Mais à mesure que les projets deviennent de plus en plus complexes, nous devons contrôler un nombre astronomique de dépendances.

Pour contourner ce problème, nous nous tournons souvent vers les conteneurs d’injection de dépendance. Mais est-ce nécessaire dans toutes les situations?

Dans cet article, je vais expliquer en quoi les paramètres par défaut de JavaScript peuvent nous aider à résoudre ce problème. Pour ce faire, nous allons implémenter une application simple dans Node.JS. Il aura les fonctionnalités de création et de lecture des informations des utilisateurs selon trois approches différentes:

  1. Sans injection de dépendance
  2. Avec injection de dépendance
  3. Avec injection de dépendance et paramètres par défaut

Structure de projet

Nous allons structurer notre exemple de projet par caractéristique (au fait, ne structurez pas vos fichiers en fonction de rôles). Donc, la structure ressemblera à ceci:

├── utilisateurs /
├── utilisateurs-repository.js
├── utilisateurs.js
├── utilisateurs.spec.js
├── index.js
├── app.js

Remarque: Pour les besoins de cet exemple, nous allons enregistrer les informations des utilisateurs en mémoire.

Sans injection de dépendance

En analysant le code précédent, nous vérifions que nous sommes limités par l’instruction: const usersRepo = require ('./ users-repository') chez les utilisateurs. Le module utilisateurs, avec cette approche, est fortement couplé au référentiel utilisateurs.

Cela nous limite à utiliser l'implémentation d'un autre référentiel sans modifier l'instruction require. Lorsque le besoin est utilisé, nous créons une dépendance statique au module requis. Avec cela, nous ne pouvons pas utiliser un autre référentiel dans le modèle d'application en plus de celui défini par le module users-repository.

De plus, nous sommes également liés au référentiel users-dans le spec-users en raison de la dépendance statique mentionnée précédemment. Ces tests unitaires sont destinés à tester uniquement le module utilisateur et rien de plus. Imaginez si le référentiel était connecté à une base de données externe. Il faudrait interagir avec la base de données pour pouvoir tester.

Avec injection de dépendance

Avec Dependency Injection, le module users n'est plus couplé au module users-repository.

La principale différence avec l’approche précédente est que nous n’avons plus la dépendance statique dans le module utilisateurs (nous n’avons pas l’instruction suivante: const usersRepo = require ('./ users-repository')). Au lieu de cela, le module utilisateur exporte une fonction fabrique avec un paramètre pour le référentiel. Cela nous permet de transmettre n'importe quel référentiel au module à un niveau supérieur.

Une alternative à la fonction factory est d’ajouter un paramètre pour l’argument du référentiel dans les fonctions create et read. Mais si les deux fonctions dépendent du même référentiel, nous pouvons les encapsuler avec une fonction et tirer parti des fermetures de JavaScript.

Maintenant, dans le module d'application, nous avons la liberté de définir le référentiel que nous voulons utiliser. Regardez aussi les tests unitaires. Nous pouvons maintenant tester le module utilisateur sans se soucier du référentiel. Il suffit de s'en moquer!

Cependant, soyons honnêtes: à quelle fréquence définissons-nous des dépendances qui changent tout au long du cycle de vie de l’application? Normalement, nous essayons d'éviter les dépendances statiques car cela complique les tests. Mais maintenant, comme nous voulons la testabilité, nous devons passer une instance du référentiel au module utilisateur à chaque fois que nous voulons l’utiliser.

Vous savez ce qui serait vraiment génial? Si nous pouvions utiliser le module sans avoir à lui donner un référentiel à chaque fois. Nous pouvons le faire en JavaScript avec les paramètres par défaut.

Avec injection de dépendance et paramètres par défaut

Avec cette stratégie, en plus de l’injection de dépendance que nous avons vue dans l’approche précédente, le paramètre défini dans la fonction de fabrique exportée par le module utilisateurs est désormais un paramètre par défaut: usersRepo = defaultUsersRepo.

Avec le paramètre default, si nous ne passons pas d’argument, la valeur du paramètre default est utilisée par la fonction. Sinon, la valeur de l’argument est utilisée. Cela revient à utiliser la technique d’injection de dépendance définie dans l’approche précédente.

Maintenant, nous avons à nouveau la dépendance statique dans le module utilisateurs. Cependant, cette dépendance statique ne sert qu'à définir la valeur utilisée dans le paramètre par défaut si aucun argument n'est transmis à la fonction factory.

Avec cette approche, nous ne sommes pas obligés de passer le référentiel dans le module d'application lorsque vous avez besoin du module utilisateurs. Néanmoins, nous pouvons le faire. Nous pouvons également vérifier que les tests unitaires peuvent continuer à utiliser le référentiel fictif, car nous pouvons le transmettre au lieu d’utiliser la valeur du paramètre par défaut.

Conclusion

Les paramètres par défaut sont une fonctionnalité JavaScript simple, mais puissante. Avec eux, nous pouvons mettre en œuvre de meilleures solutions.

N'hésitez pas à me demander n'importe quoi.

Plus de ressources

Dépôt GitHub avec les exemples: ici.

Mattias Petter Johansson a une excellente vidéo d’explication de Dependency Injection:

Si vous avez apprécié cet article, donnez-moi s'il vous plaît des applaudissements afin que plus de gens le voient. Je vous remercie!