Modul erfordert vs Abhängigkeit Injection in Javascript

24

In diesen Tagen tauchte eine Frage in meinem Kopf auf:

Widerspricht die Art und Weise, in der wir Javascript verwenden, fast allem, was in der traditionellen Softwareentwicklung als gute Praxis angesehen wird?

Ich habe eine Reihe von Fragen / Beobachtungen im Zusammenhang mit dieser Aussage, aber um das Format von StackExchange zu respektieren, ist es besser, wenn ich sie in verschiedene Fragen aufteile.

Modul erforderlich

Standard Javascript Code sieht heutzutage so aus:

const someModule = require('./someModule')

module.exports = function doSomethingWithRequest() {
  // do stuff
  someModule.someFunc()
  // do other stuff
}

Vorteile

  • Kapselung: Das Modul arbeitet eigenständig und weiß alles, was es zur Ausführung seiner Funktionen benötigt.
  • Als Kolorist ist es für Kunden einfacher, das Modul zu verwenden.

Nachteile

  • Schlechte Testbarkeit: Dies ist Standard, wenn DI nicht verwendet wird, aber in dynamischen Sprachen wie Javscript kann dies durch Module wie mockeryoder umgangen werden rewire.
  • Es verstößt mit Sicherheit gegen das DIP - nicht zu verwechseln mit Dependency Injection. - da kann ich nur betonmodule importieren.
  • Es verstößt wahrscheinlich gegen das OCP - stellen Sie sich zum Beispiel vor, dass ich ein Protokollmodul habe, das in das Dateisystem schreibt (über das fsModul). Wenn ich dieses Protokollmodul erweitern möchte, um es an das Netzwerk zu senden, wäre es sehr schwierig.

* Dies funktioniert möglicherweise mit CommonJS- oder sogar AMD-Modulen, da diese hauptsächlich im User-Land implementiert sind. Ich bin mir jedoch nicht sicher, wie dies mit der ES6- importSyntax möglich sein könnte .

Abhängigkeitsspritze

Bei Verwendung der Abhängigkeitsinjektion wäre dies eher wie folgt:

module.exports = function doSomethingWithRequest(someModule) {
  // do stuff
  someModule.someFunc()
  // do other stuff
}

Vorteile

  • Verbesserte Testbarkeit: Es ist jetzt someModuleauch mit der ES6-Syntax einfacher, Stubs / Mocks durchzuführen.
  • Es ist möglich , das DIP zu würdigen: nicht unbedingt, da das Client-Modul weiterhin auf die Implementierung und nicht auf eine Schnittstelle programmiert werden kann.

Nachteile

  • Gebrochene Kapselung: Die Hauptfrage lautet:

    Ok, wer erstellt / benötigt dann die Abhängigkeiten?

  • Dies in jedem Client des Moduls zu tun, scheint sehr WET zu sein .
  • Dies würde wahrscheinlich erfordern, dass ich einen DI-Container verwende, um in einem realen Projekt realisierbar zu sein.

Die eigentliche Frage lautet also:

Warum neigen Javascript-Entwickler dazu, sich dem ersten Ansatz zuzuwenden?

Ist das nur "der Javascript-Weg"?

Ich selbst schreibe die meiste Zeit Code wie diesen. Ich hatte einen guten Teil des Testaufbaus mit spöttischen Bibliotheken, aber es fühlte sich immer irgendwie falsch an.

Vermisse ich etwas?

Henrique Barcelos
quelle
Als ein .Net-Typ, der sich kürzlich für NodeJs interessiert hat, habe ich auch damit zu kämpfen. Ich habe festgestellt, dass das Patchen von Affenabhängigkeiten mit Proxyquire (ähnlich wie bei ReWire) zu Testzwecken in Ordnung ist, aber manchmal muss eine Abhängigkeit
wirklich

Antworten:

6

Ich bin hauptsächlich ein PHP-Programmierer, habe aber im letzten Jahr Kontakt zu 4 JavaScript-Teams.

Als objektorientierter Programmierer scheint das Prinzip der Abhängigkeitsinjektion der beste Weg zu sein, was mir jedoch von wenigen JS-Entwicklern anders gesagt wurde. JS ist eine ganz andere Welt.

Da Sie mit JavaScript alles und jeden mit sehr einfachen Techniken patchen können, haben JavaScript-Entwickler gelernt, eine andere Technologie zum Erstellen von JavaScript-Anwendungen in größerem Maßstab anzupassen. Die meisten dieser Module bestehen aus eigenständigen Modulen, die die Funktionalität durch öffentliche Exporte offenlegen und die Interna des Moduls verbergen, damit andere die Funktionen, auf die Sie sich verlassen, nicht umschreiben können.

Der übliche Ansatz besteht darin, nicht einmal einen Konstruktor zu exponieren, sondern die Konstruktion eines Objekts mit einem Factory-Wrapper zu exponieren - aus genau dem gleichen Grund: Wenn Sie jemandem Zugriff auf ein Objekt gewähren, können sie diese direkt instanziieren dürfen nichts ändern.

Indem Sie den modularen Aufbau nutzen, können andere nicht mit Ihren Funktionen experimentieren, die Sie voraussichtlich verwenden, aber Sie können Ihre Module dennoch testen - über die öffentliche API der erforderlichen Datei, die von Ihnen erstellte API.

Andy
quelle