Sollte ich Dependency Injection und IoC vermeiden?

8

In meinem mittelgroßen Projekt verwendete ich statische Klassen für Repositories, Dienste usw. und es funktionierte wirklich sehr gut, selbst wenn die meisten Programmierer das Gegenteil erwarten würden. Meine Codebasis war sehr kompakt, sauber und leicht zu verstehen. Jetzt habe ich versucht alles neu zu schreiben und IoC (Invertion of Control) zu benutzen und ich war absolut enttäuscht. Ich muss Dutzende von Abhängigkeiten in jeder Klasse, Controller usw. manuell initialisieren, mehr Projekte für Schnittstellen hinzufügen und so weiter. Ich sehe wirklich keine Vorteile in meinem Projekt und es scheint, dass es mehr Probleme als Lösungen verursacht. Ich habe die folgenden Nachteile in IoC / DI :

gefunden
  • viel größere Codesize
  • Ravioli-Code statt Spaghetti-Code
  • langsamere Leistung, müssen alle Abhängigkeiten im Konstruktor initialisiert werden, selbst wenn die Methode, die ich aufrufen möchte, nur eine Abhängigkeit hat
  • schwerer zu verstehen, wenn keine IDE verwendet wird
  • einige Fehler werden zur Laufzeit verschoben
  • Hinzufügen zusätzlicher Abhängigkeit (DI-Framework selbst)
  • neue Mitarbeiter müssen zuerst DI lernen, um damit zu arbeiten
  • viel Vortex-Code, der für kreative Leute schlecht ist (zum Beispiel Instanzen vom Konstruktor in Eigenschaften kopieren ...)

Wir testen nicht die gesamte Codebasis, sondern nur bestimmte Methoden und verwenden echte Datenbanken. Sollte also Dependency Injection vermieden werden, wenn für das Testen keine Spottmaßnahmen erforderlich sind?

    
Mark Smith 21.09.2016, 20:39
quelle

6 Antworten

14

Die meisten Ihrer Bedenken scheinen auf Missbrauch oder Missverständnis zurückzuführen zu sein.

  • viel größere Codesize

    Dies ist in der Regel ein Ergebnis, wenn sowohl das Prinzip der einfachen Verantwortung als auch das Prinzip der Schnittstellentrennung eingehalten werden. Ist es drastisch größer? Ich vermute, nicht so groß wie du behauptet hast. Was es tut, ist jedoch höchstwahrscheinlich, Klassen auf bestimmte Funktionalität zu reduzieren, anstatt "Catch-All" -Klassen zu haben, die alles und jeden tun. In den meisten Fällen ist dies ein Zeichen für eine gesunde Trennung von Sorgen, kein Problem.

  • Ravioli-Code statt Spaghetti-Code

    Auch hier ist es sehr wahrscheinlich, dass Sie eher in Stapeln als in schwer erkennbaren Abhängigkeiten denken. Ich denke, das ist ein großer Vorteil, da es zu einer korrekten Abstraktion und Verkapselung führt.

  • langsamere Leistung Verwenden Sie einfach einen schnellen Container. Meine Favoriten sind SimpleInjector und LightInject.

  • müssen alle Abhängigkeiten im Konstruktor even initialisieren wenn die Methode, die ich aufrufen möchte, nur eine Abhängigkeit hat

    Auch dies ist ein Zeichen dafür, dass Sie gegen das Prinzip der einfachen Verantwortung verstoßen. Das ist eine gute Sache, weil es Sie zwingt, logisch durch Ihre Architektur zu denken, anstatt Willy-Nilly hinzuzufügen.

  • schwerer zu verstehen, wenn keine IDE verwendet wird, werden einige Fehler zur Laufzeit

    übertragen

    Wenn Sie immer noch keine IDE verwenden, schämen Sie sich. Dafür gibt es kein Argument mit modernen Maschinen. Darüber hinaus werden einige Container (SimpleInjector) bei der ersten Ausführung validiert, wenn Sie dies wünschen. Sie können dies leicht mit einem einfachen Komponententest erkennen.

  • Hinzufügen zusätzlicher Abhängigkeit (DI-Framework selbst)

    Du musst deine Schlachten auswählen und auswählen. Wenn die Kosten für das Erlernen eines neuen Rahmens geringer sind als die Kosten für die Pflege von Spaghetti-Code (und ich vermute, dass dies der Fall sein wird), dann sind die Kosten gerechtfertigt.

  • neue Mitarbeiter müssen zuerst DI lernen, um damit zu arbeiten

    Wenn wir uns vor neuen Mustern scheuen, wachsen wir nie. Ich betrachte dies als eine Gelegenheit, dein Team zu bereichern und zu vergrößern, nicht als eine Möglichkeit, sie zu verletzen. Der Kompromiss besteht darin, den Spaghetti-Code zu lernen, der viel schwieriger sein könnte, als ein branchenweites Muster aufzugreifen.

  • eine Menge Standardcode, der für kreative Leute schlecht ist (z. B. Instanzen vom Konstruktor in Eigenschaften kopieren ...)

    Das ist einfach falsch. Obligatorische Abhängigkeiten sollten immer über den Konstruktor übergeben werden. Nur optionale Abhängigkeiten sollten über Eigenschaften festgelegt werden, und das sollte nur unter sehr speziellen Umständen geschehen, da es oft das Prinzip der einfachen Verantwortlichkeit verletzt.

  • Wir testen nicht die gesamte Codebasis, sondern nur bestimmte Methoden und verwenden eine echte Datenbank. Sollte also Dependency Injection vermieden werden, wenn für das Testen keine Mocking benötigt wird?

    Ich denke, das könnte das größte Missverständnis von allen sein. Die Abhängigkeitsinjektion ist NICHT einfach, um das Testen zu erleichtern. So können Sie einen Blick auf die Signatur eines Klassenkonstruktors werfen und IMMEDIATELY wissen, was erforderlich ist, um diese Klasse zu aktivieren. Dies ist bei statischen Klassen nicht möglich, da Klassen den Stack beliebig oft auf und ab aufrufen können, ohne zu reimen. Ihr Ziel sollte sein, Ihrem Code Konsistenz, Klarheit und Unterscheidung zu verleihen. Dies ist der wichtigste Grund für die Verwendung von DI und deshalb empfehle ich Ihnen dringend, es erneut zu besuchen.

