J'ai une grande base de code avec beaucoup de singletons "anti-pattern", des classes utilitaires avec des méthodes statiques et des classes créant leurs propres dépendances à l'aide de new
mots-clés. Cela rend un code très difficile à tester.
Je veux migrer progressivement le code vers le conteneur d'injection de dépendance (dans mon cas, c'est Guice
parce que c'est un GWT
projet). D'après ma compréhension de l'injection de dépendance, c'est tout ou rien. Soit toutes les classes sont gérées par Spring / Guice, soit aucune. Étant donné que la base de code est grande, je ne peux pas transformer le code pendant la nuit. J'ai donc besoin d'un moyen de le faire progressivement.
Le problème est que lorsque je commence avec une classe qui doit être injectée dans d'autres classes, je ne peux pas utiliser de simple @Inject
dans ces classes, car ces classes ne sont pas encore gérées par conteneur. Cela crée donc une longue chaîne jusqu'aux classes "supérieures" qui ne sont injectées nulle part.
La seule façon que je vois est de rendre un Injector
contexte / application globalement disponible via un singleton pour le moment, afin que d'autres classes puissent en obtenir un beans gérés. Mais cela contredit l'idée importante de ne pas révéler le composition root
à l'application.
Une autre approche serait ascendante: pour commencer avec des classes "de haut niveau", incluez-les dans le conteneur d'injection de dépendance et descendez lentement vers des classes "plus petites". Mais alors je dois attendre longtemps, car je peux tester ces classes plus petites qui dépendent toujours des globaux / statiques.
Quelle serait la voie à suivre pour réaliser une telle migration progressive?
PS La question Approches progressives de l'injection de dépendance est similaire dans son titre, mais elle ne répond pas à ma question.
Réponses:
Désolé,
C#
c'est ma langue de choix, je peux lire,Java
mais je ferais probablement disparaître la syntaxe en essayant de l'écrire ... Les mêmes concepts s'appliquent entreC#
etJava
bien, alors j'espère que cela montrera les étapes de la façon dont vous pouvez progressivement déplacer votre base de code pour être plus testable.Donné:
pourrait facilement être refactorisé pour utiliser DI, sans l'utilisation d'un conteneur IOC - et vous pourriez même le décomposer en plusieurs étapes:
(potentiel) Première étape - prendre en compte les dépendances mais pas de modification du code appelant (UI):
Refactor 2 (ou premier refactor si l'implémentation du conteneur IOC et la modification immédiate du code d'appel):
L'étape 2 pourrait techniquement être effectuée seule - mais cela représenterait (potentiellement) beaucoup plus de travail - en fonction du nombre de classes qui "actualisent" actuellement la fonctionnalité que vous recherchez pour DI.
Pensez à suivre l'étape 1 -> étape 2 - vous seriez en mesure de créer des tests unitaires pour
Foo
, indépendamment deBar
. Alors qu'avant le refactor de l'étape 1, il n'était pas facile à réaliser sans utiliser l'implémentation réelle des deux classes. Faire l'étape 1 -> l'étape 2 (plutôt que l'étape 2 immédiatement) permettrait de plus petits changements au fil du temps, et vous aurez déjà votre début d'un harnais de test afin de mieux vous assurer que votre refactoriste a fonctionné sans conséquence.la source
Le concept est le même que vous utilisiez Java, PHP ou même C #. Cette question est assez bien traitée par Gemma Anible dans cette vidéo YouTube:
https://www.youtube.com/watch?v=Jccq_Ti8Lck (PHP, désolé!)
Vous remplacez le code non testable par «façade» (faute d'un meilleur terme) qui appelle un nouveau code testable. Ensuite, vous pouvez progressivement remplacer les anciens appels par les services injectés. Je l'ai fait dans le passé et cela fonctionne assez bien.
la source