Abhängigkeitsinjektion: Wie verkauft man es? [Geschlossen]

95

Lassen Sie es wissen, dass ich ein großer Fan von Dependency Injection (DI) und automatisierten Tests bin . Ich könnte den ganzen Tag darüber reden.

Hintergrund

Kürzlich hat unser Team dieses große Projekt bekommen, das von Grund auf neu gebaut werden soll. Es ist eine strategische Anwendung mit komplexen Geschäftsanforderungen. Natürlich wollte ich, dass es schön und sauber ist, was für mich bedeutet: wartbar und überprüfbar. Also wollte ich DI verwenden.

Widerstand

Das Problem war in unserem Team, DI ist tabu. Es wurde ein paar Mal erwähnt, aber die Götter sind nicht einverstanden. Das hat mich aber nicht entmutigt.

Mein Umzug

Das mag komisch klingen, aber Bibliotheken von Drittanbietern werden normalerweise von unserem Architektenteam nicht genehmigt (denken Sie: "Sie sollten nicht von Unity , Ninject , NHibernate , Moq oder NUnit sprechen , damit ich Ihnen nicht den Finger abschneide"). Anstatt einen etablierten DI-Container zu verwenden, habe ich einen extrem einfachen Container geschrieben. Es hat im Grunde alle Ihre Abhängigkeiten beim Start verkabelt, alle Abhängigkeiten (Konstruktor / Eigenschaft) injiziert und alle verfügbaren Objekte am Ende der Webanforderung entsorgt. Es war extrem leicht und hat genau das getan, was wir brauchten. Und dann bat ich sie, es zu überprüfen.

Die Antwort

Um es kurz zu machen. Ich stieß auf heftigen Widerstand. Das Hauptargument war: "Wir müssen diese Komplexitätsebene nicht zu einem bereits komplexen Projekt hinzufügen". "Es ist auch nicht so, als würden wir verschiedene Implementierungen von Komponenten einstecken". Und "Wir wollen es einfach halten, wenn möglich einfach alles in eine Baugruppe packen. DI ist eine nicht benötigte Komplexität ohne Nutzen".

Schließlich meine Frage

Wie würden Sie mit meiner Situation umgehen? Ich bin nicht gut darin, meine Ideen zu präsentieren, und ich würde gerne wissen, wie die Leute ihre Argumente präsentieren würden.

Natürlich gehe ich davon aus, dass Sie wie ich lieber DI verwenden. Wenn Sie nicht einverstanden sind, sagen Sie bitte, warum, damit ich die andere Seite der Medaille sehen kann. Es wäre wirklich interessant, den Standpunkt von jemandem zu sehen, der anderer Meinung ist.

Aktualisieren

Vielen Dank für alle Antworten. Das relativiert die Dinge wirklich. Es ist schön genug, noch ein paar Augen zu haben, um dir ein Feedback zu geben. Fünfzehn ist wirklich großartig! Das sind wirklich großartige Antworten und haben mir geholfen, das Problem von verschiedenen Seiten zu sehen, aber ich kann nur eine Antwort auswählen, also werde ich nur die meistgewählte auswählen. Vielen Dank an alle, die sich die Zeit genommen haben zu antworten.

Ich habe entschieden, dass es wahrscheinlich nicht der beste Zeitpunkt ist, DI zu implementieren, und wir sind nicht bereit dafür. Stattdessen werde ich mich darauf konzentrieren, das Design testbar zu machen und zu versuchen, automatisierte Komponententests vorzustellen. Mir ist bewusst, dass das Schreiben von Tests zusätzlichen Aufwand bedeutet, und wenn jemals entschieden wird, dass sich der zusätzliche Aufwand nicht lohnt, würde ich es persönlich immer noch als eine Gewinnsituation ansehen, da das Design immer noch testbar ist. Und wenn in Zukunft jemals ein Test oder DI in Frage kommt, kann das Design problemlos damit umgehen.

Mel
quelle
64
Es hört sich so an, als müssten Sie zu einem anderen Unternehmen
wechseln
24
Die Verwendung von DI ist (zumindest in Java, C #, ...) fast eine natürliche Folge der Verwendung von Komponententests. Verwendet Ihr Unternehmen Komponententests?
Sebastiangeiger
27
Oder einfach nicht auf DI fokussieren. DI unterscheidet sich von "wartbar und testbar". Wenn es unterschiedliche Meinungen zu einem Projekt gibt, müssen Sie verfassen und manchmal akzeptieren, dass Sie sich nicht entscheiden. Ich habe zum Beispiel Katastrophen erlebt, die durch die Inversion von Steuerelementen, DI und mehreren Ebenen von Frameworks verstärkt wurden und komplexe Dinge ergeben, die einfach sein sollten (ich kann in Ihrem Fall nicht argumentieren).
Denys Séguret
34
"... ich könnte den ganzen Tag darüber reden." Klingt so, als müssten Sie aufhören, von etwas besessen zu sein, das häufig missbraucht wird, weil Sie dogmatisch an einem Weißbuch des Tages festhalten.
21
Ihre Mitarbeiter haben dem Klang nach objektive Argumente, die gegen die Verwendung von DI-Containern sprechen: „Wir müssen diese Komplexität nicht zu einem bereits komplexen Projekt hinzufügen“ - haben sie vielleicht Recht? Haben Sie in der Tat profitieren von der zusätzlichen Komplexität? Wenn ja, sollte das möglich sein zu streiten. Sie behaupten, dass "DI eine unnötige Komplexität ohne Nutzen ist." Wenn Sie einen objektiven Nutzen zeigen können, sollten Sie dies ganz einfach gewinnen, nicht wahr? Tests werden in den anderen Kommentaren häufig erwähnt. Für das Testen wird jedoch grundsätzlich kein DI benötigt, es sei denn, Sie benötigen Mocks (was nicht selbstverständlich ist).
Konrad Rudolph

Antworten:

62

Nehmen Sie ein paar der Gegenargumente:

"Wir wollen es einfach halten, wenn möglich einfach alles in eine Baugruppe packen. DI ist eine nicht benötigte Komplexität ohne Nutzen."

"Es ist nicht so, als würden wir verschiedene Implementierungen von Komponenten einstecken."

Sie möchten, dass das System testbar ist. Um leicht prüfbar sein müssen Sie verspotten die verschiedenen Schichten des Projektes (Datenbank, Kommunikation etc.) zu suchen und in diesem Fall , dass Sie werden in verschiedenen Implementierungen von Komponenten werden zu verstopfen.

Verkaufen Sie DI über die Testvorteile, die es Ihnen bietet. Wenn das Projekt komplex ist, brauchen Sie gute, solide Unit-Tests.

Ein weiterer Vorteil ist, dass Sie beim Codieren auf Schnittstellen die alte Implementierung mit DI viel einfacher gegen die andere austauschen können, wenn Sie eine bessere Implementierung (schneller, weniger speicherhungrig, was auch immer) für eine Ihrer Komponenten finden Neu.

Was ich hier sage, ist, dass Sie sich mit den Vorteilen befassen müssen, die DI mit sich bringt, anstatt für DI zu streiten. Indem die Leute dazu gebracht werden, der Aussage zuzustimmen:

"Wir brauchen X, Y und Z"

Sie verschieben dann das Problem. Sie müssen sicherstellen, dass DI die Antwort auf diese Anweisung ist. Auf diese Weise erhalten Ihre Mitarbeiter die Lösung, anstatt das Gefühl zu haben, dass sie ihnen auferlegt wurde.

ChrisF
quelle
+1. Kurz und auf den Punkt. Leider fällt es ihm aufgrund der von Mels Mitarbeitern vorgebrachten Argumente schwer, sie davon zu überzeugen, dass es sich lohnt, es nur einmal zu versuchen - was Spoike in seiner Antwort sagte -, eher ein Menschenproblem als ein technisches Problem.
Patryk Ćwiek
1
@ Trustme-I'maDoctor - Oh, ich bin damit einverstanden, dass es sich um ein Menschenproblem handelt, aber mit diesem Ansatz zeigen Sie die Vorteile, anstatt für DI zu argumentieren.
ChrisF
Es stimmt und ich wünsche ihm viel Glück, sein Leben als Entwickler wird einfacher mit der richtigen Testbarkeit usw. :)
Patryk Ćwiek
4
+1 Ich denke, dein letzter Absatz sollte der erste sein. Das ist zentral für das Problem. Wenn Unit Test durchgeführt und die Umstellung des gesamten Systems auf ein DI-Modell vorgeschlagen wurde, würde ich auch Nein zu ihm sagen.
Andrew T Finnell
+1 sehr hilfreich. Ich würde nicht sagen, dass DI ein absolutes Muss für Unit-Tests ist, aber es macht die Dinge verdammt viel einfacher.
Mel
56