David L 21.09.2016, 21:11
quelle
10

Obwohl IoC / DI kein Wundermittel ist, das in allen Fällen funktioniert, ist es möglich, dass Sie es nicht korrekt angewendet haben. Die Menge der Prinzipien hinter Dependency Injection braucht Zeit, um es zu meistern, oder zumindest hat es sicher für mich getan. Wenn richtig angewendet, kann es (unter anderem) die folgenden Vorteile bringen:

  • Verbesserte Testbarkeit
  • Verbesserte Flexibilität
  • Verbesserte Wartbarkeit
  • Verbesserte parallele Entwicklung

Aus Ihrer Frage kann ich bereits einige Dinge extrahieren, die in Ihrem Fall schiefgelaufen sein könnten:

  

Ich muss Dutzende von Abhängigkeiten in jeder Klasse manuell initialisieren

Dies bedeutet, dass jede Klasse, die Sie erstellen, dafür verantwortlich ist, die erforderlichen Abhängigkeiten zu erstellen. Dies ist ein Anti-Pattern, bekannt als Control Freak . Eine Klasse sollte%% ihre Abhängigkeiten nicht selbst erhöhen. Möglicherweise haben Sie sogar das Service Locator-Anti-Pattern angewendet, in dem Ihre Klasse ihre Abhängigkeiten durch Aufruf anfordert der Container (oder eine Abstraktion, die den Container darstellt), um eine bestimmte Abhängigkeit zu erhalten. Eine Klasse sollte nur die Abhängigkeiten definieren, die sie als Konstruktorargumente benötigt.

  

Dutzend von Abhängigkeiten

Diese Aussage impliziert, dass Sie das Prinzip der einheitlichen Verantwortlichkeit verletzen. Dies ist eigentlich nicht an IoC / DI gekoppelt, Ihr alter Code hat wahrscheinlich bereits das Single-Responsibility-Prinzip verletzt, wodurch es für andere Entwickler schwer zu verstehen und zu pflegen ist. Es ist oft schwer für den ursprünglichen Autor zu verstehen, warum andere es schwer haben, Code zu pflegen, da das, was Sie geschrieben haben, oft gut in Ihren Kopf passt. Häufig führt die Verletzung der SRP dazu, dass andere Probleme haben, Code zu verstehen und zu pflegen. Und das Testen von Klassen, die SRP verletzen, ist oft noch schwieriger. Eine Klasse sollte höchstens ein halbes Dutzend Abhängigkeiten haben.

  

