Empfehlungen zur Integration des DI / IoC-Containers in eine vorhandene Anwendung

10

Ich stehe nun vor der Aufgabe, einen IoC-Container (Inversion of Control) in eine vorhandene Anwendung zu integrieren, und suche nach Empfehlungen, wie dies am einfachsten erreicht werden kann, um letztendlich die Kopplung zu reduzieren und dadurch die Testbarkeit zu verbessern. Obwohl ich im Allgemeinen nicht die meisten Klassen als klassifizieren Gott Objekte hat jeder zu viele Aufgaben und versteckte Abhängigkeiten durch Statik, Singletons, und es fehlt ihnen an Schnittstellen.

Hier einige Hintergrundinformationen zu den Herausforderungen, denen Sie sich stellen müssen:

  • Abhängigkeitsinjektion wird selten verwendet
  • Statische Methoden gibt es zuhauf - sowohl als Factory- als auch als Hilfsmethode
  • Singletons sind ziemlich verbreitet
  • Schnittstellen sind bei Verwendung nicht zu detailliert
  • Objekte ziehen häufig nicht benötigte Abhängigkeiten über Basisklassen ein

Unsere Absicht ist es, dass wir beim nächsten Mal, wenn wir Änderungen in einem bestimmten Bereich vornehmen müssen, versuchen, Abhängigkeiten herauszufiltern, die tatsächlich existieren, aber hinter globalen Elementen wie Singletons und Statik verborgen sind.

Ich nehme an, das macht den IoC-Container sekundär zur Einführung der Abhängigkeitsinjektion, aber ich würde erwarten, dass es eine Reihe von Praktiken und Empfehlungen gibt, die befolgt oder in Betracht gezogen werden könnten, um diese Abhängigkeiten aufzubrechen.

Kaleb Pederson
quelle
3
Ich muss jetzt nach dem Grund dafür fragen ... was treibt diese Veränderung an? Wartbarkeit? Skalierbarkeit, da es exponentiell wachsen wird? Entwickler langweilen sich?
Aaron McIver
1
Ich bin erst kürzlich in das Unternehmen eingetreten und versuche, einige "Best Practices" einzuführen. Mein Hauptziel ist es, die Testbarkeit zu verbessern und die Kopplung zu reduzieren. Wir können DI / IoC problemlos für neuen Code verwenden und beabsichtigen nicht, den gesamten vorhandenen Code auf einmal zu ändern. Ich hätte jedoch Empfehlungen, wie wir den vorhandenen Code beim nächsten Mal am besten zum Besseren ändern können Änderungen in diesem Bereich. Bisher habe ich nur Folgendes online gefunden: code.google.com/p/autofac/wiki/ExistingApplications
Kaleb Pederson
3
Es sei denn, es gibt eine große Anzahl automatisierter Unit- / Integrationstests. Wenn Sie die vorhandene Infrastruktur ändern, es sei denn, aus Gründen der Best Practices besteht ein Problem, werden Sie nach Problemen gefragt. Selbst wenn Ihre Unit / Integration-Testsuite solide war, hatte ich immer noch Bedenken.
Aaron McIver
1
@ Aaron Ich hoffe, es klang nicht so, als würden wir es aus Gründen der Best Practices tun. Wir nehmen Änderungen vor, weil es schwierig und langsam ist, mit dem vorhandenen Code zu arbeiten und dies schrittweise zu tun, während wir in diesem bestimmten Bereich arbeiten. Gerne haben wir eine Reihe vernünftiger Integrationstests und einige Komponententests, um Änderungen vorzunehmen.
Kaleb Pederson

Antworten:

8