Von dem, was Sie schreiben, ist DI selbst nicht tabu, sondern die Verwendung von DI-Containern, was eine andere Sache ist. Ich nehme an, Sie werden keine Probleme mit Ihrem Team bekommen, wenn Sie nur unabhängige Komponenten schreiben, die andere Komponenten erhalten, die sie zum Beispiel vom Konstruktor übergeben müssen. Nennen Sie es einfach nicht "DI".

Sie mögen denken, dass die Verwendung eines DI-Containers für solche Komponenten mühsam ist, und Sie haben Recht, aber geben Sie Ihrem Team die Zeit, dies selbst herauszufinden.

Doc Brown
quelle
10
+1 ein pragmatischer Workaround für eine politische / dogmatische Sackgasse
k3b
32
Es lohnt sich auf jeden Fall, alle Ihre Objekte manuell zu verkabeln und einen DI-Container erst dann einzuführen, wenn es haarig wird. Wenn Sie dies tun, sehen sie DI-Container nicht als zusätzliche Komplexität, sondern als zusätzliche Einfachheit.
Phil
2
Das einzige Problem ist , dass das Muster lose gekoppelten Abhängigkeiten in Abhängigen von vorbei ist DI. IoC oder die Verwendung eines "Containers" zum Auflösen lose gekoppelter Abhängigkeiten ist eine automatisierte DI.
KeithS
51

Da Sie gefragt haben, werde ich die Seite Ihres Teams gegen DI übernehmen.

Der Fall gegen Dependency Injection

Es gibt eine Regel, die ich "Erhaltung der Komplexität" nenne und die der physikalischen Regel "Erhaltung der Energie" entspricht. Es heißt, dass kein Ingenieuraufwand die Gesamtkomplexität einer optimalen Lösung für ein Problem verringern kann. Alles, was er tun kann, ist, diese Komplexität zu verschieben. Die Produkte von Apple sind nicht weniger komplex als die von Microsoft. Sie verlagern einfach die Komplexität vom Benutzerbereich in den Engineering-Bereich. (Es ist jedoch eine fehlerhafte Analogie. Sie können zwar keine Energie erzeugen, aber Ingenieure haben die unangenehme Angewohnheit, auf Schritt und Tritt Komplexität zu erzeugen. Tatsächlich scheinen viele Programmierer Spaß daran zu haben, Komplexität hinzuzufügen und Magie einzusetzenDies ist per definitionem eine Komplexität, die der Programmierer nicht vollständig versteht. Diese übermäßige Komplexität kann reduziert werden.) Normalerweise bedeutet das Reduzieren der Komplexität, dass die Komplexität einfach an einen anderen Ort verlagert wird, normalerweise in eine Bibliothek.

In ähnlicher Weise verringert DI nicht die Komplexität der Verknüpfung von Client-Objekten mit Server-Objekten. Was es tut, ist, es aus Java herauszunehmen und es in XML zu verschieben. Das ist insofern gut, als es alles in eine (oder mehrere) XML-Datei (en) zentralisiert, in denen es einfach ist, alles zu sehen, was vor sich geht, und in denen es möglich ist, Dinge zu ändern, ohne den Code neu zu kompilieren. Auf der anderen Seite ist das schlecht, weil die XML-Dateien nicht Java sind und daher nicht für Java-Tools verfügbar sind. Sie können sie nicht im Debugger debuggen, Sie können ihre Aufrufhierarchie nicht mithilfe der statischen Analyse nachverfolgen usw. Insbesondere werden Fehler im DI-Framework extrem schwierig zu erkennen, zu identifizieren und zu beheben.

Es ist daher viel schwieriger, ein Programm mit DI als korrekt zu beweisen. Viele Leute argumentieren, dass Programme, die DI verwenden, einfacher zu testen sind , aber das Testen von Programmen kann niemals das Fehlen von Fehlern beweisen . (Beachten Sie, dass das verlinkte Papier ungefähr 40 Jahre alt ist und daher einige veraltete Verweise enthält und einige veraltete Praktiken zitiert, aber viele der grundlegenden Aussagen immer noch zutreffen. Insbesondere gilt P <= p ^ n, wobei P ist die Wahrscheinlichkeit, dass das System fehlerfrei ist, p ist die Wahrscheinlichkeit, dass eine Systemkomponente fehlerfrei ist, und n ist die Anzahl der Komponenten. Natürlich ist diese Gleichung stark vereinfacht, weist aber auf eine wichtige Wahrheit hin NASDAQ-Absturz beim Facebook-Börsengang ist ein aktuelles Beispiel, bei demSie gaben an, dass sie 1.000 Stunden damit verbracht hatten, den Code zu testen und die Fehler, die den Absturz verursacht hatten, immer noch nicht aufgedeckt hatten. 1.000 Stunden sind ein halbes Personenjahr, es ist also nicht so, als würden sie nur knapp an den Tests teilnehmen.

Es stimmt, kaum jemand unternimmt (geschweige denn beendet) die Aufgabe, formal zu beweisen, dass ein Code korrekt ist, aber selbst schwache Versuche, Beweise zu liefern, schlagen die meisten Testverfahren zum Auffinden von Fehlern aus. Starke Beweisversuche, zum Beispiel L4.verified , deckten ausnahmslos eine große Menge von Fehlern auf, die beim Testen nicht aufgedeckt wurden und wahrscheinlich auch nicht aufgedeckt würden, wenn der Tester die genaue Art des Fehlers nicht bereits kannte. Alles, was die Überprüfung des Codes durch Inspektion erschwert, kann als Verringerung der Wahrscheinlichkeit angesehen werden, dass Fehler erkannt werden , selbst wenn dies die Testfähigkeit erhöht.

Außerdem wird DI nicht zum Testen benötigt . Ich benutze es selten für diesen Zweck, da ich es vorziehen würde, das System mit der realen Software im System zu testen, anstatt mit einer alternativen Testversion. Alles, was ich im Test ändere, wird (oder könnte es auch sein) in Eigenschaftendateien gespeichert, die das Programm eher auf Ressourcen in der Testumgebung als auf Produktionsdateien verweisen. Ich würde viel lieber Zeit damit verbringen, einen Testdatenbankserver mit einer Kopie der Produktionsdatenbank einzurichten, als Zeit damit zu verbringen, eine Scheindatenbank zu codieren, da ich auf diese Weise Probleme mit Produktionsdaten verfolgen kann (Probleme mit der Zeichencodierung sind nur ein Beispiel) ) und Systemintegrationsfehler sowie Fehler im Rest des Codes.