fügen Sie weitere Projekte für Schnittstellen usw. hinzu

Dies bedeutet, dass Sie gegen das Prinzip der wiederverwendeten Abstraktion verstoßen. Im Allgemeinen sollte die Mehrheit der Komponenten / Klassen in Ihrer Anwendung durch ein Dutzend Abstraktionen abgedeckt sein. Zum Beispiel, alle Klassen, die einige Anwendungsfälle implementieren, verdienen wahrscheinlich eine einzige (generische) Abstraktion . Klassen, die Abfragen implementieren verdienen auch eine Abstraktion . Für die Systeme, die ich schreibe, sind 80% bis 95% meiner Komponenten (Klassen, die das Verhalten der Anwendung enthalten) von 5 bis 12 (meist generischen) Abstraktionen abgedeckt. Meistens müssen Sie kein neues Projekt nur für die Schnittstellen erstellen. Die meiste Zeit lege ich diese Schnittstellen in die Wurzel des gleichen Projekts.

  

viel größere Codesize

Die Menge an Code, die Sie schreiben, wird anfangs nicht sehr unterschiedlich sein. Die Praxis von Dependency Injection funktioniert jedoch nur dann, wenn SOLID angewendet wird, und SOLID fördert wenig fokussiert Klassen. Klassen mit einer einzigen Verantwortung. Dies bedeutet, dass Sie viele kleine Klassen haben werden, die einfach zu verstehen und einfach in flexible Systeme zu komponieren sind. Und vergessen Sie nicht: Wir sollten uns nicht bemühen, weniger Code zu schreiben, sondern mehr wartbaren Code.

Aber mit einem guten SOLID-Design und den richtigen Abstraktionen habe ich tatsächlich viel weniger Code schreiben müssen als zuvor. Zum Beispiel kann die Anwendung bestimmter bereichsübergreifender Probleme (wie Protokollierung, Audit-Trailing, Autorisierung usw.) angewendet werden, indem einfach einige Codezeilen in die Infrastrukturschicht der Anwendung geschrieben werden, anstatt dass sie über den gesamten Bereich verteilt werden Anwendung. Es hat mich sogar dazu gebracht, Dinge zu tun, die zuvor nicht möglich waren, weil sie mich dazu zwangen, umfassende Änderungen in der gesamten Codebasis vorzunehmen, was so zeitaufwendig war, dass das Management mir das nicht erlaubte.

  

Ravioli-Code statt Spaghetti-Code   schwerer zu verstehen, wenn keine IDE verwendet wird

Das ist irgendwie wahr. Dependency Injection fördert das Entkoppeln von Klassen voneinander. Dies kann es manchmal schwieriger machen, zu einer Codebasis zu navigieren, da eine Klasse normalerweise von einer Abstraktion anstatt von konkreten Klassen abhängt. In der Vergangenheit fand ich die Flexibilität, dass DI die Kosten überwiegt, um die Implementierung zu finden. Mit Visual Studio 2015 kann ich einfach STRG + F12 verwenden, um die Implementierungen einer Schnittstelle zu finden. Wenn es nur eine Implementierung gibt, springt Visual Studio direkt zu dieser Implementierung.

  

langsamere Leistung

Das ist nicht wahr. Die Leistung muss nicht anders sein als das Arbeiten mit einer Codebasis von nur statischen Methodenaufrufen. Sie wählen jedoch Ihre Klassen mit einem transienten Lebensstil, was bedeutet, dass Sie neue Instanzen überall auf dem Platz. In meinen letzten Anwendungen habe ich alle meine Klassen nur einmal pro Anwendung erstellt, was ungefähr die gleiche Leistung bringt wie nur statische Methodenaufrufe, aber mit dem Vorteil, dass die Anwendung sehr flexibel und wartbar ist. Beachten Sie jedoch, dass, selbst wenn Sie sich dazu entschließen, Grafiken mit Objekten für jede (Web-) Anfrage zu vervollständigen, die Leistungskosten wahrscheinlich um Größenordnungen niedriger sein werden als bei allen I / O (Datenbank-, Dateisystem- und Web-Service-Aufrufen) führen Sie während dieser Anfrage auch mit den langsamsten DI-Containern aus.

  

