paint-brush
Code zu einer Schnittstelle: Alles, was Sie wissen müssenvon@oussamamater
351 Lesungen
351 Lesungen

Code zu einer Schnittstelle: Alles, was Sie wissen müssen

von Oussama Mater7m2024/06/18
Read on Terminal Reader

Zu lang; Lesen

„Code für eine Schnittstelle“ hat für mich nie Sinn ergeben. Ich habe die Notwendigkeit in Frage gestellt, eine Schnittstelle zu erstellen und sie dann zu implementieren. Wie bestimme ich, wann und wo ich diese Schnittstellen verwenden soll? Wenn Sie dies erleben, wissen Sie, dass wir das alle schon einmal erlebt haben. Wir helfen Ihnen zu verstehen, warum Sie „Code für eine Schnittstelle“ benötigen.
featured image - Code zu einer Schnittstelle: Alles, was Sie wissen müssen
Oussama Mater HackerNoon profile picture

Wenn Sie sich ernsthafter mit dem Programmieren beschäftigen, stoßen Sie unweigerlich auf den Ausdruck „Code für eine Schnittstelle“, entweder in Videos, Büchern oder Artikeln. Und für mich ergab das nie Sinn. Ich stellte die Notwendigkeit in Frage, eine Schnittstelle zu erstellen und sie dann zu implementieren. Wie bestimme ich, wann und wo ich diese Schnittstellen verwenden soll?


Immer wenn ich mir ein Tutorial ansah oder einen Artikel las, wurde mir erklärt, was eine Schnittstelle ist: „Es ist eine Klasse ohne Implementierung“, und ich dachte nur: „Ähm, danke 😏“. Ich meine, das wusste ich schon; was ich wirklich wissen wollte, war, warum und wann man sie verwendet.


Ich erinnere mich, wie ich eines Tages in der Discord-Community nachgefragt habe und einer der Älteren einfach sagte: „Keine Sorge, irgendwann wird es bei dir Klick machen“, und das tat es. Es dauerte zwar eine Weile, aber es klappte. Wenn du das auch erlebst, sei dir bewusst, dass wir das alle schon durchgemacht haben. Wir helfen dir zu verstehen, warum du Code für eine Schnittstelle schreiben musst.

Lass uns Code schreiben

Da die KI die Oberhand gewinnt und alle darüber ausflippen, wollen wir nicht zu spät zur Party kommen. Wir wollen sie auf unserer Website integrieren, und zwar mit einem kleinen Chatbot, der Fragen zu unserem Produkt beantwortet.


Ich werde für mein Beispiel PHP verwenden. Sie können aber auch jede andere Sprache verwenden, mit der Sie vertraut sind. Was zählt, ist das Konzept.


So einfach kann unser Chatbot sein:

 <?php class ChatBot { public function ask(string $question): string { $client = new OpenAi(); $response = $client->ask($question); return $response; } }

Es gibt eine einzelne Methode ask() , die das OpenAI SDK verwendet, um eine Verbindung mit deren API herzustellen, eine Frage zu stellen und dann einfach die Antwort zurückzugeben.


Wir können jetzt unseren Chatbot verwenden

 $bot = new ChatBot(); $response = $bot->ask('How much is product X'); // The product costs $200.


Bisher sieht die Implementierung gut aus, sie funktioniert wie erwartet und das Projekt ist bereitgestellt und im Einsatz. Wir können jedoch nicht leugnen, dass unser Chatbot stark von der Open AI API abhängig ist. Sie stimmen mir da sicher zu.


Betrachten wir nun ein Szenario, in dem sich die Preise für Open AI verdoppeln und weiter steigen. Welche Optionen haben wir? Entweder wir akzeptieren einfach unser Schicksal oder wir suchen nach einer anderen API. Die erste Option ist einfach: Wir zahlen einfach weiter, und die zweite ist nicht so einfach, wie sie klingt. Der neue Anbieter wird wahrscheinlich seine eigene API und sein eigenes SDK haben. Wir müssen alle Klassen, Tests und zugehörigen Komponenten aktualisieren, die ursprünglich für Open AI entwickelt wurden. Das ist eine Menge Arbeit.


