352 Stimmen

Was sind die Nachteile bei der Verwendung von Dependency Injection?

Ich versuche, DI als Muster hier bei der Arbeit einzuführen, und einer unserer leitenden Entwickler würde es gerne wissen: Was - wenn überhaupt - sind die Nachteile zur Verwendung des Dependency Injection-Musters?

Bitte beachten Sie, dass es mir hier um eine - möglichst vollständige - Liste geht, nicht um eine subjektive Diskussion zu diesem Thema.


Klärung : Ich spreche über die Dependency Injection Muster (siehe dieser Artikel von Martin Fowler), no ein bestimmtes Framework, sei es XML-basiert (wie Spring) oder codebasiert (wie Guice), oder "selbstgesteuert".


bearbeiten : Einige großartige weitere Diskussionen / Tiraden / Debatten /r/programmierung hier.

229voto

Håvard S Punkte 22133

Ein paar Punkte:

  • DI erhöht die Komplexität, in der Regel durch eine größere Anzahl von Klassen, da die Verantwortlichkeiten stärker getrennt werden, was nicht immer von Vorteil ist.
  • Ihr Code ist (in gewissem Maße) an das von Ihnen verwendete Dependency-Injection-Framework gekoppelt (oder allgemeiner gesagt, an die Art und Weise, wie Sie das DI-Muster implementieren wollen).
  • DI-Container oder Ansätze, die eine Typauflösung durchführen, verursachen im Allgemeinen einen leichten Laufzeitnachteil (sehr vernachlässigbar, aber es gibt ihn)

Der Vorteil der Entkopplung besteht im Allgemeinen darin, dass die einzelnen Aufgaben einfacher zu lesen und zu verstehen sind, aber die Komplexität der Orchestrierung der komplexeren Aufgaben steigt.

203voto

Dasselbe Grundproblem tritt häufig bei der objektorientierten Programmierung, bei Stilregeln und bei so ziemlich allem anderen auf. Es ist möglich - und sogar sehr verbreitet -, zu viel zu abstrahieren, zu viele Umwege zu machen und allgemein gute Techniken übermäßig und an den falschen Stellen anzuwenden.

Jedes Muster oder andere Konstrukt, das Sie anwenden, bringt Komplexität mit sich. Abstraktion und Indirektion streuen Informationen umher, wodurch manchmal irrelevante Details aus dem Weg geräumt werden, es aber auch manchmal schwieriger wird, genau zu verstehen, was passiert. Jede Regel, die Sie anwenden, bringt Unflexibilität mit sich und schließt Optionen aus, die vielleicht gerade die beste Herangehensweise sind.

Es geht darum, einen Code zu schreiben, der seine Aufgabe erfüllt und robust, lesbar und wartbar ist. Sie sind ein Software-Entwickler - kein Elfenbeinturm-Bauer.

Einschlägige Links

http://thedailywtf.com/Articles/The_Inner-Platform_Effect.aspx

http://www.joelonsoftware.com/articles/fog0000000018.html


Die wahrscheinlich einfachste Form der Dependency Injection (lachen Sie nicht) ist ein Parameter. Der abhängige Code ist von Daten abhängig, und diese Daten werden durch die Übergabe des Parameters injiziert.

Ja, es ist albern und geht nicht auf den objektorientierten Punkt der Dependency Injection ein, aber ein funktionaler Programmierer wird Ihnen sagen, dass (wenn Sie Funktionen erster Klasse haben) dies die einzige Art von Dependency Injection ist, die Sie brauchen. Es geht hier darum, ein triviales Beispiel zu nehmen und die möglichen Probleme aufzuzeigen.

Nehmen wir diese einfache traditionelle Funktion - die C++-Syntax ist hier nicht von Bedeutung, aber ich muss sie irgendwie buchstabieren...

void Say_Hello_World ()
{
  std::cout << "Hello World" << std::endl;
}

Ich habe eine Abhängigkeit, die ich extrahieren und injizieren möchte - den Text "Hello World". Einfach genug...

void Say_Something (const char *p_text)
{
  std::cout << p_text << std::endl;
}

Inwiefern ist das unflexibler als das Original? Nun, was ist, wenn ich beschließe, dass die Ausgabe in Unicode erfolgen soll. Dann möchte ich wahrscheinlich von std::cout zu std::wcout wechseln. Aber das bedeutet, dass meine Zeichenketten dann wchar_t und nicht char sein müssen. Entweder muss jeder Aufrufer geändert werden, oder (vernünftiger), die alte Implementierung wird durch einen Adapter ersetzt, der den String übersetzt und die neue Implementierung aufruft.

Das sind Wartungsarbeiten, die nicht nötig wären, wenn wir das Original behalten hätten.

Und wenn es Ihnen trivial erscheint, schauen Sie sich diese reale Funktion aus der Win32-API an...

http://msdn.microsoft.com/en-us/library/ms632680%28v=vs.85%29.aspx

Das sind 12 "Abhängigkeiten", mit denen man umgehen muss. Wenn zum Beispiel die Bildschirmauflösungen wirklich riesig werden, brauchen wir vielleicht 64-Bit-Koordinatenwerte - und eine weitere Version von CreateWindowEx. Und ja, es gibt bereits eine ältere Version, die vermutlich hinter den Kulissen auf die neuere Version abgebildet wird...