Einige Fehler werden zur Laufzeit übertragen   Hinzufügen zusätzlicher Abhängigkeit (DI-Framework selbst)

Diese Probleme beinhalten die Verwendung einer DI-Bibliothek. DI-Bibliotheken erstellen zur Laufzeit Objekte. Eine DI-Bibliothek ist jedoch nicht , wenn Sie Dependency Injection durchführen. Kleine Anwendungen können davon profitieren, Dependency Injection ohne ein Tool zu verwenden. eine Praxis namens Pure DI . Ihre Anwendung profitiert möglicherweise nicht von der Verwendung eines DI-Containers, aber die meisten Anwendungen profitieren von der Verwendung von Dependency Injection (wenn sie korrekt verwendet werden) als eine Praxis. Againt: Werkzeuge sind optional, schreibbarer Code ist nicht.

Aber selbst wenn Sie eine DI-Bibliothek verwenden, gibt es Bibliotheken mit eingebauten Tools, mit denen Sie Ihre Konfiguration überprüfen und diagnostizieren können. Sie bieten keine Unterstützung für die Kompilierungszeit, aber sie ermöglichen Ihnen, diese Analyse entweder beim Start der Anwendung oder mithilfe eines Komponententests auszuführen. Dies verhindert, dass Sie eine Regression für die gesamte Anwendung durchführen, nur um zu überprüfen, ob Ihr Container richtig verdrahtet ist. Ich rate, einen DI-Container auszuwählen, der Ihnen hilft, diese Konfigurationsfehler zu erkennen.

  

neue Mitarbeiter müssen zuerst DI lernen, um damit zu arbeiten

Das ist richtig, aber Dependency Injection selbst ist nicht wirklich schwer zu lernen. Was eigentlich schwer zu erlernen ist, ist, die SOLID-Prinzipien korrekt anzuwenden, und Sie müssen dies trotzdem lernen, wenn Sie Anwendungen schreiben möchten, die von mehr als einem Entwickler über einen längeren Zeitraum gewartet werden müssen. Ich investiere lieber in die Entwicklung der Entwickler in meinem Team, um SOLID-Code zu schreiben, anstatt sie nur Code austoben zu lassen. das wird sicherlich später eine Wartung Hölle verursachen.

  

eine Menge Boilerplate-Code

Es gibt einige Codebeispiele, wenn wir uns den in C # 6 geschriebenen Code ansehen, aber das ist nicht wirklich so schlimm, besonders wenn man die Vorteile betrachtet, die es bietet. Und zukünftige Versionen von C # werden das Boilerplate entfernen, das hauptsächlich dadurch verursacht wird, dass Konstruktoren definiert werden müssen, die Argumente übernehmen, die auf Null geprüft und privaten Variablen zugewiesen sind. C # 7 oder 8 wird dies sicher beheben, wenn Datensatztypen und nicht nullable Referenztypen eingeführt werden.

  

was schlecht für kreative Leute ist

Es tut mir leid, aber dieses Argument ist einfacher Schwachsinn. Ich habe gesehen, dass dieses Argument immer wieder als Ausrede benutzt wurde, um schlechten Code von Entwicklern zu schreiben, die sich nicht über Designmuster und Software-Prinzipien und -Praktiken informieren wollten. Kreativ zu sein, ist keine Entschuldigung dafür, Code zu schreiben, den kein anderer verstehen oder programmieren kann, was unmöglich zu testen ist. Wir müssen akzeptierte Muster und Praktiken anwenden und innerhalb dieser Grenze ist genug Platz, um kreativ zu sein, während man guten Code schreibt. Code schreiben ist keine Kunst; es ist ein Handwerk.

Wie ich schon sagte, DI ist nicht in allen Fällen angemessen, und die Praktiken darum brauchen Zeit, um sie zu meistern. Ich kann Ihnen raten, das Buch Dependency Injection in .NET von Mark Seemann zu lesen; es wird viele Antworten geben und Ihnen einen guten Sinn dafür geben, wie und wann es anzuwenden ist und wann nicht.

    
Steven 21.09.2016 21:49
quelle
1