Dies wirft auch Bedenken auf: Was, wenn die neue API unsere Erwartungen in Bezug auf Genauigkeit nicht erfüllt oder Ausfallzeiten erhöht? Was, wenn wir einfach mit verschiedenen Anbietern gleichzeitig experimentieren möchten? Zum Beispiel unseren abonnierten Kunden den OpenAI-Client bereitstellen und für Gäste eine einfachere API verwenden? Sie sehen, wie komplex dies sein kann, und wissen Sie, warum? Weil unser Code schlecht entworfen war.


Wir hatten keine Vision, wir haben einfach eine API ausgewählt und waren komplett von ihr und ihrer Implementierung abhängig. Das Prinzip „Code to Interface“ hätte uns das alles erspart. Wie? Mal sehen.


Beginnen wir mit der Erstellung einer Schnittstelle:

 <?php interface AIProvider { public function ask(string $question): string; }


Wir haben unsere Schnittstelle, oder wie ich sie gerne nenne, einen Vertrag. Lassen Sie uns diese implementieren oder Code dafür schreiben.

 <?php class OpenAi implements AIProvider { public function ask(string $question): string { $openAiSdk = new OpenAiSDK(); $response = $openAiSdk->ask($question); return "Open AI says: " . $response; } } class RandomAi implements AIProvider { public function ask(string $question): string { $randomAiSdk = new RandomAiSDK(); $response = $randomAiSdk->send($question); return "Random AI replies: " . $response->getResponse(); } }


In Wirklichkeit werden sowohl OpenAiSDK als auch RandomAiSDK über den Konstruktor eingefügt. Auf diese Weise delegieren wir die komplexe Instanziierungslogik an einen DI-Container , ein Konzept, das als Inversion of Control bekannt ist. Dies liegt daran, dass jeder Anbieter normalerweise bestimmte Konfigurationen erfordert.


Wir haben jetzt zwei Anbieter, die wir zum Beantworten von Fragen verwenden können. Unabhängig von ihrer Implementierung sind wir zuversichtlich, dass sie sich bei einer Frage mit ihrer API verbinden und darauf antworten. Sie müssen den Vertrag AIProvider einhalten.


