it-swarm.com.de

Das Umschließen von Bibliotheken von Drittanbietern ist eine bewährte Methode

Beim Lesen des Clean Code book von Robert C. Martin stieß ich auf folgende Aussagen.

Kapitel: 7: Fehlerbehandlung
Seite Nr.: 109
.. Tatsächlich ist das Umschließen von APIs von Drittanbietern eine Best Practice . Wenn Sie eine Drittanbieter-API einschließen, minimieren Sie Ihre Abhängigkeiten davon: Sie können in Zukunft ohne große Nachteile in eine andere Bibliothek wechseln. Wrapping erleichtert auch das Verspotten von Anrufen von Drittanbietern, wenn Sie Ihren eigenen Code testen.

Ein letzter Vorteil des Wrappings besteht darin, dass Sie nicht an die API-Designoptionen eines bestimmten Anbieters gebunden sind. Sie können eine API definieren, mit der Sie sich wohl fühlen.

Ich bin ziemlich verwirrt über den Teil fett.

Ich bin völlig ahnungslos, wie wir so einfach zu einer anderen Bibliothek wechseln können, wenn wir die Bibliothek eines Drittanbieters einpacken, und wie das Testen damit einfach wird.

11
CoderCroc

Stellen Sie sich vor, Sie haben eine komplizierte Bibliothek, auf die Sie angewiesen sind. Angenommen, die Bibliothek stellt ihrer Funktionalität vier verschiedene Aufrufe zur Verfügung, und Ihre Codebasis verwendet jeden von ihnen dreimal.

Wenn Sie die Raw-Vendor-API in Ihrem Code verwenden, müssen Sie zwölf API-Aufrufe in Ihrer Codebasis ändern, wenn sich die Vendor-Bibliothek ändert oder Sie sie ersetzen müssen. Wenn Sie eine Abstraktionsschicht zwischen Ihrem Code und dessen Code hätten, müssten Sie vier Stellen in der Abstraktionsschicht und keine überhaupt in Ihrer Codebasis ändern. Sie sehen, dass dies Aufwand spart - je mehr Aufwand desto mehr Aufrufe bietet die API. Die meisten realen APIs bieten mehr als vier Einstiegspunkte.

19
Kilian Foth

Berücksichtigen Sie neben der sehr guten Antwort von Killian Foth einige Probleme beim Testen von Code, der APIs verwendet:

  • Testen ist schwierig, weil die API etwas "Reales" macht. Stellen Sie sich vor, Sie möchten Ihren Code testen, der eine API verwendet, die eine Kreditkartenzahlung vornimmt. Wenn jedes Mal, wenn Sie Ihren Code ausführen, dies zu einer echten Transaktion führt, ist dies eine große Einschränkung für Ihre Tests.
  • Das Testen ist schwierig, da Sie die von der API zurückgegebenen Informationen nicht steuern können.
    • Ihr Code soll an Weihnachten etwas Besonderes tun, aber die API gibt nur das aktuelle Datum zurück. Warten Sie bis Weihnachten, um diese Funktion zu testen?
    • Sie möchten den Umgang mit einer Million E-Mail-Adressen testen, diese stammen jedoch von einer externen Plattform mit nur wenigen Testbenutzern. Eine Million Testbenutzer manuell zu dieser Plattform hinzufügen?
    • Ihr Code verwendet eine Telefon-GPS-API, um den aktuellen Standort abzurufen und die Sprache entsprechend einzustellen. Müssen Sie tatsächlich in verschiedene Länder reisen, um zu sehen, ob dies funktioniert?

Es könnten noch viele weitere Beispiele erstellt werden, aber Sie haben die Idee. Alle diese Probleme werden durch mschließen der API gelöst. Anschließend können Sie die eigentliche API durch eine Test-API ersetzen, die zu Testzwecken alles zurückgibt, was Sie möchten.

16
user82096

Sie haben Recht, misstrauisch zu sein. Ich habe dieses Buch nicht gelesen, aber ich persönlich bin mit diesem Rat nicht einverstanden.

Dieser Ansatz fügt sowohl zusätzlichen Code als auch zusätzliche Abtraktion hinzu.

Code kann Fehler und Overhead hinzufügen.

Abstraktionen haben ihre Grenzen, und der arme Betreuer muss jetzt sowohl die Bibliothek als auch die Abstraktion verstehen, um seine Arbeit zu erledigen.