Es gibt viele "Lehrbuch" Argumente für die Verwendung von IoC, aber nach meiner persönlichen Erfahrung sind / sind die Vorteile:

Möglichkeit, nur Teile des Projekts zu testen und einige andere Teile zu verspotten . Wenn Sie zum Beispiel eine Komponente haben, die die Konfiguration von der DB zurückgibt, ist es einfach, sie zu verspotten, so dass Ihr Test ohne eine echte DB funktionieren kann. Mit statischen Klassen ist das nicht möglich.

Bessere Sichtbarkeit und Kontrolle von Abhängigkeiten . Mit den statischen Klassen ist es sehr einfach, einige Abhängigkeiten hinzuzufügen, ohne es zu bemerken, was später Probleme verursachen kann. Mit IoC ist dies expliziter und sichtbarer.

Explizitere Initialisierungsreihenfolge . Bei statischen Klassen kann dies oft eine Black Box sein, und es können latente Probleme aufgrund der zirkulären Verwendung auftreten.

Die einzige Unannehmlichkeit für mich war, dass es nicht möglich ist, direkt von der Verwendung (F12) zu der Implementierung zu navigieren, indem Sie alles vor den Schnittstellen platzieren.

Allerdings sind es die Entwickler eines Projekts, die im Einzelfall die Vor- und Nachteile am besten beurteilen können.

    
Adam Rotaru 21.09.2016 21:02
quelle
1

Gab es einen Grund, warum Sie sich nicht für eine IOC-Bibliothek entschieden haben (StructureMap, Ninject, Autofac usw.)? Die Verwendung von diesen hätte Ihr Leben viel einfacher gemacht.

  

Obwohl David L bereits eine ausgezeichnete Reihe von Kommentaren zu Ihren Punkten gemacht hat, werde ich auch meine eigenen hinzufügen.

Viel größere Codesize

Ich bin mir nicht sicher, wie Sie zu einer größeren Codebasis gekommen sind. Das typische Setup für eine IOC-Bibliothek ist ziemlich klein, und da Sie Ihre Invarianten (Abhängigkeiten) in den Klassenkonstruktoren definieren, entfernen Sie auch etwas Code (dh das "neue xyz ()" Zeug), das Sie nicht brauchen mehr.

Ravioli-Code statt Spaghetti-Code

Ich mag Ravioli ganz ähnlich:)

Langsamere Performance, alle Abhängigkeiten im Konstruktor müssen initialisiert werden, auch wenn die Methode, die ich aufrufen möchte, nur eine Abhängigkeit hat

Wenn Sie dies tun, verwenden Sie Dependency Injection überhaupt nicht. Sie sollten vorgefertigte, vollständig geladene Objektgraphen über die in den Konstruktorparametern der Klasse selbst deklarierten Abhängigkeitsargumente erhalten - sie nicht im Konstruktor erzeugen! Die meisten modernen IOC-Bibliotheken sind lächerlich schnell und werden niemals ein Leistungsproblem sein. Hier ist ein gutes Video, das den Punkt beweist.

Schwieriger zu verstehen, wenn keine IDE verwendet wird

Das stimmt, aber es bedeutet auch, dass Sie die Gelegenheit nutzen können, in Abstraktionen zu denken. So können Sie beispielsweise einen Code ansehen

%Vor%

Wenn Sie sich diesen Code ansehen und versuchen herauszufinden, ob er funktioniert oder ob es die Ursache eines Problems ist, können Sie die tatsächliche IFrobber -Implementierung ignorieren; es repräsentiert nur die abstrakte Fähigkeit von Frob, und Sie müssen nicht mental mitnehmen, wie ein bestimmter Frobber seine Arbeit machen könnte. Sie können sich darauf konzentrieren, sicherzustellen, dass diese Klasse das tut, was sie tun soll - nämlich etwas Arbeit an einen Frobber irgendeiner Art zu delegieren.

Beachten Sie auch, dass Sie nicht brauchen, um hier Schnittstellen zu verwenden; Sie können auch konkrete Implementierungen erstellen. Das tendiert jedoch dazu, das Prinzip der Abhängigkeitsinversion zu verletzen (das nur tangential mit der DI in Verbindung steht, über die wir hier sprechen), weil es die Klasse zwingt, sich auf eine Konkretion statt auf eine Abstraktion zu verlassen.