Jetzt können wir in unserem ChatBot Folgendes tun

 class ChatBot { private AIProvider $client; // A dependency can be injected via the constructor public function __construct(AIProvider $client) { $this->client = $client; } // It can also be set via a setter method public function setClient(AIProvider $client): void { $this->client = $client; } public function ask(string $question): string { return $this->client->ask($question); } }


Beachten Sie, dass das Beispiel die verschiedenen Möglichkeiten zum Einfügen einer Abhängigkeit demonstrieren soll, in diesem Fall einen AIProvider . Sie müssen nicht sowohl Konstruktoren als auch Setter verwenden.


Sie sehen, dass wir einige Optimierungen vorgenommen haben. Wir sind nicht mehr von OpenAI abhängig und Sie werden auch keine Hinweise darauf finden. Stattdessen sind wir vom Vertrag/der Schnittstelle abhängig. Und irgendwie können wir dieses Beispiel mit dem wirklichen Leben in Verbindung bringen; wir waren alle mindestens einmal ein ChatBot .


Stellen Sie sich vor, Sie kaufen eine Solaranlage. Das Unternehmen verspricht, Techniker zur Installation zu schicken, und versichert Ihnen, dass die Arbeit erledigt wird, egal welchen Mitarbeiter sie schicken, und dass Sie am Ende Ihre Paneele installiert haben. Es ist Ihnen also egal, ob sie Josh oder George schicken. Sie mögen unterschiedlich sein, und einer ist besser als der andere, aber beide sind vertraglich verpflichtet, die Paneele zu installieren.


Sie werden nicht sagen: „Weißt du was, ich repariere stattdessen deinen Fernseher“, sondern sie sind von der Firma dazu verpflichtet, die angegebene Arbeit zu erledigen. Sowohl RandomAi als auch OpenAi agieren als Mitarbeiter von AIProvider ; du stellst eine Frage und sie geben dir eine Antwort. So wie es dir egal war, wer die Panels installiert, sollte es dem ChatBot auch völlig egal sein, wer die Arbeit macht. Er muss nur wissen, dass jede bereitgestellte Implementierung dies tun wird.


Nun können Sie frei das eine oder das andere verwenden.

 $bot = new ChatBot(); // For subscribed users $bot = new ChatBot(new OpenAi()); $response = $bot->ask('How much is Product X'); // Open AI says: 200$ // For guests $bot->setClient(new RandomAi()); $response = $bot->ask('How much is Product X'); // Random AI replies: 200$

Jetzt haben Sie die Flexibilität, den gesamten API-Anbieter zu ändern, und Ihr Code verhält sich immer gleich. Sie müssen nichts daran ändern, da Sie für eine Schnittstelle codiert haben . Daher wird keiner der zuvor angesprochenen Punkte ein Problem darstellen.

Es gibt immer Boni

In unserem Beispiel haben wir durch die Codierung einer Schnittstelle auch drei der SOLID- Prinzipien eingehalten, ohne es zu wissen. Lassen Sie mich das näher erläutern.


Ich werde nicht ins Detail gehen; jedes der Prinzipien könnte einen langen Artikel füllen. Dies ist nur eine kurze Erklärung, um zu zeigen, was wir durch die Codierung einer Schnittstelle gewonnen haben.

Open-Closed-Prinzip

Das erste Prinzip, das wir respektiert haben, ist das Open-Closed-Prinzip, das besagt, dass der Code für Erweiterungen offen und für Änderungen geschlossen sein sollte. So herausfordernd es auch klingen mag, Sie haben es geschafft. Denken Sie darüber nach, der ChatBot ist jetzt für Änderungen geschlossen; wir werden den Code nicht mehr anfassen. Das war von Anfang an unser Ziel.


Es ist jedoch erweiterbar. Wenn wir einen dritten, vierten oder sogar fünften Anbieter hinzufügen möchten, hält uns nichts davon ab. Wir können die Schnittstelle implementieren und unsere Klasse kann sie sofort verwenden. Es sind keine Änderungen erforderlich.

Liskov-Ersetzung

Ich will Sie nicht mit der Definition langweilen, aber im Grunde besagt sie, dass Sie Klassen durch ALLE ihre Unterklassen ersetzen können und umgekehrt. Technisch gesehen are-a AIProvider , und ihre Implementierungen können gegeneinander ausgetauscht werden, ohne die Richtigkeit von ChatBot zu beeinträchtigen. Letzterer weiß nicht einmal, welchen Anbieter er verwendet 😂, also ja, wir haben Frau Liskov respektiert.

Abhängigkeitsumkehrung

Ich muss zugeben, das könnte einen eigenen Artikel füllen. Aber um es einfach auszudrücken: Das Prinzip besagt, dass man sich auf Abstraktionen und nicht auf Konkretes verlassen sollte, und genau das tun wir. Wir sind von einem Anbieter abhängig, nicht von einem bestimmten wie Open AI.


Bedenken Sie, dass dies alles darauf zurückzuführen ist, dass wir eine Schnittstelle codiert haben.

Irgendwann wird es bei Ihnen Klick machen

Wenn Sie eine Klasse aktualisieren, von der Sie wissen, dass Sie sie nicht aktualisieren sollten, und Ihr Code durch if-Anweisungen unübersichtlich wird, benötigen Sie eine Schnittstelle. Fragen Sie sich immer: Muss diese Klasse wirklich wissen, wie? Werde ich diesen Dienstanbieter für immer verwenden? Oder diesen Datenbanktreiber? Wenn nicht, wissen Sie, was zu tun ist.


Geben Sie der Sache einfach etwas Zeit, irgendwann wird es bei Ihnen Klick machen .