Le seul anti-modèle d'injection de dépendance légitime que je connaisse est le modèle Service Locator , qui est un anti-modèle lorsqu'un cadre DI est utilisé pour cela.
Tous les autres anti-modèles dits DI dont j'ai entendu parler, ici ou ailleurs, ne sont que des cas légèrement plus spécifiques d'anti-modèles généraux de conception OO / logiciel. Par exemple:
La sur-injection du constructeur est une violation du principe de responsabilité unique . Trop d'arguments constructeurs indiquent trop de dépendances; trop de dépendances indique que la classe essaie d'en faire trop. Habituellement, cette erreur est en corrélation avec d'autres odeurs de code, telles que des noms de classe inhabituellement longs ou ambigus ("manager"). Les outils d'analyse statique peuvent facilement détecter un couplage afférent / efférent excessif.
L'injection de données, par opposition au comportement, est un sous-type de l' anti-modèle poltergeist , le «geist dans ce cas étant le conteneur. Si une classe doit connaître la date et l'heure actuelles, vous n'injectez pas a DateTime
, qui est une donnée; à la place, vous injectez une abstraction sur l'horloge système (j'appelle généralement la mienne ISystemClock
, bien que je pense qu'il y en a une plus générale dans le projet SystemWrappers ). Ce n'est pas seulement correct pour DI; il est absolument essentiel pour la testabilité, afin que vous puissiez tester des fonctions variant dans le temps sans avoir à les attendre.
Déclarer chaque cycle de vie comme Singleton est, pour moi, un parfait exemple de programmation culte du fret et, dans une moindre mesure, du " cloaque d'objet ", familièrement appelé . J'ai vu plus d'abus de singleton que je ne m'en souviens, et très peu d'entre eux impliquent DI.
Une autre erreur courante concerne les types d'interfaces spécifiques à l'implémentation (avec des noms étranges comme IOracleRepository
) faits juste pour pouvoir l'enregistrer dans le conteneur. Ceci est en soi une violation du principe d'inversion de dépendance (juste parce que c'est une interface, ne signifie pas qu'elle est vraiment abstraite) et inclut souvent également un ballonnement d'interface qui viole le principe de ségrégation d'interface .
La dernière erreur que je vois habituellement est la "dépendance facultative", ce qu'ils ont fait dans NerdDinner . En d'autres termes, il existe un constructeur qui accepte l'injection de dépendances, mais aussi un autre constructeur qui utilise une implémentation "par défaut". Cela viole également le DIP et a tendance à entraîner également des violations de LSP , car les développeurs, au fil du temps, commencent à faire des hypothèses sur l'implémentation par défaut et / ou à démarrer de nouvelles instances à l'aide du constructeur par défaut.
Comme le dit le vieil adage, vous pouvez écrire FORTRAN dans n'importe quelle langue . L' injection de dépendance n'est pas une balle d'argent qui empêche les développeurs de vissage leur gestion de la dépendance, mais il ne prévenir un certain nombre d'erreurs / anti-modèles communs:
...etc.
De toute évidence, vous ne voulez pas concevoir un framework dépendant d'une implémentation de conteneur IoC spécifique , comme Unity ou AutoFac. C'est, encore une fois, violer le DIP. Mais si vous pensez même à faire quelque chose comme ça, vous devez déjà avoir fait plusieurs erreurs de conception, car l'injection de dépendance est une technique de gestion des dépendances à usage général et n'est pas liée au concept d'un conteneur IoC.
Tout peut construire un arbre de dépendance; c'est peut-être un conteneur IoC, c'est peut-être un test unitaire avec un tas de simulations, c'est peut-être un pilote de test fournissant des données factices. Votre framework ne devrait pas s'en soucier, et la plupart des frameworks que j'ai vus ne s'en soucient pas, mais ils utilisent toujours massivement l'injection de dépendance afin qu'elle puisse être facilement intégrée dans le conteneur IoC de l'utilisateur final de choix.
DI n'est pas sorcier. Essayez simplement d'éviter new
et static
sauf lorsqu'il existe une raison impérieuse de les utiliser, comme une méthode utilitaire qui n'a pas de dépendances externes, ou une classe utilitaire qui ne pourrait avoir aucun but en dehors du cadre (les enveloppes d'interopérabilité et les clés de dictionnaire sont des exemples courants de cette).
De nombreux problèmes avec les frameworks IoC surviennent lorsque les développeurs apprennent à les utiliser pour la première fois, et au lieu de changer la façon dont ils gèrent les dépendances et les abstractions pour s'adapter au modèle IoC, essayez plutôt de manipuler le conteneur IoC pour répondre aux attentes de leurs ancien style de codage, qui impliquerait souvent un couplage élevé et une faible cohésion. Un mauvais code est un mauvais code, qu'il utilise ou non des techniques DI.