Die Abhängigkeitsinjektion ist auch für die Abhängigkeitsinversion nicht erforderlich . Sie können problemlos statische Factory-Methoden verwenden, um die Abhängigkeitsinversion zu implementieren. So wurde es in den 90er Jahren gemacht.

In der Tat, obwohl ich DI seit einem Jahrzehnt verwende, sind die einzigen Vorteile, die ich davon überzeugen kann, die Möglichkeit, Bibliotheken von Drittanbietern für die Verwendung anderer Bibliotheken von Drittanbietern zu konfigurieren (z. B. Spring für die Verwendung von Hibernate und beide für die Verwendung von Log4J einrichten) ) und die Aktivierung von IoC über Proxys. Wenn Sie keine Bibliotheken von Drittanbietern und kein IoC verwenden, hat dies nicht viel Sinn und führt in der Tat zu einer ungerechtfertigten Komplexität.

Old Pro
quelle
1
Ich bin anderer Meinung, es ist möglich, die Komplexität zu reduzieren. Ich weiß, weil ich es getan habe. Natürlich erfordern einige Probleme / Anforderungen Komplexität, aber darüber hinaus kann das meiste mit Mühe beseitigt werden.
Ricky Clarkson
10
@ Ricky, es ist eine subtile Unterscheidung. Wie gesagt, Ingenieure können Komplexität hinzufügen und diese Komplexität kann weggenommen werden, sodass Sie möglicherweise die Komplexität der Implementierung verringert haben, aber per Definition können Sie die Komplexität der optimalen Lösung für ein Problem nicht verringern. Meistens wird die Komplexität nur an einen anderen Ort verlagert (normalerweise in eine Bibliothek). In jedem Fall ist es für mich zweitrangig, dass DI die Komplexität nicht verringert.
Old Pro
2
@Lee, das Konfigurieren von DI im Code ist noch weniger nützlich. Einer der am weitesten verbreiteten Vorteile von DI ist die Möglichkeit, die Dienstimplementierung zu ändern, ohne den Code neu zu kompilieren. Wenn Sie DI im Code konfigurieren, verlieren Sie diesen.
Old Pro
7
@OldPro - Das Konfigurieren im Code bietet den Vorteil der Typensicherheit, und die meisten Abhängigkeiten sind statisch und können nicht extern definiert werden.
Lee
3
@Lee Wenn die Abhängigkeiten statisch sind, warum sind sie dann überhaupt nicht fest codiert, ohne den Umweg über DI?
Konrad Rudolph
25

Es tut mir leid zu sagen, dass das Problem, das Sie haben, in Anbetracht dessen, was Ihre Kollegen in Ihrer Frage gesagt haben, eher politischer als technischer Natur ist. Es gibt zwei Mantras, an die Sie denken sollten:

  • "Es ist immer ein Menschenproblem"
  • " Veränderung ist beängstigend"

Sicher, Sie können viele Gegenargumente mit soliden technischen Gründen und Vorteilen vorbringen, aber das bringt Sie in eine schlechte Situation mit dem Rest des Unternehmens. Sie haben bereits eine Haltung, die sie nicht wollen (weil sie sich damit abfinden, wie die Dinge jetzt funktionieren). Daher kann es sogar zu Problemen in Ihrer Beziehung zu Ihren Kollegen kommen, wenn Sie weiterhin hartnäckig sind. Vertrauen Sie mir, denn es ist mir passiert und hat mich letztendlich vor einigen Jahren gefeuert (jung und naiv, wie ich es war). Dies ist eine Situation, in die du dich nicht hineinversetzen willst.

Die Sache ist, dass Sie ein gewisses Maß an Vertrauen erreichen müssen, bevor die Menschen ihre derzeitige Arbeitsweise ändern können. Solange Sie nicht in einer Position sind, in der Sie viel Vertrauen haben oder über solche Dinge wie die Rolle eines Architekten oder eines technischen Leiters entscheiden können, können Sie nur sehr wenig tun, um Ihre Kollegen umzudrehen. Es wird eine Menge Zeit in Anspruch nehmen, um Vertrauen zu gewinnen und die Unternehmenskultur wieder auf Vordermann zu bringen. Wir sprechen von einer Zeitspanne von vielen Monaten oder Jahren.

Wenn Sie feststellen, dass die aktuelle Unternehmenskultur nicht mit Ihnen zusammenarbeitet, wissen Sie zumindest etwas anderes, das Sie bei Ihrem nächsten Vorstellungsgespräch fragen sollten. ;-)

Spoike
quelle
23

DI nicht verwenden. Vergiss es.

Erstellen Sie eine Implementierung des GoF- Factory-Musters , das Ihre speziellen Abhängigkeiten "erstellt" oder "findet" und sie an Ihr Objekt weiterleitet und dabei belässt. Nennen Sie es jedoch nicht DI und erstellen Sie kein komplexes verallgemeinertes Framework. Halten Sie es einfach und relevant. Stellen Sie sicher, dass die Abhängigkeiten und Ihre Klassen so sind, dass ein Wechsel zu DI möglich ist. Behalten Sie aber die Fabrik als Master bei und halten Sie den Umfang extrem begrenzt.

Mit der Zeit können Sie hoffen, dass es wachsen und sogar eines Tages zu DI übergehen wird. Lassen Sie die Leads in Ihrer Freizeit zum Abschluss kommen und drücken Sie nicht. Selbst wenn Sie nie dazu kommen, hat zumindest Ihr Code einige der Vorteile von DI, zum Beispiel Unit-Test-Code.

jasonk
quelle
3
+1 für das Zusammenwachsen mit dem Projekt und "Nenn es nicht DI"
Kevin McCormick
5
Ich stimme zu, aber am Ende ist es DI. Es wird nur kein DI-Container verwendet. Es geht darum, die Last an den Anrufer weiterzuleiten, anstatt sie an einem Ort zu zentralisieren. Es wäre jedoch klug, es "Externalizing Dependencies" anstelle von DI zu nennen.
Juan Mendes
5
Mir ist oft der Gedanke gekommen, dass man, um ein Elfenbeinturm-Konzept wie DI zu entwickeln, denselben Prozess durchlaufen muss wie die Evangelisten, um zu erkennen, dass es überhaupt ein Problem gibt, das gelöst werden muss. Autoren vergessen dies oft. Bleiben Sie bei der einfachen Mustersprache, und die Notwendigkeit eines Containers kann sich als Folge ergeben (oder auch nicht).
Tom W
@ JuanMendes aus ihrer Antwort Ich denke, dass das Externalisieren von Abhängigkeiten genau das ist, was sie ablehnen, weil sie auch keine Bibliotheken von Drittanbietern mögen und alles in einer einzigen Baugruppe wollen (Monolith?). Wenn dies zutrifft, ist es nicht besser, es "Externalizing Dependencies" zu nennen, als DI von ihrem Standpunkt aus aufzurufen.
Jonathan Neufeld
22