Die Abstraktion ist schwierig: Entweder ahmen Sie die zugrunde liegende Bibliotheks-API fast 1: 1 nach, und zu diesem Zeitpunkt ist diese "Abstraktion" keine mehr. Oder Sie erstellen Ihre eigene API, die sicherlich nicht mit dem Design der von Ihnen verwendeten Bibliothek oder mit der zukünftigen Bibliothek übereinstimmt, die Sie in Zukunft verwenden möchten. In der Codebasis, an der ich gerade arbeite, gibt es eine solche Abstraktion über den von uns verwendeten XML-Parser. Wir haben ein bekanntes Leistungsproblem, bei dem die Abstraktion eine Liste aller Knoten führen und diese immer wieder durchlaufen muss, um die API der Abstraktion zu erfüllen. Es ist mehr als 10 Jahre her, dass wir von dieser speziellen Drittanbieter-Bibliothek abhängig sind, und wir hatten nie die Notwendigkeit, sie zu ändern. Das Entfernen dieser schrecklichen Abstration steht auf meiner Aufgabenliste ...

Das Ersetzen von Bibliotheken von Drittanbietern ist eine Ausnahme und nicht die Regel. In diesem Rat werden Sie gebeten, im Voraus einige Arbeiten mit allen oben genannten Nachteilen für einen Fall durchzuführen, der unwahrscheinlich ist.

Über den Teil "Verspotten von Anrufen an Drittanbieter-Bibliotheken" kann ich mir keinen Fall vorstellen, in dem ich eine Bibliothek verspotten musste. Ich bin hier vielleicht ein bisschen kurzsichtig.

12
barjak

Ich habe das Gefühl, dass diese Praxis oft schlecht angewendet werden kann.

Angenommen, Sie verwenden den MongoDB-Client, um auf Ihre Mongo-Datenbank zuzugreifen. Es ist ziemlich schwierig, den Client selbst zu verpacken, während alle Funktionen offengelegt werden. Sie müssen ein Abfrageobjekt implementieren und es in das entsprechende Objekt usw. umwandeln. Es ist eine Menge Arbeit, und wenn Sie den Client später ändern, werden Sie möglicherweise feststellen, dass das neue einem völlig anderen Muster folgt und Ihre Schnittstellen und Wrapper-Klassen dies sind nicht mehr angemessen.

Sie möchten jedoch in der Lage sein, verspottete Objekte usw. zum Testen zu injizieren und im Allgemeinen zu vermeiden, dass andere Dinge von der Bibliothek der dritten Partei abhängig gemacht werden.

Dies kann immer noch erreicht werden, wenn Sie auf einer höheren Ebene umbrechen, beispielsweise nach dem Repository-Muster. Durch das Umschließen auf dieser höheren Ebene müssen Sie sich nicht mit allen Details der Drittanbieter-Bibliothek befassen und können eine eingeschränkte und konstante Schnittstelle bereitstellen, die für Ihren Code relevant ist, und nicht den externen Code, den Sie umschließen.

6
Ewan

Es werden unterschiedliche Meinungen geäußert, aber ich bezweifle, dass die Leute grundsätzlich anderer Meinung sind.

Der Punkt ist, dass das Umschließen von APIs can eine bewährte Methode ist.

  1. Wenn die Schnittstelle der API trivial ist, macht das Umschließen keinen Sinn. Das Gleiche gilt, wenn die Schnittstelle stabil ist, dem Testen nicht im Wege steht und nicht viel komplizierter ist als das, was Sie benötigen.
  2. Wenn die Schnittstelle kompliziert ist und Sie nur eine Teilmenge verwenden, verwenden Sie einen Wrapper. Ein erweitertes Protokollierungsframework, in dem Sie immer Dinge im selben Format protokollieren möchten und alles, was Sie jemals in der App verwenden, ist LogError, LogWarn, LogInfo und LogDebug. Die Verwendung eines Wrappers ermöglicht die Verwendung eines Modells zum Testen von Protokollnachrichten und das einfache Ändern der Implementierung
  3. Wenn die Schnittstelle kompliziert ist, weil es sein muss, und Sie alles verwenden, können Sie die Schnittstelle nicht verbessern, und der Wrapper ist so kompliziert wie die ursprüngliche Schnittstelle. Das bedeutet, dass ein Wrapper keinen Vorteil bietet, wenn Sie in eine andere Bibliothek wechseln.
