Warum ist es so eine schlechte Idee, eine Schnittstelle zwischen Server und Client zu teilen?

12

Ich habe gerade die Spring Cloud Netflix- Dokumentation gelesen, als ich herausgefunden habe, wie eine Schnittstelle zwischen einem HTTP-Server und seinem Client gemeinsam genutzt werden kann. Sie verwenden dieses Beispiel für Microservices, obwohl es keinen Grund gibt, warum es nicht auf die generische HTTP-Kommunikation ausgedehnt werden kann:

// The shared interface, in a common library
public interface UserService {
    @RequestMapping(method = GET, value = "/users/{id}")
    User getUser(@PathVariable long id);
}

// The controller, on the server
@RestController
public class UserResource implements UserService {
}

// The same interface used for the client
@FeignClient("users")
public interface UserClient extends UserService {
}

Dies definiert eine Schnittstelle, die sowohl als Server (The Spring @RestControllerverwandelt sie in einen HTTP-Server) als auch als Client (The Feign @FeignClientrichtet sie für die Verwendung als HTTP-Client ein) verwendet wird. Die Server- und Clientklassenimplementierungen können in separaten Projekten verwendet werden, verwenden jedoch dieselbe Schnittstelle, um sicherzustellen, dass die Typen übereinstimmen.

Unter das Beispiel stellen sie jedoch die folgende Einschränkung:

Hinweis: Es ist im Allgemeinen nicht ratsam, eine Schnittstelle zwischen einem Server und einem Client freizugeben. Es führt eine enge Kopplung ein und funktioniert auch in der aktuellen Form nicht mit Spring MVC (die Zuordnung von Methodenparametern wird nicht vererbt).

OK, es ist momentan nicht gut integriert ... aber dieser Teil kommt nach der Warnung vor dem Teilen von Code und der Einführung der Kopplung zwischen dem Server und dem Client, was sie für wichtiger halten. Warum halten sie es für eine so schlechte Idee, eine Schnittstelle auf diese Weise zu teilen?

Ohne sie verlieren Sie die Fähigkeit zu garantieren, dass Server und Client sich gegenseitig Daten senden, die beide verstehen können. Sie können dem einen, aber nicht dem anderen Feld ein Feld hinzufügen und die Nichtübereinstimmung nur bis zur Laufzeit feststellen. Meiner Meinung nach , ist es nicht die Einführung Kupplung, sondern lediglich enthüllt Kopplung , die bereits existiert. Ist die Notwendigkeit, Server vollständig unabhängig zu machen, größer als die Notwendigkeit, ihnen mitzuteilen, welche Arten von Daten sie erhalten werden?

Ben S.
quelle
1
Die vorhandene Kopplung in Bezug auf Daten / Formatierungen, die von Clients / Servern verarbeitet werden, wird durch das Protokoll bestimmt - eine Dokumentation, die als Konvention verwendet werden kann . Die durch die gemeinsame Nutzung einer Schnittstelle eingeführte Kopplung ist eine Kopplung zur Kompilierungszeit. Überlegen Sie, was passiert, wenn die Schnittstelle geändert wird (z. B. abwärtsinkompatibel), der Client / Server-Code, der diese Schnittstelle verwendet, jedoch zu unterschiedlichen Zeiten bereitgestellt wird. Diese Bereitstellung-Zeit- Kopplung kann schwieriger zu verwalten sein, insbesondere auf Netflix-Ebene.
Castaglia
1
Ich bin ziemlich sicher , dass ich nicht bei Netflix operierendes :) aber , wenn die Schnittstellen in einer rückwärts geändert werden inkompatible Weise, dann nicht diese Verschiebung nur den Fehler aus , die statt zur Laufzeit gefunden werden bei der Kompilierung gefunden werden? Halten sie es für in Ordnung, einige Funktionsaufrufe fehlschlagen zu lassen, während sie langsam alle Server aktualisieren?
Ben S
1
Möglicherweise; hängt vom Client-Code ab. Betrachten Sie auch den anderen Fall: Die Server werden zuerst aktualisiert, und die Clients müssen jetzt (unerwartet) fehlgeschlagene Anrufe
bearbeiten
1
Nur neugierig, durch das Teilen dieser Schnittstelle, schränkt es ein, aus welchen Sprachen / Stapeln Sie den Client erstellen können?
JeffO
Ja, es ist eine Java-Datei, daher müssen Sie Java verwenden. Sie können eine andere JVM Sprache verwenden können , aber ich habe es nicht versucht.
Ben S

Antworten:

6

Der in den Kommentaren angegebene Grund ist, dass Ihre Client-Plattform eng mit Ihrer Server-Plattform verbunden ist. Hier bedeutet dies, dass Ihr Client die Sprache / Plattform verwenden muss, die Sie auf dem Server verwenden, um den erwarteten Vertrag Ihres Servers zu verstehen. Beachten Sie, dass es einen Unterschied zwischen der Freigabe desselben Codes (ein Artefakt einer bestimmten Sprache / Plattform) und der Vereinbarung eines bestimmten Vertrags gibt.

Viele Projekte verwenden stattdessen Dokumentation für ihre Verträge. Beispielanfragen und -antworten in einem neutralen Format (z. B. JSON) über Standardprotokolle (z. B. REST). (Siehe z. B. Stripe-API-Dokumente .) Da es unpraktisch ist, einen Code-basierten Vertrag für jede mögliche Client-Plattform zu schreiben, die Sie möglicherweise verwenden oder zulassen möchten. Wieder andere verwenden API-Verwaltungstools, um neutrale Verträge zu definieren .

Ihr Beispiel für das Hinzufügen eines Felds ist ein separates Problem - ein Beispiel dafür, warum es wichtig ist, API-Verträge zu versionieren. Lassen Sie die Clients die Version verwenden, für die sie entwickelt wurden. Neben der alten gibt es eine abwärtskompatible neue API-Version. Der Client für die alte Version arbeitet so lange weiter, bis sein Team mit der Aktualisierung fertig ist oder bis Sie die alte Version zurückziehen (nach einer Verfalls- / Migrationsperiode). Siehe Parallele Änderung .

Das Befolgen der (impliziten Hinweise in der) Warnung hilft dem Client und dem Server, sich auf eine Weise und in Schritten zu entwickeln, die für jeden sinnvoll sind. Wenn Sie vernünftigerweise garantieren können, dass Ihr Server und Client immer dieselbe Sprache / Plattform verwenden UND sich im gleichen Tempo weiterentwickeln, ist die Verwendung eines sprach- und plattformspezifischen Code-Artefakts als Vertrag wahrscheinlich in Ordnung. Dies ist jedoch wahrscheinlich keine vernünftige Erwartung, insbesondere für Projekte, die auf Netflix OSS abzielen (etwas, das speziell auf Cloud-Skalierbarkeit und -Leistung mit all dieser erforderlichen Komplexität ausgerichtet ist).

Kasey Speakman
quelle
2
Wird vom Client wirklich erwartet, dass er die Schnittstelle verwendet? Ich habe solche Konstrukte immer als eine Möglichkeit gesehen, das Schreiben eines Kunden zu vereinfachen. Schließlich können Sie immer noch einen REST-Client in einer anderen Sprache schreiben.
Jimmy T.
1
Genau, API wird immer noch existieren, mit seinen Routendefinitionen, nichts verhindert die Erstellung eines Clients in einer anderen Sprache, aber solange Sie Java verwenden, könnte die Schnittstelle verwenden
Leonardo Villela