Ich habe Projekte gesehen, die DI auf das Äußerste trieben, um Objekte zu testen und zu verspotten. So sehr, dass die DI-Konfiguration selbst zur Programmiersprache wurde und so viel Konfiguration erforderlich war, um ein System zum Laufen zu bringen, wie der eigentliche Code.

Leidet das System derzeit unter dem Mangel an geeigneten internen APIs, die nicht getestet werden können? Hoffen Sie, dass Sie durch die Umstellung des Systems auf ein DI-Modell einen besseren Komponententest durchführen können? Sie benötigen keinen Container, um Ihren Code einem Komponententest zu unterziehen. Die Verwendung eines DI-Modells würde es Ihnen ermöglichen, den Komponententest mit Mock-Objekten zu vereinfachen, dies ist jedoch nicht erforderlich.

Sie müssen nicht das gesamte System sofort umschalten, um DI-kompatibel zu sein. Sie sollten auch nicht willkürlich Unit-Tests schreiben. Refactor-Code, wie Sie ihn in Ihren Feature- und Bug-Working-Tickets finden. Stellen Sie dann sicher, dass der Code, den Sie berührt haben, leicht testbar ist.

Denken Sie an CodeRot als Krankheit. Sie wollen nicht willkürlich loshacken. Sie haben einen Patienten, Sie sehen einen wunden Fleck, also beginnen Sie, den Fleck und die umliegenden Dinge zu reparieren. Sobald dieser Bereich sauber ist, fahren Sie mit dem nächsten fort. Früher oder später haben Sie den größten Teil des Codes berührt und es war keine "massive" architektonische Änderung erforderlich.

Ich mag es nicht, dass DI- und Mock-Tests sich gegenseitig ausschließen. Und nachdem ich ein Projekt gesehen habe, das mangels eines besseren Wortes verrückt nach DI war, wäre ich auch müde, ohne den Nutzen zu sehen.

Es gibt einige Orte, an denen die Verwendung von DI sinnvoll ist:

  • Die Datenzugriffsebene zum Austauschen von Strategien zum Erstellen von Storys
  • Authentifizierungs- und Autorisierungsschicht.
  • Themen für die Benutzeroberfläche
  • Dienstleistungen
  • Plugin-Erweiterungspunkte, die von Ihrem eigenen System oder von Drittanbietern verwendet werden können.

Es ist frustrierend, wenn jeder Entwickler weiß, wo sich die DI-Konfigurationsdatei befindet (ich weiß, dass Container durch Code instanziiert werden können, aber warum sollten Sie das tun.), Wenn er eine RegEx ausführen möchte. Oh, ich sehe, es gibt IRegExCompiler, DefaultRegExCompiler und SuperAwesomeRegExCompiler. Trotzdem kann ich an keiner Stelle im Code analysieren, wo Default und SuperAwesome verwendet werden.

Meine eigene Persönlichkeit reagieren würde besser , wenn jemand zeigt mir etwas , das besser war, dann versucht , mich mit ihren Worten zu überzeugen. Es gibt etwas zu sagen über jemanden, der Zeit und Mühe investieren würde, um das System zu verbessern. Ich finde nicht, dass es vielen Entwicklern wichtig genug ist, das Produkt wirklich zu verbessern. Wenn Sie mit echten Änderungen im System zu ihnen gehen und ihnen zeigen könnten, wie es für Sie besser und einfacher geworden ist, ist das mehr wert als jede Online-Recherche.

Zusammenfassend lässt sich festhalten, dass der Code, den Sie gerade berühren, mit jedem Durchlauf besser wird, um Änderungen an einem System zu bewirken. Früher oder später konnten Sie das System in etwas Besseres verwandeln.

Andrew Finnell
quelle
"DI- und Mock-Test schließen sich gegenseitig aus" Das ist falsch, sie schließen sich auch nicht gegenseitig ein. Sie arbeiten einfach gut zusammen. Sie listen auch die Orte auf, an denen DI gut ist, die Serviceebene, das Dao und die Benutzeroberfläche - das ist fast überall, nicht wahr?
NimChimpsky
@Zeichne gültige Punkte. Natürlich würde ich nicht wollen, dass es zu weit geht. Ich wollte das automatisierte Testen für die Geschäftsklassen am meisten, da wir sehr komplexe Geschäftsregeln implementieren müssen. Und mir ist klar, dass ich sie immer noch ohne Container testen kann, aber persönlich ist es nur sinnvoll, einen Container zu verwenden. Ich habe tatsächlich ein kleines Beispiel gemacht, das das Konzept zeigte. Aber es wurde nicht einmal angeschaut. Ich glaube, mein Fehler war, dass ich keinen Test erstellt habe, der zeigt, wie einfach das Testen / Verspotten ist.
Mel
So viel Übereinstimmung! Ich hasse DI-Konfigurationsdateien und die Auswirkungen auf den Programmfluss. Das Ganze verwandelt sich in "gruselige Action auf Distanz" ohne erkennbare Verbindungen zwischen den Teilen. Wenn es einfacher wird, Code in einem Debugger als in Quelldateien zu lesen, stimmt etwas nicht.
Zan Lynx
19

DI erfordert keine invasive Inversion von Control-Containern oder spottenden Frameworks. Sie können den Code entkoppeln und DI über ein einfaches Design zulassen. Sie können Unit-Tests über die integrierten Visual Studio-Funktionen durchführen.

Um fair zu sein, haben Ihre Mitarbeiter einen Punkt. Die schlechte Nutzung dieser Bibliotheken (und da sie nicht mit ihnen vertraut sind, kann es zu Lernschwierigkeiten kommen) kann zu Problemen führen. Am Ende zählt der Code. Versauen Sie Ihr Produkt nicht für Ihre Tests.

Denken Sie daran, dass in diesen Szenarien Kompromisse erforderlich sind.

Telastyn
quelle
2
Ich bin damit einverstanden, dass DI keine IoC-Container benötigt. obwohl ich es nicht als invasiv bezeichnen würde (zumindest diese Implementierung), da der Code containerunabhängig gestaltet wurde (hauptsächlich Konstruktorinjektionen) und das gesamte DI-Material an einem Ort stattfindet. Es funktioniert also immer noch alles ohne DI-Container - ich habe parameterlose Konstruktoren eingefügt, die die konkreten Implementierungen mit Abhängigkeiten in den anderen Konstruktor "injizieren". Auf diese Weise kann ich es immer noch leicht verspotten. Also ja, ich stimme zu, DI wird tatsächlich durch Design erreicht.
Mel
+1 Für einen Kompromiss. Wenn niemand Kompromisse eingehen will, leiden alle.
Tjaart
14

Ich glaube nicht, dass Sie DI mehr verkaufen können, weil dies eine dogmatische Entscheidung ist (oder, wie @Spoike es höflicher nannte, politisch ).

In dieser Situation ist es nicht mehr möglich , mit allgemein anerkannten Best Practices wie SOLID-Konstruktionsprinzipien zu streiten .

Jemand, der mehr politische Macht hat als Sie, hat eine (möglicherweise falsche) Entscheidung getroffen, DI nicht zu verwenden.