http://msdn.microsoft.com/en-us/library/ms632679%28v=vs.85%29.aspx

Diese "Abhängigkeiten" sind nicht nur ein Problem für den ursprünglichen Entwickler - jeder, der diese Schnittstelle verwendet, muss nachschlagen, was die Abhängigkeiten sind, wie sie spezifiziert sind und was sie bedeuten, und herausfinden, was für seine Anwendung zu tun ist. An dieser Stelle können die Worte "sinnvolle Standardeinstellungen" das Leben sehr viel einfacher machen.

Die objektorientierte Dependency Injection ist im Prinzip nicht anders. Das Schreiben einer Klasse bedeutet einen Mehraufwand, sowohl an Quelltext als auch an Entwicklungszeit, und wenn diese Klasse so geschrieben ist, dass sie Abhängigkeiten gemäß den Spezifikationen einiger abhängiger Objekte bereitstellt, dann ist das abhängige Objekt an die Unterstützung dieser Schnittstelle gebunden, selbst wenn die Implementierung dieses Objekts ersetzt werden muss.

Das soll nicht heißen, dass Dependency Injection schlecht ist - ganz im Gegenteil. Aber jede gute Technik kann übermäßig und an der falschen Stelle angewendet werden. So wie nicht jede Zeichenkette extrahiert und in einen Parameter verwandelt werden muss, muss auch nicht jedes Low-Level-Verhalten aus High-Level-Objekten extrahiert und in eine injizierbare Abhängigkeit verwandelt werden.

82voto

Epaga Punkte 36700

Hier ist meine eigene erste Reaktion: Im Grunde die gleichen Nachteile wie bei jedem anderen Muster.

  • es braucht Zeit zu lernen
  • wenn sie missverstanden wird, kann sie mehr schaden als nützen
  • Wenn man es auf die Spitze treibt, kann es mehr Arbeit bedeuten, als der Nutzen rechtfertigen würde.

48voto

kyoryu Punkte 12525

Der größte "Nachteil" der Inversion of Control (nicht ganz DI, aber nahe genug) ist, dass sie dazu führt, dass es keinen einzigen Punkt mehr gibt, an dem man sich einen Überblick über einen Algorithmus verschaffen kann. Das ist im Grunde das, was passiert, wenn man entkoppelten Code hat, obwohl - die Fähigkeit, an einem Ort zu schauen, ist ein Artefakt der engen Kopplung.

46voto

Andy Peck Punkte 441

Ich habe Guice (Java DI-Framework) in den letzten 6 Monaten ausgiebig genutzt. Obwohl ich es insgesamt für großartig halte (vor allem aus der Testperspektive), gibt es gewisse Nachteile. Vor allem:

  • Der Code kann schwieriger zu verstehen werden. Dependency Injection kann auf sehr... kreative... Weise verwendet werden. Ich bin zum Beispiel gerade auf einen Code gestoßen, der eine benutzerdefinierte Annotation verwendet, um bestimmte IOStreams zu injizieren (z. B. @Server1Stream, @Server2Stream). Das funktioniert zwar, und ich gebe zu, es hat eine gewisse Eleganz, aber es macht das Verständnis der Guice-Injektionen zu einer Voraussetzung für das Verständnis des Codes.
  • Höhere Lernkurve beim Erlernen des Projekts. Dies hängt mit Punkt 1 zusammen. Um zu verstehen, wie ein Projekt, das Dependency Injection verwendet, funktioniert, muss man sowohl das Dependency Injection Pattern als auch das spezifische Framework verstehen. Als ich bei meiner jetzigen Arbeit anfing, verbrachte ich einige verwirrte Stunden damit, zu verstehen, was Guice hinter den Kulissen tat.
  • Konstrukteure werden groß. Obwohl dies weitgehend mit einem Standardkonstruktor oder einer Fabrik gelöst werden kann.
  • Fehler können vertuscht werden. Mein jüngstes Beispiel dafür war eine Kollision bei 2 Flaggennamen. Guice schluckte den Fehler stillschweigend und eine meiner Flaggen wurde nicht initialisiert.
  • Fehler werden in die Laufzeit verschoben. Wenn Sie Ihr Guice-Modul falsch konfigurieren (zirkuläre Referenz, schlechte Bindung, ...), werden die meisten Fehler nicht während der Kompilierzeit aufgedeckt. Stattdessen werden die Fehler aufgedeckt, wenn das Programm tatsächlich ausgeführt wird.

Jetzt, wo ich mich beschwert habe. Lassen Sie mich sagen, dass ich Guice in meinem aktuellen Projekt und höchstwahrscheinlich auch in meinem nächsten Projekt weiterhin (gerne) verwenden werde. Dependency Injection ist ein großartiges und unglaublich mächtiges Muster. Aber es kann definitiv verwirrend sein, und Sie werden mit ziemlicher Sicherheit einige Zeit damit verbringen, über das von Ihnen gewählte Dependency Injection Framework zu fluchen.

Außerdem stimme ich mit anderen Postern überein, dass Dependency Injection überstrapaziert werden kann.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X