Module nécessitant une injection de dépendance en Javascript

24

Ces jours-ci, une question m'est venue à l'esprit:

La façon dont nous Javascript va-t-elle à l'encontre de presque tout ce qui est considéré comme une bonne pratique dans le développement de logiciels traditionnel?

J'ai une série de questions / observations liées à cette déclaration, mais afin de respecter le format de StackExchange, il sera préférable de les diviser en différentes questions.

Module nécessitant

Le code Javascript standard ressemble de nos jours à:

const someModule = require('./someModule')

module.exports = function doSomethingWithRequest() {
  // do stuff
  someModule.someFunc()
  // do other stuff
}

Les avantages

  • Encapsulation: le module fonctionne de manière autonome et sait tout ce dont il a besoin pour exécuter ses fonctions.
  • En tant que coloraire, il est plus facile pour les clients d'utiliser le module.

Désavantages

  • Mauvaise testabilité: ceci est standard lorsque vous n'utilisez pas DI, mais dans les langages dynamiques, tels que Javscript, il peut être contourné * par des modules comme mockeryou rewire.
  • Il viole certainement le DIP - à ne pas confondre avec l'injection de dépendance. - puisque je ne peux importer que des modules concrets.
  • Il viole probablement l' OCP - par exemple, imaginez que j'ai un module de journal qui écrit dans le système de fichiers (via le fsmodule). Si je veux étendre ce module de journalisation pour l'envoyer au réseau, ce serait très difficile.

* Cela peut fonctionner avec les modules CommonJS ou même AMD car ils sont implémentés principalement dans le pays utilisateur. Cependant, je ne sais pas comment cela pourrait être possible avec la importsyntaxe ES6 .

Injection de dépendance

En utilisant l'injection de dépendance, ce serait plus comme:

module.exports = function doSomethingWithRequest(someModule) {
  // do stuff
  someModule.someFunc()
  // do other stuff
}

Les avantages

  • Testabilité accrue: il est désormais plus facile de stub / mock someModule, même en utilisant la syntaxe ES6.
  • Il est possible d'honorer le DIP: pas nécessairement cependant, car le module client peut toujours être programmé pour la mise en œuvre et non une interface.

Désavantages

  • Encapsulation brisée: la principale question qui reste est:

    Ok, alors qui va créer / exiger les dépendances?

  • Faire cela dans chaque client du module semble très mouillé .
  • Cela nécessiterait probablement que j'utilise un conteneur DI afin d'être réalisable dans un projet réel.

Donc, la vraie question ici est:

Pourquoi les développeurs Javascript ont tendance à tendre vers la première approche?

Est-ce juste "la manière Javascript"?

J'écris moi-même du code comme ça la plupart du temps. J'ai eu ma part de configuration de test à l'aide de bibliothèques de simulation, mais cela m'a toujours semblé mal de le faire.

Suis-je en train de manquer quelque chose?

Henrique Barcelos
la source
En tant que gars .Net qui s'est récemment intéressé aux NodeJ, j'ai également eu du mal avec cela. J'ai trouvé que les dépendances de correction de singe avec Proxyquire (un peu comme ReWire) étaient correctes à des fins de test, mais parfois vous avez légitimement besoin de plusieurs implémentations d'une dépendance ...
RubberDuck

Réponses:

6

Je suis principalement un programmeur PHP, mais j'ai été en contact avec 4 équipes JavaScript au cours de la dernière année.

En tant que programmeur orienté objet, le principe de l'injection de dépendances semble être le meilleur moyen, mais quelques développeurs JS m'ont dit le contraire. JS est un tout autre monde.

Parce que JavaScript vous permet de patcher tout et n'importe quoi à l'aide de techniques très simples, les développeurs JavaScript ont appris à adapter une technologie différente sur la façon de créer des applications JavaScript à plus grande échelle. La plupart d'entre eux sont construits sous forme d'ensembles de modules autonomes, qui exposent la fonctionnalité par le biais d'exportations publiques, masquant les éléments internes du module pour ne pas permettre aux autres de réécrire les fonctions sur lesquelles vous vous appuyez.

L'approche habituelle consiste généralement à aller jusqu'à ne pas exposer un constructeur, mais à exposer la construction d'un objet à l'aide d'un wrapper d'usine - pour la même raison: si vous donnez à quelqu'un accès à un objet, il peut instancier directement sont autorisés à changer quoi que ce soit.

En tirant parti de la conception modulaire, vous refusez aux autres de jouer avec les fonctions que vous prévoyez de travailler, mais vous avez toujours la possibilité de tester vos modules - via l'API publique du fichier requis, l'API que vous avez créée.

Andy
la source