Sie auf der anderen Seite haben sich dieser Entscheidung widersetzt, indem Sie Ihren eigenen Container implementiert haben, da die Verwendung eines etablierten Containers verboten war. Diese Politik der vollendeten Tatsachen , die Sie versucht haben, könnte die Situation noch schlimmer gemacht haben.

Analyse

Meiner Meinung nach hat DI ohne Testdriven Development (TDD) und Unit Testing keinen signifikanten Vorteil, der die anfänglichen Mehrkosten überwiegt.

Geht es bei diesem Thema wirklich um

  • wollen wir nicht DI ?

oder geht es hier mehr um

  • tdd / unittesting ist eine Verschwendung von Ressourcen ?

[Aktualisieren]

Wenn Sie Ihr Projekt anhand der klassischen Fehler in der Projektmanagementansicht sehen , sehen Sie

#12: Politics placed over substance.
#21: Inadequate design. 
#22: Shortchanged quality assurance.
#27: Code-like-hell programming.

während die anderen sehen

#3: Uncontrolled problem employees. 
#30: Developer gold-plating. 
#32: Research-oriented development. 
#34: Overestimated savings from new tools or methods. 
k3b
quelle
Derzeit führen wir keine Unit-Tests in unserem Team durch. Ich vermute, dass Ihre letzte Aussage genau richtig ist. Ich habe ein paar Mal Unit-Tests angesprochen, aber niemand hat sich wirklich dafür interessiert, und es gab immer Gründe, warum wir es nicht übernehmen können.
Mel
10

Wenn Sie feststellen, dass Sie ein Prinzip an Ihr Team "verkaufen" müssen, sind Sie wahrscheinlich bereits mehrere Kilometer auf dem falschen Weg.

Niemand möchte zusätzliche Arbeit leisten. Wenn also das, was Sie verkaufen möchten, für ihn zusätzliche Arbeit bedeutet, werden Sie ihn nicht durch die wiederholte Aufforderung zum überlegenen Argument überzeugen. Sie müssen wissen, dass Sie ihnen einen Weg zeigen, ihre Arbeitsbelastung zu reduzieren, nicht zu erhöhen.

DI wird oft als zusätzliche Komplexität angesehen, mit dem Versprechen , die Komplexität zu einem späteren Zeitpunkt zu reduzieren , was sich auszahlt, aber nicht so sehr für jemanden, der versucht, seine Arbeitsbelastung im Voraus zu reduzieren. In vielen Fällen ist DI nur eine weitere Schicht von YAGNI . Und die Kosten für diese Komplexität sind nicht gleich Null. Für ein Team, das nicht an diese Art von Muster gewöhnt ist, ist sie sogar ziemlich hoch. Und das sind echte Dollars, die in einen Eimer geschaufelt werden, der möglicherweise nie einen Nutzen bringt.

Platzieren Sie es an seinem Platz.
Verwenden Sie DI am besten dort, wo es besonders nützlich ist, und nicht nur dort, wo es üblich ist. Beispielsweise verwenden viele Apps DI, um Datenbanken auszuwählen und zu konfigurieren. Und wenn Ihre App mit einer Datenbankschicht geliefert wird, ist dies ein verlockender Ort, um sie zu platzieren. Wenn Ihre App jedoch mit einer integrierten, vom Benutzer nicht sichtbaren Datenbank ausgestattet ist, die ansonsten eng in den Code integriert ist, ist die Wahrscheinlichkeit, dass die Datenbank zur Laufzeit ersetzt werden muss, gleich Null. Und wenn Sie DI verkaufen, indem Sie sagen: "Sehen Sie, wir können einfach das tun, was wir niemals und niemals wollen.", Werden Sie wahrscheinlich auf die Liste "Dieser Kerl hat schlechte Ideen" mit Ihrem Chef gesetzt.

Sagen wir stattdessen, Sie haben Debugging-Ausgaben, die normalerweise in der Version IFDEF'ed werden. Und jedes Mal, wenn ein Benutzer ein Problem hat, muss Ihr Support-Team ihm einen Debugbuild senden, damit er die Protokollausgabe erhält. Hier können Sie DI verwenden, um dem Kunden das Wechseln zwischen Protokolltreibern zu ermöglichen - LogConsolefür Entwickler, LogNullKunden und LogNetworkKunden mit Problemen. Ein einheitlicher Build, zur Laufzeit konfigurierbar.

Dann musst du es nicht einmal DI nennen, sondern heißt einfach "Mel's wirklich gute Idee" und du stehst jetzt auf der Liste der guten Ideen anstelle der schlechten. Die Benutzer werden sehen, wie gut das Muster funktioniert, und es dort einsetzen, wo es in ihrem Code Sinn macht.

Wenn Sie eine Idee richtig verkaufen, werden die Leute nicht wissen, dass Sie sie von irgendetwas überzeugt haben.

tylerl
quelle
8

Natürlich hat Inversion of Control (IoC) eine Reihe von Vorteilen: Es vereinfacht den Code, fügt etwas Magie hinzu , die die typischen Aufgaben erledigt, usw.

Jedoch:

  1. Es werden viele Abhängigkeiten hinzugefügt. Einfache hallo Weltanwendung, die mit Spring geschrieben wurde, kann ein Dutzend MB wiegen, und ich habe gesehen, dass Spring nur hinzugefügt wurde, um ein paar Zeilen Konstruktor und Setter zu vermeiden.

  2. Es fügt die oben erwähnte Magie hinzu , die für Außenstehende schwer zu verstehen ist (zum Beispiel für GUI-Entwickler, die einige Änderungen in der Business-Schicht vornehmen müssen). Lesen Sie den großartigen Artikel Innovative Köpfe denken nicht gleich - New York Times , in dem beschrieben wird, wie dieser Effekt von Experten unterschätzt wird .

  3. Es wird schwieriger, die Verwendung von Klassen zu verfolgen. IDEs wie Eclipse können die Verwendung bestimmter Klassen oder Methodenaufrufe hervorragend verfolgen. Diese Spur geht jedoch verloren, wenn Abhängigkeitsinjektion und -reflexion aufgerufen werden.

  4. Die IoC-Nutzung endet normalerweise nicht mit dem Einfügen von Abhängigkeiten, sondern mit unzähligen Proxys, und Sie erhalten eine Stapelverfolgung mit Hunderten von Zeilen, von denen 90% Proxys sind und über Reflektion aufgerufen werden. Dies erschwert die Analyse von Stack-Traces erheblich.

Da ich ein großer Fan von Spring und IoC bin, musste ich kürzlich die obigen Fragen überdenken. Einige meiner Kollegen sind Webentwickler, die aus der von Python und PHP beherrschten Webwelt in die Java-Welt aufgenommen wurden, und die für Javaisten offensichtlichen Dinge sind für sie alles andere als offensichtlich. Einige meiner Kollegen machen Tricks (natürlich undokumentiert), was es sehr schwierig macht, den Fehler zu finden. Natürlich macht IoC-Missbrauch die Dinge für sie leichter;)

Mein Rat, wenn Sie die Verwendung von IoC in Ihrem Job erzwingen, werden Sie für jeden Missbrauch verantwortlich gemacht, den andere Personen anrichten;)

Łukasz Lech
quelle
+1 Wie bei jedem leistungsstarken Tool kann es leicht missbraucht werden und Sie MÜSSEN verstehen, wann Sie es NICHT verwenden dürfen.
Phil
4