Einige Fehler werden zur Laufzeit verschoben

Nicht mehr oder weniger als beim manuellen Konstruieren von Graphen im Konstruktor;

Zusätzliche Abhängigkeit hinzufügen (DI-Framework selbst)

Das stimmt auch, aber die meisten IOC-Bibliotheken sind ziemlich klein und unaufdringlich, und irgendwann müssen Sie entscheiden, ob der Kompromiss, ein etwas größeres Produktionsartefakt zu haben, es wert ist (ist es wirklich)

Neue Mitarbeiter müssen zuerst DI lernen, um damit arbeiten zu können

Das ist nicht wirklich anders als das bei jeder neuen Technologie der Fall wäre :) Wenn man lernt, eine IOC-Bibliothek zu benutzen, öffnet sich der Geist für andere Möglichkeiten wie TDD, die SOLID-Prinzipien und so weiter, was niemals schlecht ist Ding!

Viel Vortex-Code, der für kreative Leute schlecht ist (zum Beispiel Instanzen vom Konstruktor in Eigenschaften kopieren ...)

Ich verstehe das nicht, wie Sie mit viel Vortex-Code enden könnten; Ich würde nicht zählen, die gegebenen Abhängigkeiten in privaten readonly-Mitgliedern zu speichern, über die es sich zu reden lohnt - bedenkt man, dass wenn Sie mehr als 3 oder 4 Abhängigkeiten pro Klasse haben, Sie wahrscheinlich gegen die SRP verstoßen und Ihr Design überdenken sollten.

Wenn Sie schließlich von keinem der hier vorgebrachten Argumente überzeugt sind, würde ich Ihnen trotzdem empfehlen, Mark Seemans "Abhängigkeit" zu lesen Injektion in .Net ". (oder in der Tat alles andere, was er auf DI zu sagen hat, das Sie auf seinem Blog finden können). Ich verspreche dir, dass du einige nützliche Dinge lernen wirst und ich kann dir sagen, dass es die Art und Weise verändert hat, wie ich Software zum Besseren schreibe.

    
Stephen Byrne 21.09.2016 21:30
quelle
1

Sei gewarnt: Ich hasse IoC.

Hier gibt es viele gute Antworten, die beruhigend sind. Die Hauptvorteile laut Steven (sehr starke Antwort) sind:

  
  • Verbesserte Testbarkeit
  •   
  • Verbesserte Flexibilität
  •   
  • Verbesserte Wartbarkeit
  •   
  • Verbesserte Skalierbarkeit
  •   

Meine Erfahrungen sind sehr unterschiedlich durch, hier sind sie für etwas Gleichgewicht:

(Bonus) Dunkles Repository-Muster

Zu oft ist dies zusammen mit IoC enthalten. Das Repository-Muster sollte nur für den Zugriff auf externe Daten verwendet werden, und die Austauschbarkeit ist eine Kernerwartung.

Wenn Sie dies mit Entity Framework verwenden, deaktivieren Sie die gesamte Leistungsfähigkeit von Entity Framework, dies geschieht auch mit Service-Layern.

z. Aufruf:

%Vor%

Es sollte sein:

%Vor%

In diesem Fall mit Erweiterungsmethoden.

Wer braucht Flexibilität?

Wenn Sie keine Service-Implementierungen ändern möchten, brauchen Sie sie nicht. Wenn Sie denken, dass Sie in Zukunft mehr als eine Implementierung haben werden, fügen Sie vielleicht IoC hinzu, und nur für diesen Teil.

Aber "Testability"!

Entity Framework (und wahrscheinlich auch andere ORMs) ermöglichen es Ihnen, die Verbindungszeichenfolge so zu ändern, dass sie auf eine speicherinterne Datenbank verweist. Zugegeben, das ist erst ab EF7 möglich. Es kann jedoch einfach eine neue (geeignete) Testdatenbank in einer Staging-Umgebung sein.

Haben Sie andere spezielle Testressourcen und Servicepunkte? In der heutigen Zeit sind sie wahrscheinlich verschiedene WebService-URI-Endpunkte, die auch in App.Config / Web.Config konfiguriert werden können.

Automatisierte Tests machen Ihren Code wartbar

