web-dev-qa-db-fra.com

L'injection de dépendance du pauvre est-elle un bon moyen d'introduire la testabilité dans une application héritée?

Au cours de la dernière année, j'ai créé un nouveau système utilisant l'injection de dépendance et un conteneur IOC. Cela m'a beaucoup appris sur l'ID!

Cependant, même après avoir appris les concepts et les modèles appropriés, je considère qu'il est difficile de découpler le code et d'introduire un conteneur IOC dans une application héritée. L'application est suffisamment grande au point qu'une véritable implémentation serait écrasante. Même si la valeur était comprise et le temps accordé. Qui a accordé du temps pour quelque chose comme ça ??

Le but est bien sûr d'amener les tests unitaires à la logique métier!
Logique métier étroitement liée aux appels de base de données empêchant les tests.

J'ai lu les articles et je comprends les dangers de l'injection de dépendance du pauvre comme décrit dans cet article de Los Techies . Je comprends que cela ne vraiment découpler rien.
Je comprends que cela peut impliquer une refactorisation à l'échelle du système car les implémentations nécessitent de nouvelles dépendances. Je n'envisagerais pas de l'utiliser sur un nouveau projet avec une certaine taille.

Question: Est-il correct d'utiliser l'ID de Poor Man pour introduire la testabilité d'une application héritée et de lancer le bal?

De plus, l'utilisation de l'ID du pauvre comme approche populaire de l'injection de dépendance véritable est-elle un moyen précieux d'éduquer sur le besoin et les avantages du principe?

Pouvez-vous refactoriser une méthode qui a une dépendance d'appel de base de données et abstraire cet appel derrière une interface? Le simple fait d'avoir cette abstraction rendrait cette méthode testable car une implémentation simulée pourrait être transmise via une surcharge du constructeur.

Plus tard, une fois l'effort gagné, le projet pourrait être mis à jour pour implémenter un conteneur IOC et les constructeurs seraient là-bas pour prendre les abstractions.

14
Airn5475

La critique de Poor Man's Injection dans NerdDinner a moins à voir avec l'utilisation ou non d'un conteneur DI qu'elle ne le fait configurer correctement vos classes.

Dans l'article, ils déclarent que

public class SearchController : Controller {

    IDinnerRepository dinnerRepository;

    public SearchController() : this(new DinnerRepository()) { }

    public SearchController(IDinnerRepository repository) {
        dinnerRepository = repository;
    }
}

est incorrect car, bien que le premier constructeur fournisse un mécanisme de secours pratique pour construire la classe, il crée également une dépendance étroitement liée à DinnerRepository.

Le bon remède n'est bien sûr pas, comme le suggère Los Techies, d'ajouter un conteneur DI, mais plutôt de supprimer le constructeur incriminé.

public class SearchController : Controller 
{
    IDinnerRepository dinnerRepository;

    public SearchController(IDinnerRepository repository) {
        dinnerRepository = repository;
    }
}

La classe restante a maintenant ses dépendances correctement inversées. Vous êtes maintenant libre d'injecter ces dépendances comme bon vous semble.

25
Robert Harvey

Vous faites ici une fausse hypothèse sur ce qu'est "l'ID du pauvre".

La création d'une classe qui a un constructeur de "raccourci" qui crée toujours le couplage n'est pas DI du pauvre.

Ne pas utiliser de conteneur et créer toutes les injections et mappages manuellement, est DI du pauvre.

Le terme "DI du pauvre" sonne comme une mauvaise chose à faire. Pour cette raison, le terme "DI pur" est encouragé de nos jours car il semble plus positif et décrit en fait plus précisément le processus.

Non seulement il est tout à fait correct d'utiliser DI pauvre/pur pour introduire DI dans une application existante, mais c'est aussi un moyen valable d'utiliser DI pour de nombreuses nouvelles applications. Et comme vous le dites, tout le monde devrait utiliser la DI pure sur au moins un projet pour vraiment comprendre comment la DI fonctionne, avant de gérer la responsabilité de la "magie" d'un conteneur IoC.

15
David Arno

Les changements de Paragidm dans les anciennes équipes/bases de code sont extrêmement risqués:

Chaque fois que vous proposez "améliorations" au code hérité et qu'il y a "héritage" programmeurs de l'équipe, vous dites simplement à tout le monde que "ils ont mal fait" et vous devenez L'ennemi pour le reste de votre/leur temps avec l'entreprise.

L'utilisation d'un DI Framework comme un marteau pour briser tous les clous rendra le code hérité pire que meilleur dans tous les cas. C'est aussi extrêmement risqué personnellement.

Même dans les cas les plus limités, comme juste pour qu'il puisse être utilisé dans des cas de test, ces codes de test seront "non standard" et "étrangers" qui, au mieux, seront simplement marqués @Ignore quand ils cassent ou pire se plaignent constamment des programmeurs hérités avec le plus d'influence auprès de la direction et sont réécrits "correctement" avec tout ce "temps perdu sur les tests unitaires" imputé uniquement à vous.

Introduire un framework DI, ou même le concept de "Pure DI" dans une application métier, encore moins une énorme base de code héritée sans la gestion, l'équipe et surtout le parrainage du développeur principal ne seront que le glas de la mort pour vous socialement et politiquement au sein de l'équipe/entreprise. Faire des choses comme ça est extrêmement risqué et peut être le pire des suicides politiques.

L'injection de dépendance est une solution à la recherche d'un problème.

Tout langage avec des constructeurs par définition utilise l'injection de dépendance par convention si vous savez ce que vous faites et comprenez comment utiliser correctement un constructeur, c'est juste une bonne conception.

L'injection de dépendance n'est utile qu'à petites doses pour une gamme très étroite de choses:

  • Les choses qui changent beaucoup ou qui ont beaucoup d'implémentations alternatives qui sont liées statiquement.

    • Les pilotes JDBC en sont un parfait exemple.
    • Clients HTTP qui peuvent varier d'une plateforme à l'autre.
    • Systèmes de journalisation qui varient selon la plate-forme.
  • Systèmes de plugins qui ont des plugins configurables qui peuvent être définis dans le code de configuration de votre framework et découverts automatiquement au démarrage et chargés/rechargés dynamiquement pendant l'exécution du programme.

1
user7519