Ich denke, dass ChrisF in etwas richtig ist. Verkaufe DI nicht an sich. Aber verkaufen Sie die Idee über Unit-Tests des Codes.

Ein Ansatz, um einen DI-Container in die Architektur einzubinden, könnte darin bestehen, die Implementierung von den Tests langsam auf etwas fahren zu lassen, das gut zu dieser Architektur passt. Angenommen, Sie arbeiten an einem Controller in einer ASP.NET MVC-Anwendung. Angenommen, Sie schreiben die Klasse folgendermaßen:

public class UserController {
    public UserController() : this (new UserRepository()) {}

    public UserController(IUserRepository userRepository) {
        ...
    }

    ...
}

Auf diese Weise können Sie Komponententests schreiben, die von der tatsächlichen Implementierung des Benutzer-Repositorys entkoppelt sind. Die Klasse funktioniert jedoch ohne DI-Container, um sie für Sie zu erstellen. Der parameterlose Konstruktor erstellt es mit dem Standardrepository.

Wenn Ihre Kollegen erkennen, dass dies zu viel saubereren Tests führt, können sie möglicherweise erkennen, dass dies ein besserer Weg ist. Vielleicht können Sie sie dazu bringen, so zu programmieren.

Sobald sie erkannt haben, dass dies ein besseres Design ist als der UserController, der über eine bestimmte UserRepository-Implementierung Bescheid weiß, können Sie den nächsten Schritt unternehmen und ihnen zeigen, dass Sie eine Komponente haben können, den DI-Container, der automatisch die von Ihnen benötigten Instanzen bereitstellen kann.