TDD - Wenn es sich um eine Webanwendung handelt, verwenden Sie Jasmine oder Selenium und führen Sie automatisierte Verhaltenstests durch. Dies testet alles bis zum Benutzer. Es ist eine Investition im Laufe der Zeit, beginnend mit der Abdeckung kritischer Merkmale und Funktionen.

DevOps / SysOps - Pflegen Sie Skripte für die Bereitstellung Ihrer gesamten Umgebung (dies ist auch die beste Vorgehensweise), erstellen Sie eine Staging-Umgebung und führen Sie alle Tests aus. Sie können Ihre Produktionsumgebung auch klonen und dort Ihre Tests durchführen. Machen Sie nicht "wartbar" und "testbar" Ihre Entschuldigung für die Wahl von IoC. Beginnen Sie mit diesen Anforderungen und finden Sie die besten Möglichkeiten, diese Anforderungen zu erfüllen.

Skalierbarkeit - auf welche Weise?

(Ich muss wahrscheinlich das Buch lesen)

  • Für die Skalierbarkeit von Codern ist die Versionskontrolle mit verteilter Code die Norm (obwohl ich die Zusammenführung hasse).
  • Für die Skalierbarkeit der Personalressourcen sollten Sie keine Tage verschwenden, um zusätzliche abstrakte Ebenen für Ihr Projekt zu erstellen.
  • Für die gleichzeitige Skalierbarkeit von Produktionskunden sollten Sie bauen, testen und dann verbessern.
  • Für die Skalierbarkeit des Serverdurchsatzes müssen Sie viel höher denken als IoC. Werden Sie einen Server im Kunden-LAN betreiben? Können Sie Ihre Daten replizieren? Replizieren Sie auf Datenbank- oder Anwendungsebene? Ist der Offline-Zugriff wichtig, während er mobil ist? Dies sind wesentliche Architekturfragen, bei denen IoC selten die Antwort ist.

Versuchen Sie F12

Wenn Sie eine IDE verwenden (was Sie tun sollten), z. B. Visual Studio Community Edition, dann wissen Sie, wie nützlich F12 sein kann, um Code zu navigieren.

Mit IoC werden Sie zur Benutzeroberfläche geleitet, und Sie müssen dann alle Referenzen finden, die eine bestimmte Schnittstelle verwenden. Nur ein zusätzlicher Schritt, aber für ein Werkzeug, das so viel benutzt wird, frustriert es mich.

Steven ist am Ball

  

Mit Visual Studio 2015 kann ich einfach STRG + F12 drücken, um das zu finden   Implementierungen einer Schnittstelle.

Ja, aber Sie müssen dann eine Liste der beiden Gebräuche sowie die Erklärung durchblättern. (Eigentlich denke ich, in der neuesten VS, die Erklärung separat aufgeführt, aber es ist immer noch ein extra Mausklick, die Hände von der Tastatur. Und ich sollte sagen, das ist eine Einschränkung von Visual Studio, nicht in der Lage, Sie zu einem einzigen zu nehmen Schnittstellenimplementierung direkt.

    
Todd 17.12.2016 11:01
quelle
0

Wenn Sie Abhängigkeiten manuell im Code initialisieren müssen, tun Sie etwas falsch. Generelles Muster für IoC ist die Konstruktorinjektion oder wahrscheinlich die Eigenschafteninjektion. Klasse oder Controller sollten überhaupt nichts über den DI-Container wissen.

Im Allgemeinen müssen Sie nur Folgendes tun:

  1. configure container, wie Interface = Class in Singleton scope
  2. Benutze es wie Controller(Interface interface) {}
  3. Profitieren Sie von der Kontrolle aller Abhängigkeiten an einem Ort

Ich sehe keinen Standardcode oder eine langsamere Leistung oder irgendetwas anderes, das Sie beschrieben haben. Ich kann nicht wirklich darstellen, wie man mehr oder weniger komplexe App ohne es schreibt.

Aber im Allgemeinen müssen Sie entscheiden, was wichtiger ist. Um "kreative Menschen" zufrieden zu stellen oder eine wartbare und robuste App zu erstellen.

Übrigens, um eine Eigenschaft oder ein Feld vom Konstruktor zu erstellen, können Sie Alt+Enter in R # verwenden, und es erledigt alle Aufgaben für Sie.

    
Traveler 21.09.2016 20:48
quelle