it-swarm.com.de

Ist die Abhängigkeitsinjektion von Poor Man eine gute Möglichkeit, die Testbarkeit einer Legacy-Anwendung zu verbessern?

Im vergangenen Jahr habe ich ein neues System mit Dependency Injection und einem IOC Container) erstellt. Dies hat mir viel über DI beigebracht!

Selbst nachdem ich die Konzepte und richtigen Muster gelernt habe, halte ich es für eine Herausforderung, Code zu entkoppeln und einen IOC Container) in eine Legacy-Anwendung einzuführen. Die Anwendung ist groß genug, um eine echte Implementierung zu ermöglichen wäre überwältigend. Selbst wenn der Wert verstanden und die Zeit gewährt würde. Wer hat Zeit für so etwas gewährt?

Das Ziel ist natürlich, Unit-Tests in die Geschäftslogik einzubringen!
Geschäftslogik, die mit testverhindernden Datenbankaufrufen verflochten ist.

Ich habe die Artikel gelesen und verstehe die Gefahren der Abhängigkeitsinjektion von Poor Man, wie in dieser Artikel von Los Techies beschrieben. Ich verstehe, dass es nicht wirklich irgendetwas entkoppelt.
Ich verstehe, dass es viel systemweites Refactoring beinhalten kann, da Implementierungen neue Abhängigkeiten erfordern. Ich würde nicht in Betracht ziehen, es für ein neues Projekt mit einer beliebigen Größe zu verwenden.

Frage: Ist es in Ordnung, Poor Man's DI zu verwenden, um einzuführen Testbarkeit für eine Legacy-Anwendung zu verwenden und den Ball ins Rollen zu bringen?

Ist die Verwendung von Poor Man's DI als Basisansatz für eine echte Abhängigkeitsinjektion ein wertvoller Weg, um über die Notwendigkeit und den Nutzen des Prinzips aufzuklären?

Können Sie eine Methode mit einer Datenbankaufrufabhängigkeit und eine Zusammenfassung, die hinter einer Schnittstelle aufgerufen wird, umgestalten? Nur diese Abstraktion würde diese Methode testbar machen, da eine Scheinimplementierung über eine Konstruktorüberladung übergeben werden könnte.

Sobald die Bemühungen die Unterstützer gewinnen, könnte das Projekt aktualisiert werden, um einen IOC Container) zu implementieren, und die Konstruktoren würden da draußen sein, die die Abstraktionen aufnehmen.

14
Airn5475

Die Kritik an Poor Man's Injection in NerdDinner hat weniger damit zu tun, ob Sie einen DI-Container verwenden oder nicht, als mit Richten Sie Ihre Klassen richtig ein.

In dem Artikel heißt es

public class SearchController : Controller {

    IDinnerRepository dinnerRepository;

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

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

ist falsch, da der erste Konstruktor zwar einen praktischen Fallback-Mechanismus zum Erstellen der Klasse bietet, aber auch eine eng gebundene Abhängigkeit von DinnerRepository erzeugt.

Das richtige Mittel ist natürlich nicht, wie Los Techies vorschlägt, einen DI-Container hinzuzufügen, sondern entfernen Sie den fehlerhaften Konstruktor.

public class SearchController : Controller 
{
    IDinnerRepository dinnerRepository;

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

Die Abhängigkeiten der verbleibenden Klasse sind jetzt ordnungsgemäß invertiert. Sie können diese Abhängigkeiten jetzt beliebig einfügen.

25
Robert Harvey

Sie machen hier eine falsche Annahme darüber, was "DI des armen Mannes" ist.

Das Erstellen einer Klasse mit einem "Shortcut" -Konstruktor, der weiterhin eine Kopplung erstellt , ist nicht der DI eines armen Mannes .

Wenn Sie keinen Container verwenden und alle Injektionen und Zuordnungen manuell erstellen, ist der DI des armen Mannes .

Der Begriff "DI des armen Mannes" klingt nach einer schlechten Sache. Aus diesem Grund der Begriff "reines DI" wird heutzutage empfohlen , da er positiver klingt und den Prozess tatsächlich genauer beschreibt.

Es ist nicht nur absolut in Ordnung, DI von armen Männern/reinem DI zu verwenden, um DI in eine vorhandene App einzuführen, sondern es ist auch eine gültige Methode, DI für viele neue Anwendungen zu verwenden. Und wie Sie sagen, sollte jeder bei mindestens einem Projekt reines DI verwenden, um wirklich zu verstehen, wie DI funktioniert, bevor er die Verantwortung auf die "Magie" eines IoC-Containers überträgt.

15
David Arno

Paragidm-Verschiebungen in Legacy-Teams/Codebasen sind äußerst riskant:

Jedes Mal, wenn Sie "Verbesserungen" für Legacy-Code vorschlagen, gibt es "Legacy" Programmierer im Team, Sie sagen nur allen, dass "sie haben es falsch gemacht" und Sie werden Der Feind für den Rest Ihrer Zeit mit der Firma.

Wenn Sie ein DI-Framework als Hammer verwenden, um alle Nägel zu zerschlagen, wird der Legacy-Code in allen Fällen nur schlechter als besser. Es ist auch persönlich sehr riskant.

Selbst in den begrenztesten Fällen, wie nur, damit es in Testfällen verwendet werden kann, werden diese Testfälle nur zu "nicht standardmäßigen" und "fremden" Codes, die bestenfalls nur als @Ignore Markiert werden, wenn sie kaputt gehen oder schlimmer Lassen Sie sich ständig von den älteren Programmierern mit dem größten Einfluss auf das Management beschweren und lassen Sie sich "richtig" neu schreiben, wobei all diese "verschwendete Zeit für Komponententests" nur Ihnen angelastet wird.

Die Einführung eines DI-Frameworks oder sogar des Konzepts von "Pure DI" in eine Branchen-App, geschweige denn eine riesige Legacy-Codebasis ohne das Management, das Team und insbesondere das Sponsoring des Hauptentwicklers, wird nur die Todesursache sein für Sie sozial und politisch im Team/Unternehmen. Solche Dinge zu tun ist extrem riskant und kann im schlimmsten Fall politischer Selbstmord sein.

Dependency Injection ist eine Lösung, die nach einem Problem sucht.

Jede Sprache mit Konstruktoren verwendet per Definition die Abhängigkeitsinjektion gemäß Konvention. Wenn Sie wissen, was Sie tun und verstehen, wie ein Konstruktor richtig verwendet wird, ist dies nur ein gutes Design.

Die Abhängigkeitsinjektion ist nur in kleinen Dosen für einen sehr engen Bereich von Dingen nützlich:

  • Dinge, die sich stark ändern oder viele alternative Implementierungen haben, die statisch gebunden sind.

    • JDBC-Treiber sind ein perfektes Beispiel.
    • HTTP-Clients, die von Plattform zu Plattform variieren können.
    • Protokollierungssysteme, die je nach Plattform variieren.
  • Plugin-Systeme mit konfigurierbaren Plugins, die im Konfigurationscode Ihres Frameworks definiert und beim Start automatisch erkannt und dynamisch geladen/neu geladen werden können, während das Programm ausgeführt wird.

1
user7519