Pete
quelle
Toll! Ich mache das gerade, weil ich wirklich das automatisierte Testen von Einheiten möchte, auch wenn ich DI nicht bekommen kann. Ich habe vergessen zu erwähnen, dass Unit-Tests auch in unserem Team nicht durchgeführt werden :( Also, wenn ich der erste sein werde.
Mel
2
In diesem Fall würde ich sagen, dass das hier das eigentliche Problem ist. Finden Sie die Wurzel des Widerstandes gegen Unit-Tests und greifen Sie das an. Lass DI erstmal liegen. Testen ist wichtiger IMHO.
Christian Horsdal
@ChristianHorsdal Ich stimme zu, ich wollte, dass es lose gekoppelt ist, um ein einfaches Verspotten / Testen zu ermöglichen.
Mel
Diese Idee ist wirklich cool ... Großartiger Verkauf zum Testen
Mistkerl
2

Am besten treten Sie zurück und fragen sich, warum Sie DI-Container einführen möchten. Wenn Sie die Testbarkeit verbessern möchten, müssen Sie zunächst das Team dazu bringen, sich mit Unit-Tests zu befassen. Persönlich würde ich mir viel mehr Sorgen machen über das Fehlen von Unit-Tests als über das Fehlen eines DI-Containers.

Ausgestattet mit einer umfassenden Suite oder einer Reihe von Komponententests können Sie Ihr Design mit der Zeit sicher weiterentwickeln. Ohne sie haben Sie es immer schwerer, Ihr Design mit den sich ändernden Anforderungen in Einklang zu bringen - ein Kampf, den schließlich viele Teams verlieren.

Mein Rat wäre also, zuerst Unit-Tests und Refactoring zu betreiben und dann DI- und schließlich DI-Container einzuführen.

kimj100
quelle
2

Ich höre hier ein paar große Neins von Ihrem Team:

  • "Keine Bibliotheken von Drittanbietern" - AKA "Not Invented Here" oder "NIH". Die Befürchtung ist, dass Sie durch die Implementierung einer Drittanbieter-Bibliothek und die damit verbundene Abhängigkeit der Codebasis von dieser abhängig werden, falls die Bibliothek einen Fehler, eine Sicherheitslücke oder sogar nur eine Einschränkung aufweist, die Sie überwinden müssen Partei, um ihre Bibliothek zu reparieren, damit Ihr Code funktioniert. In der Zwischenzeit tragen Sie immer noch die Verantwortung (und die Entwickler von Drittanbietern werden sagen, dass ihr Tool "so wie es ist" ist, da es "Ihr" Programm ist, das spektakulär versagt hat oder gehackt wurde oder nicht das tut, wonach sie gefragt haben ", Benutzung auf eigene Gefahr).

    Das Gegenargument ist, dass der Code, der das Problem löst, bereits in der Drittanbieter-Bibliothek vorhanden ist. Bauen Sie Ihre Computer von Grund auf neu? Hast du Visual Studio geschrieben? Vermeiden Sie die integrierten Bibliotheken in .NET? Nein. Sie haben ein gewisses Vertrauen in Intel / AMD und Microsoft und sie finden ständig Fehler (und beheben sie nicht immer schnell). Durch Hinzufügen einer Bibliothek eines Drittanbieters können Sie schnell eine wartbare Codebasis zum Laufen bringen, ohne das Rad neu erfinden zu müssen. Und Microsofts Armee von Anwälten wird Ihnen ins Gesicht lachen, wenn Sie ihnen sagen, dass ein Fehler in den .NET-Kryptografiebibliotheken sie für den Vorfall des Hackens Ihres Clients verantwortlich macht, der durch die Verwendung Ihres .NET-Programms verursacht wurde. Zwar wird Microsoft mit Sicherheit versuchen, Sicherheitslücken zu schließen, die sich in keinem seiner Produkte befinden.

  • "Wir wollen alles in eine Baugruppe packen" - das tust du eigentlich nicht. Zumindest in .NET muss die gesamte Assembly, die diese Codezeile enthält, neu erstellt werden, wenn Sie eine Änderung an einer Codezeile vornehmen. Ein guter Codeentwurf basiert auf mehreren Assemblys, die Sie so unabhängig wie möglich neu erstellen können (oder zumindest nur Abhängigkeiten und keine Abhängigkeiten neu erstellen müssen). Wenn sie WIRKLICH eine EXE-Datei veröffentlichen möchten, die nur die EXE-Datei ist (die unter bestimmten Umständen einen Wert hat), gibt es eine App dafür. ILMerge.

  • "DI ist tabu" - WTF? DI ist eine akzeptierte Best Practice in jeder O / O-Sprache mit einem "Interface" -Codekonstrukt. Wie hält sich Ihr Team an die GRASP- oder SOLID-Entwurfsmethoden, wenn sie die Abhängigkeiten zwischen Objekten nicht lose koppeln? Wenn sie sich nicht darum kümmern, dann behalten sie die Spaghetti-Fabrik bei, die das Produkt zu dem komplizierten Morast macht, der es ist. Jetzt erhöht DI die Komplexität, indem es die Anzahl der Objekte erhöht, und während es das Ersetzen einer anderen Implementierung erleichtert, erschwert es das Ändern der Schnittstelle selbst (durch Hinzufügen einer zusätzlichen Schicht von Codeobjekten, die geändert werden müssen).

  • "Wir müssen diese Komplexität nicht zu einem bereits komplexen Projekt hinzufügen" - Sie haben vielleicht einen Punkt. Eine wichtige Sache, die bei jeder Codeentwicklung berücksichtigt werden muss, ist YAGNI. "Du wirst es nicht brauchen". Ein Design, das von Anfang an SOLID entwickelt wurde, ist ein Design, das SOLID "im Glauben" gemacht wurde. Sie wissen nicht, ob Sie die einfache Änderung benötigen, die SOLID-Designs bieten, aber Sie haben eine Ahnung. Während Sie Recht haben können, können Sie auch sehr falsch sein; Ein sehr FESTES Design könnte als "Lasagne-Code" oder "Ravioli-Code" mit so vielen Schichten oder mundgerechten Stücken angesehen werden, dass scheinbar triviale Änderungen schwierig werden, weil Sie so viele Schichten durchgraben und / oder nachverfolgen müssen solch ein gewundener Aufrufstapel.

    Ich unterstütze eine Drei-Treffer-Regel: Lass es funktionieren, lass es sauber sein, lass es FEST sein. Wenn Sie zum ersten Mal eine Codezeile schreiben, muss diese funktionieren, und Sie erhalten keine Punkte für Entwürfe von Elfenbeintürmen. Angenommen, es ist eine einmalige Angelegenheit, und tun Sie, was Sie tun müssen. Wenn Sie sich den Code zum zweiten Mal ansehen, möchten Sie ihn wahrscheinlich erweitern oder wiederverwenden, und es ist nicht das Einzige, von dem Sie dachten, dass es das wäre. Machen Sie es jetzt eleganter und verständlicher, indem Sie es überarbeiten. Vereinfachen Sie die verschlungene Logik, extrahieren Sie wiederholten Code in Schleifen und / oder Methodenaufrufe, fügen Sie hier und da ein paar Kommentare für Kludge hinzu, die Sie an Ort und Stelle lassen müssen. Nun sollten Sie die SOLID-Regeln einhalten. Abhängigkeiten einbauen, anstatt sie zu konstruieren, Klassen extrahieren, um Methoden zu enthalten, die weniger mit dem "Fleisch" des Codes zu tun haben,

  • "Es ist nicht so, als würden wir verschiedene Implementierungen einstecken" - Sie, Sir, haben ein Team, das nicht an Unit-Tests an Ihren Händen glaubt. Ich gehe davon aus, dass es unmöglich ist, einen Komponententest zu schreiben, der isoliert abläuft und keine Nebenwirkungen hat, ohne die Objekte "verspotten" zu können, die diese Nebenwirkungen haben. Jedes nicht triviale Programm hat Nebenwirkungen. Wenn Ihr Programm eine Datenbank liest oder in diese schreibt, Dateien öffnet oder speichert, über ein Netzwerk oder einen Peripherie-Socket kommuniziert, ein anderes Programm startet, Fenster zeichnet, Ausgaben an die Konsole ausgibt oder auf andere Weise Speicher oder Ressourcen außerhalb der "Sandbox" des Prozesses verwendet, über die es verfügt ein Nebeneffekt. Wenn es keines dieser Dinge tut, was macht es und warum sollte ich es kaufen?

    Um fair zu sein, ist Unit Testing nicht der einzige Weg, um zu beweisen, dass ein Programm funktioniert. Sie können Integrationstests schreiben, mit mathematisch erprobten Algorithmen codieren usw. Bei Unit-Tests wird jedoch sehr schnell gezeigt, dass dieser Code bei den Eingaben A, B und C das erwartete X ausgibt (oder nicht), und damit auch das Der Code funktioniert in einem bestimmten Fall ordnungsgemäß (oder nicht). Serien von Komponententests können mit einem hohen Maß an Sicherheit beweisen, dass der Code in allen Fällen wie erwartet funktioniert, und sie bieten auch etwas, was ein mathematischer Beweis nicht kann. eine Demonstration, dass das Programm STILL so funktioniert, wie es gedacht war. Ein mathematischer Beweis für den Algorithmus beweist weder, dass er korrekt implementiert wurde, noch, dass vorgenommene Änderungen korrekt implementiert wurden und ihn nicht beschädigten.

Kurz gesagt: Wenn dieses Team keinen Wert darin sieht, was DI tun würde, wird es nicht unterstützt, und alle (zumindest alle älteren Leute) müssen sich auf etwas einlassen, um echte Veränderungen herbeizuführen passieren. Sie legen viel Wert auf YAGNI. Sie legen großen Wert auf SOLID und automatisiertes Testen. Irgendwo in der Mitte liegt die Wahrheit.

KeithS
quelle
1

Achten Sie darauf, einem Projekt zusätzliche Funktionen (wie DI) hinzuzufügen, wenn diese nicht genehmigt wurden. Wenn Sie einen zeitlich begrenzten Projektplan haben, könnten Sie in die Falle geraten, dass Sie nicht genügend Zeit haben, um die genehmigten Funktionen fertigzustellen.

Auch wenn Sie DI jetzt nicht verwenden, sollten Sie sich an den Tests beteiligen, damit Sie genau wissen, welche Erwartungen Sie an die Tests in Ihrem Unternehmen haben. Es wird ein weiteres Projekt geben, und Sie können die Probleme mit dem Testen des aktuellen Projekts im Vergleich zu DI vergleichen.

Wenn Sie DI nicht verwenden, können Sie kreativ werden und Ihren Code DI- "ready" machen. Verwenden Sie einen parameterlosen Konstruktor, um andere Konstruktoren aufzurufen:

MyClassConstructor()
{
    MyClassConstructor(new Dependency)
    Property = New Dependent Property
}

MyClassConstructor(Dependency)
{
    _Dependency = Dependency
}
JLH
quelle
0

Ich denke, eines ihrer größten Anliegen ist das Gegenteil: DI macht das Projekt nicht komplex. In den meisten Fällen wird viel Komplexität reduziert.

Denken Sie nur ohne DI, was werden Sie das abhängige Objekt / die abhängige Komponente erhalten, die Sie benötigen? Normalerweise erfolgt dies durch Nachschlagen aus einem Repository oder durch Abrufen eines Singleton oder durch Instanziieren.

Bei der ersten 2 handelt es sich um zusätzlichen Code zum Auffinden der abhängigen Komponente. In der DI-Welt haben Sie nichts unternommen, um die Suche durchzuführen. Die Komplexität Ihrer Komponenten wird reduziert.

Wenn Sie sich selbst instanziieren, was in einigen Fällen nicht angemessen ist, führt dies sogar zu mehr Komplexität. Sie müssen wissen, wie das Objekt korrekt erstellt wird, und Sie müssen wissen, welche Werte das Objekt in einen funktionsfähigen Zustand versetzen soll. All dies führt zu einer zusätzlichen Komplexität Ihres Codes.

DI macht das Projekt also nicht komplex, sondern einfacher, indem es Komponenten vereinfacht.

Ein weiteres wichtiges Argument ist, dass Sie keine andere Implementierung einstecken werden. Ja, es ist wahr, dass es im Produktionscode nicht üblich ist, viele verschiedene Implementierungen im realen Produktionscode zu haben. Es gibt jedoch einen Hauptbereich, der anders implementiert werden muss: Mock / Stub / Test Doubles in Unit Tests. Damit DI funktioniert, wird in den meisten Fällen ein Interface-gesteuertes Entwicklungsmodell verwendet, das wiederum das Verspotten / Stubben in Komponententests ermöglicht. "Interface-orientiertes Design" ersetzt nicht nur die Implementierung, sondern sorgt auch für ein saubereres und besseres Design. Natürlich kann man auch ohne DI noch mit Interface entwerfen. Unit-Tests und DI drängen Sie jedoch dazu, solche Praktiken zu übernehmen.

Wenn Ihre "Götter" in der Firma nicht der Meinung sind, dass "einfacherer Code", "Komponententests", "Modularisierung", "Einzelverantwortung" usw. nichts dagegen sind, sollte es keinen Grund für sie geben, DI abzulehnen.

Adrian Shum
quelle
Theoretisch ist das schön, aber in der Praxis bedeutet das Hinzufügen eines DI-Containers zusätzliche Komplexität. Der zweite Teil Ihres Arguments zeigt, warum es die Arbeit wert ist, aber es ist immer noch Arbeit.
Schlingel
Aufgrund meiner bisherigen Erfahrungen reduziert DI die Komplexität, anstatt sie zu erhöhen. Ja, es wurde dem System etwas mehr hinzugefügt, was zur Komplexität beiträgt. Mit DI wird jedoch die Komplexität anderer Komponenten im System erheblich reduziert. Am Ende wird die Komplexität tatsächlich reduziert. Für den zweiten Teil ist es KEINE Extraarbeit, es sei denn, sie führen keine Unit-Tests durch. Ohne DI sind ihre Komponententests meist schwer zu schreiben und zu warten. Mit DI wird der Aufwand erheblich reduziert. Also, es ist in der Tat REDUZIEREN der Arbeit (es sei denn, sie sind nicht und vertrauen nicht Unit-Tests)
Adrian Shum
Ich möchte eines hervorheben: DI bedeutet in meiner Antwort kein vorhandenes DI-Framework. Es ist nur die Methode zum Entwerfen / Entwickeln von Komponenten in Ihrer App. Sie können viel davon profitieren, wenn Ihr Code schnittstellengesteuert ist und Ihre Komponenten erwarten, dass Abhängigkeiten injiziert und nicht nachgeschlagen / erstellt werden. Selbst wenn Sie einen anwendungsspezifischen "Loader" schreiben, der die Verdrahtung von Komponenten übernimmt (kein Allzweck-DI fw), profitieren Sie von dem, was ich bereits erwähnt habe: Reduzierung der Komplexität und Reduzierung der Arbeit beim Komponententest
Adrian Shum
0

"Wir wollen es einfach halten, wenn möglich einfach alles in eine Baugruppe packen. DI ist eine nicht benötigte Komplexität ohne Nutzen."

Der Vorteil ist, dass es das Entwerfen von Schnittstellen fördert und ein einfaches Verspotten ermöglicht. Dies erleichtert folglich das Testen von Einheiten. Unit-Tests gewährleisten zuverlässigen, modularen und leicht zu wartenden Code. Wenn Ihr Chef immer noch eine schlechte Idee hat, gibt es nichts, was Sie tun können - die anerkannten Best Practices der Branche, gegen die er argumentiert.

Lassen Sie sie versuchen, einen Komponententest mit einem DI-Framework und einer spöttischen Bibliothek zu schreiben. Sie werden es bald lieben lernen.

NimChimpsky
quelle
Ich finde es jetzt nützlich, die Anzahl der Klassen in Ihrem System buchstäblich zu verdoppeln oder zu verdreifachen. Dies ähnelt der Debatte, bei der versucht wird, eine 100% ige Einheitentestabdeckung zu erzielen, indem ein einzelner Test pro Methode oder aussagekräftige Einheitentests geschrieben werden.
Andrew T Finnell
Ich verstehe nicht, Sie denken, Unit-Tests sind eine gute Idee? Wenn ja, verspotten Sie auch Objekte? Dies ist einfacher mit Schnittstellen und DI. Aber das scheint das zu sein, gegen das Sie argumentieren.
NimChimpsky
Es ist wirklich das Huhn- und das Eiproblem. Schnittstellen / DI und Komponententests sind so eng miteinander verbunden, dass es schwierig ist, auf einander zu verzichten. Aber ich glaube, dass Unit-Tests eine bessere und einfachere Möglichkeit sind, um mit einem existierenden Code zu beginnen. Allmählich überarbeiteter Kludgy-Code in zusammenhängende Komponenten. Danach können Sie argumentieren, dass die Objekterstellung mit einem DI-Framework erfolgen sollte, anstatt newüberall zu arbeiten und Factory-Klassen zu schreiben, da alle diese Komponenten vorhanden sind.
Spoike
0

Arbeiten Sie mit diesen Leuten an kleineren Projekten oder nur an einem großen? Es ist einfacher, die Leute davon zu überzeugen, in einem sekundären / tertiären Projekt etwas Neues auszuprobieren, als das Team / die Unternehmen Brot und Butter. Die Hauptgründe dafür sind, dass die Kosten für das Entfernen / Ersetzen viel geringer sind und es viel weniger Arbeit kostet, sie in einem kleinen Projekt überall hin zu bringen. In einer großen bestehenden Klasse haben Sie entweder große Vorlaufkosten, um die Änderung überall auf einmal vorzunehmen, oder einen längeren Zeitraum, in dem der Code eine Mischung aus altem und neuem Ansatz ist und Reibungspunkte schafft, da Sie sich merken müssen, wie jede Klasse gestaltet ist arbeiten.

Dan Neely
quelle
0

Obwohl eines der Dinge, die DI fördern, das Testen von Einheiten ist, glaube ich, dass es in einigen Fällen die Komplexität erhöht.

  • Es ist besser, ein Auto hart im Testen zu haben, aber leicht in der Reparatur als ein Auto, das leicht im Testen und schwer in der Reparatur ist.

  • Auch scheint es mir, dass die Gruppe, die sich für DI einsetzt, ihre Ideen nur präsentiert, indem sie beeinflusst, dass einige existierende Designansätze schlecht sind.

  • wenn wir eine Methode haben, die 5 verschiedene Funktionen ausführt

    DI-People sagt:

    • keine Trennung von Bedenken. [Was ist das Problem davon? Sie versuchen, es schlecht aussehen zu lassen. In Logik und Programmierung ist es viel besser zu wissen, was die anderen genau tun, um Konflikte und falsche Erwartungen besser zu vermeiden und die Auswirkungen von Codeänderungen leicht zu erkennen, da wir nicht alle zum Erfolg führen können Objekte, die nicht zu 100% miteinander verwandt sind oder die wir zumindest nicht garantieren können {es sei denn, warum sind Regressionstests wichtig?}]
    • Komplex [Sie möchten die Komplexität reduzieren, indem sie jeweils fünf weitere Klassen für eine Funktion und eine zusätzliche Klasse (Container) erstellen, um die Klasse für die benötigte Funktion jetzt basierend auf Einstellungen (XML oder Dictionary) zu erstellen. oder nicht "Diskussionen, ...] dann haben sie die Komplexität in den Container und in die Struktur verlagert. ]

Ich glaube, es ist besser, ein eigenes Designmuster zu erstellen, das den Geschäftsanforderungen entspricht, als sich von DI beeinflussen zu lassen.

In manchen Situationen kann es hilfreich sein, DI zu wählen. Wenn Sie beispielsweise Hunderte von Implementierungen für dasselbe Interface haben, hängt dies von einem Selektor ab, und diese Implementierungen unterscheiden sich in der Logik erheblich. In diesem Fall würde ich mich für DI oder DI-ähnliche Techniken entscheiden. Wenn wir jedoch nur wenige Implementierungen für dieselbe Schnittstelle haben, benötigen wir kein DI.

user114367
quelle