Angenommen, Sie haben ein großes Projekt, das von einer API-Basis unterstützt wird. Das Projekt liefert auch eine öffentliche API, die Endbenutzer verwenden können.
Manchmal müssen Sie Änderungen an der API-Basis vornehmen, die Ihr Projekt unterstützt. Beispielsweise müssen Sie eine Funktion hinzufügen, die eine API-Änderung oder eine neue Methode erfordert oder die Änderung eines der Objekte oder des Formats eines dieser Objekte erfordert, die an oder von der API übergeben werden.
Angenommen, Sie verwenden diese Objekte auch in Ihrer öffentlichen API, ändern sich die öffentlichen Objekte auch jedes Mal, wenn Sie dies tun. Dies ist unerwünscht, da Ihre Clients möglicherweise darauf angewiesen sind, dass die API-Objekte identisch bleiben, damit ihr Parsing-Code funktioniert. (Husten C ++ WSDL-Clients ...)
Eine mögliche Lösung besteht darin, die API zu versionieren. Wenn wir jedoch "Version" der API sagen, muss dies auch bedeuten, dass die API-Objekte versioniert und für jede geänderte Methodensignatur doppelte Methodenaufrufe bereitgestellt werden. Also hätte ich dann für jede Version meiner API ein einfaches altes clr-Objekt, was wiederum unerwünscht erscheint. Und selbst wenn ich das mache, werde ich sicherlich nicht jedes Objekt von Grund auf neu erstellen, da dies zu riesigen Mengen an dupliziertem Code führen würde. Vielmehr wird die API wahrscheinlich die privaten Objekte erweitern, die wir für unsere Basis-API verwenden, aber dann stoßen wir auf dasselbe Problem, da hinzugefügte Eigenschaften auch in der öffentlichen API verfügbar wären, wenn dies nicht der Fall sein sollte.
Was ist also eine Vernunft, die normalerweise auf diese Situation angewendet wird? Ich weiß, dass viele öffentliche Dienste wie Git für Windows eine versionierte API verwalten, aber ich habe Probleme, mir eine Architektur vorzustellen, die dies unterstützt, ohne große Mengen an doppeltem Code, der die verschiedenen versionierten Methoden und Eingabe- / Ausgabeobjekte abdeckt.
Mir ist bewusst, dass Prozesse wie die semantische Versionierung versuchen, ein gewisses Maß an Sicherheit zu schaffen, wenn öffentliche API-Unterbrechungen auftreten sollten. Das Problem ist eher, dass es so scheint, als ob viele oder die meisten Änderungen das Brechen der öffentlichen API erfordern, wenn die Objekte nicht stärker voneinander getrennt sind, aber ich sehe keinen guten Weg, dies zu tun, ohne Code zu duplizieren.
quelle
I don't see a good way to do that without duplicating code
- Ihre neue API kann immer Methoden in Ihrer alten API aufrufen oder umgekehrt.Antworten:
Wenn Sie eine API verwalten, die von Dritten verwendet wird, müssen Sie zwangsläufig Änderungen vornehmen. Der Grad der Komplexität hängt von der Art der Änderung ab. Dies sind die wichtigsten Szenarien:
Neue Funktionalität zur vorhandenen API hinzufügen
Dies ist das am einfachsten zu unterstützende Szenario. Das Hinzufügen neuer Methoden zu einer API sollte keine Änderungen an vorhandenen Clients erfordern. Dies kann sicher für Clients bereitgestellt werden, die die neue Funktionalität benötigen, da für keinen vorhandenen Client Aktualisierungen vorliegen.
Alte Funktionalität von API veraltet
In diesem Szenario müssen Sie vorhandenen Verbrauchern Ihrer API mitteilen, dass die Funktionalität langfristig nicht unterstützt wird. Bis Sie entweder die Unterstützung für die alte Funktionalität einstellen (oder bis alle Clients auf die neue Funktionalität aktualisiert haben), müssen Sie die alte und die neue API-Funktionalität gleichzeitig beibehalten. Wenn es sich um eine Bibliothek handelt, die bereitgestellt wird, können die meisten Sprachen alte Methoden als veraltet / veraltet markieren. Wenn es sich um einen Dienst eines Drittanbieters handelt, ist es normalerweise am besten, unterschiedliche Endpunkte für die alte / neue Funktionalität zu haben.
Bestehende Funktionen in der API ändern sich in irgendeiner Weise
Dieses Szenario hängt von der Art der Änderung ab. Wenn keine Eingabeparameter mehr verwendet werden müssen, können Sie einfach den Dienst / die Bibliothek aktualisieren, um die jetzt zusätzlichen Daten zu ignorieren. In einer Bibliothek müsste die überladene Methode intern die neue Methode aufrufen, für die weniger Parameter erforderlich sind. In einem gehosteten Dienst muss der Endpunkt zusätzliche Daten ignorieren und beide Clienttypen bedienen und dieselbe Logik ausführen.
Wenn die vorhandene Funktionalität neue erforderliche Elemente hinzufügen muss, müssen Sie über zwei Endpunkte / Methoden für Ihren Dienst / Ihre Bibliothek verfügen. Bis zum Aktualisieren der Clients müssen Sie beide Versionen unterstützen.
andere Gedanken
Rather, the API is likely to extend the private objects we are using for our base API, but then we run into the same problem because added properties would also be available in the public API when they are not supposed to be.
Stellen Sie keine internen privaten Objekte über Ihre Bibliothek / Ihren Dienst bereit. Erstellen Sie Ihre eigenen Typen und ordnen Sie die interne Implementierung zu. Auf diese Weise können Sie interne Änderungen vornehmen und den Aktualisierungsaufwand für externe Clients minimieren.
The problem is more that it seems like many or most changes require breaking the public API if the objects aren't more separated, but I don't see a good way to do that without duplicating code.
Die API, unabhängig davon, ob es sich um einen Dienst oder eine Bibliothek handelt, muss am Integrationspunkt mit den Clients stabil sein. Je mehr Zeit Sie benötigen, um die Ein- und Ausgänge zu ermitteln und als separate Einheiten zu speichern, desto mehr Kopfschmerzen ersparen Sie sich später. Machen Sie den API-Vertrag zu einer eigenen Entität und ordnen Sie ihn den Klassen zu, die die eigentliche Arbeit leisten. Die Zeitersparnis bei der Änderung interner Implementierungen sollte die zusätzliche Zeit, die zum Definieren der zusätzlichen Schnittstelle benötigt wurde, mehr ausgleichen.
Betrachten Sie diesen Schritt nicht als "Code duplizieren". Obwohl sie ähnlich sind, handelt es sich um separate Entitäten, deren Erstellung sich lohnt. Während externe API-Änderungen fast immer eine entsprechende Änderung der internen Implementierung erfordern, sollten interne Implementierungsänderungen die externe API nicht immer ändern.
Beispiel
Angenommen, Sie bieten eine Zahlungsverarbeitungslösung an. Sie verwenden PaymentProviderA, um Kreditkartentransaktionen durchzuführen. Später erhalten Sie über den Zahlungsprozessor von PaymentProviderB einen günstigeren Tarif. Wenn Ihre API Felder für Kreditkarten- / Rechnungsadressen Ihres Typs anstelle der Darstellung von PaymentProviderA verfügbar macht, ist die API-Änderung 0, da die Schnittstelle dieselbe bleibt (hoffentlich trotzdem, wenn PaymentProviderB Daten benötigt, die von PaymentProviderA nicht benötigt wurden, müssen Sie eine der beiden auswählen unterstützen Sie beide oder behalten Sie die schlechtere Rate mit PaymentProviderA).
quelle