Um so etwas durchzuziehen, müssen Sie in Schritten arbeiten, jede davon ist nicht trivial, aber sie können erreicht werden. Bevor Sie beginnen, müssen Sie verstehen, dass Sie diesen Prozess nicht beschleunigen können.

  1. Definieren Sie die wichtigsten Subsysteme der Anwendung und eine interfacefür jedes von ihnen. Diese Schnittstelle sollte nur die Methoden definieren, mit denen andere Teile des Systems mit ihm kommunizieren. HINWEIS: Möglicherweise müssen Sie dabei mehr als einen Durchgang machen.
  2. Stellen Sie eine Wrapper-Implementierung dieser Schnittstelle bereit, die an den vorhandenen Code delegiert. Der Zweck dieser Übung ist es zu vermeiden , Umschreiben en Masse , aber den Code Refactoring die neuen Schnittstellen zu verwenden - dh die Kopplung in Ihrem System zu reduzieren.
  3. Richten Sie den IoC-Container so ein, dass das System mithilfe der von Ihnen erstellten Schnittstellen und Implementierungen aufgebaut wird. In diesem Stadium möchten Sie dafür sorgen, dass der IoC-Container instanziiert wird, damit die Anwendung aufgerufen werden kann. Wenn Sie sich in einer Servlet-Umgebung befinden, stellen Sie sicher, dass Sie den Container in der Servlet- init()Methode abrufen / erstellen können .
  4. Machen Sie dasselbe in jedem Subsystem erneut. Dieses Mal, wenn Sie einen Refactor durchführen, verwandeln Sie Ihre Stub-Implementierung in eine echte Implementierung, die wiederum Schnittstellen verwendet, um mit den Komponenten des Subsystems zu kommunizieren.
  5. Wiederholen Sie diesen Vorgang nach Bedarf, bis Sie ein ausgewogenes Verhältnis zwischen Komponentengröße und Funktionalität gefunden haben.

Wenn Sie fertig sind, sollten Sie nur statische Methoden in Ihrem System haben, die wirklich funktionieren - zum Beispiel die CollectionsKlasse oder die MathKlasse. Keine statische Methode sollte versuchen, direkt auf andere Komponenten zuzugreifen.

Dies ist etwas, das viel Zeit in Anspruch nehmen wird. Planen Sie entsprechend. Stellen Sie sicher, dass Sie bei der Durchführung Ihres Refactorings in Ihrem Designansatz fester werden. Am Anfang wird es schmerzhaft sein. Sie ändern das Design Ihrer Anwendung drastisch iterativ.

Berin Loritsch
quelle
Gute Vorschläge. Ich verweise andere auch hier auf die Vorschläge, wenn ich solche Änderungen vornehme: code.google.com/p/autofac/wiki/ExistingApplications
Kaleb Pederson
7

Lernen Sie, effektiv mit Legacy Code zu arbeiten, und befolgen Sie seine Ratschläge. Beginnen Sie mit dem Erstellen von Inseln mit abgedecktem Code und gehen Sie schrittweise zu einer besser strukturierten Anwendung über. Der Versuch, die Änderung massenhaft vorzunehmen, ist ein Rezept für eine Katastrophe.

Michael Brown
quelle
Ich liebe dieses Buch !!
Martijn Verburg
Gute Empfehlung. Obwohl ich vor Jahren die Hälfte davon gelesen habe, kann ich mir vorstellen, dass ich jetzt, da ich tief in der Situation bin, viel mehr daraus machen würde.
Kaleb Pederson
Es ist lustig, die ausgewählte Antwort fasst das Buch im Grunde zusammen;) Natürlich geht Feathers viel detaillierter vor.
Michael Brown
5

Der Hauptgrund für die Einführung von IoC ist die Entkopplung von Modulen. Das Problem insbesondere bei Java ist die außerordentlich starke Bindung, die der newOperator gibt. In Verbindung damit bedeutet dies, dass der aufrufende Code genau weiß, welches Modul er verwenden wird.

Fabriken wurden eingeführt, um dieses Wissen an einen zentralen Ort zu bringen, aber am Ende verdrahten Sie die Module entweder immer noch mit new/ singleton, wodurch die Bindung erhalten bleibt, oder Sie lesen eine Konfigurationsdatei ein und verwenden Reflection / Class.forName, das beim Refactoring spröde ist .

Wenn Sie das Ziel nicht modularisiert haben, gibt Ihnen IoC nichts.

Die Einführung von Unit-Tests wird dies höchstwahrscheinlich ändern, da Sie Module, die nicht getestet werden, verspotten müssen. Der einfachste Weg, dies sowie tatsächliche Produktionsmodule mit demselben Code zu handhaben, besteht darin, ein IoC-Framework zu verwenden, um das entsprechende zu injizieren Module.


quelle