3
Peter

Haftungsausschluss: Ich verpacke die Middleware meiner eigenen Firma ...

Da es hier mehrere Ansprüche gibt, werde ich sie separat behandeln.

Das Umschließen erleichtert auch das Verspotten von Anrufen von Drittanbietern, wenn Sie Ihren eigenen Code testen.

Hier gibt es mehrere Vorteile, insbesondere wenn man sich nur über Verspotten lustig macht , hilft die Anzahl der Anrufe. Einige werden argumentieren, dass die Anzahl der Anrufe nicht funktioniert und daher nicht getestet werden sollte; Ich habe jedoch Leute gesehen, die Änderungen eingeführt haben, bei denen die Anzahl der Anrufe um den Faktor 10x oder 100x multipliziert wurde, und die Auswirkungen auf die Leistung sind nicht trivial. Dies gilt insbesondere dann, wenn ...

... einige Bibliotheken von Drittanbietern weisen viele Abhängigkeiten auf (Netzwerkverbindung, komplizierte Konfigurationsdatei), und nur durch Verspotten können Sie unter anderem Fehler leicht einfügen, auf die Sie testen möchten.

Zu diesem Zeitpunkt ist das Umbrechen natürlich mehr als alles andere, um eine unerwünschte Abhängigkeit (Verbindung, Konfigurationsdatei) zu beseitigen.

In der Tat ist das Umschließen von APIs von Drittanbietern eine bewährte Methode. Wenn Sie eine Drittanbieter-API umschließen, minimieren Sie Ihre Abhängigkeiten davon: Sie können in Zukunft ohne große Nachteile in eine andere Bibliothek wechseln.

Dies sollte Hand in Hand gehen mit dem Prinzip DRY] und mit der Abstraktion.

Wenn Sie eine Bibliothek eines Drittanbieters aufrufen, um ein XML-Dokument zu analysieren, navigieren Sie zum Navigieren, um einige Daten zu extrahieren. Der Aufrufer:

  • ist nicht daran interessiert, welche Drittanbieter-Bibliothek Sie verwenden
  • ist wahrscheinlich nicht an der Struktur des XML-Dokuments interessiert

infolgedessen wickeln Sie dies in einen eigenen Code ein, der den doppelten Vorteil hat, die Abstraktionsstufe zu erhöhen (es handelt sich nicht um ein XML-Dokument, sondern um den Kauf von 4 Vanilleeiscreme mit Karamell darüber).

Wenn Sie XML-Dokumente wiederholt dekodieren, werden Sie ziemlich schnell Teile des Dekodierungscodes verschmelzen, die immer wieder auftauchen. Das ist nur trocken.

Als Ergebnis finde ich, dass das Umschließen von Komponenten von Drittanbietern selbstverständlich ist: Wenn ich denselben Aufruf zweimal oder dreimal verwende, extrahiere ich den Code in einer gemeinsamen Funktion, die irgendwie zu einem Wrapper wird.

(nicht gestellte Frage zu Grenzen und Geschäftsmodell)

Eine Drittanbieter-API ist ein Ausländer und spricht Ihre Sprache nicht.

Es gibt eine Grenze zwischen Ihrem eigenen Code und dem Code eines Drittanbieters: Sie verwenden verschiedene Objekte. Sie können Ihren Server beispielsweise als Zeichenfolge (IPv4) und Ganzzahl (Port) modellieren, die zugrunde liegende API erwartet jedoch nur eine Zeichenfolge (IPv4: Port) oder umgekehrt. Daher muss eine Transformation angewendet werden, wenn mit dieser fremden API gesprochen wird.

Idealerweise möchten Sie die Codemenge maximieren, die mit Ihren eigenen Daten verarbeitet wird:

  • du verstehst es
  • sie steuern es (Invarianten sind überprüft und für Ihre App von Bedeutung.)
  • ...

dies erfordert, die Grenzen des Fremdcodes so weit wie möglich zu verschieben.

Da jede Übersetzung ein eigenes Risiko für Fehlanpassungsimpedanzen birgt, möchten Sie auch die Anzahl der Stellen im Code verringern, an denen eine solche Übersetzung erfolgt.

In beiden Fällen spricht dies für eine dünne Schicht zwischen Ihrem Anwendungscode und APIs von Drittanbietern.

2
Matthieu M.