paint-brush
Código para una interfaz: todo lo que necesita saberpor@oussamamater
482 lecturas
482 lecturas

Código para una interfaz: todo lo que necesita saber

por Oussama Mater7m2024/06/18
Read on Terminal Reader

Demasiado Largo; Para Leer

"Código para una interfaz" nunca tuvo sentido para mí. Cuestioné la necesidad de crear una interfaz y luego implementarla. ¿Cómo determino cuándo y dónde utilizar estas interfaces? Si está experimentando esto, sepa que todos hemos pasado por eso. Le ayudaremos a comprender por qué necesita "Codificar para la interfaz".
featured image - Código para una interfaz: todo lo que necesita saber
Oussama Mater HackerNoon profile picture

A medida que te tomas más en serio la programación, inevitablemente encontrarás la frase "Código para una interfaz", ya sea en videos, libros o artículos. Y nunca tuvo sentido para mí. Cuestioné la necesidad de crear una interfaz y luego implementarla. ¿Cómo determino cuándo y dónde utilizar estas interfaces?


Cada vez que veía un tutorial o leía un artículo, me explicaban qué es una interfaz, "Es una clase sin implementación", y yo decía "Ehmm, gracias 😏". Quiero decir, eso ya lo sabía; Lo que realmente quería saber era por qué y cuándo usarlo.


Recuerdo que un día pregunté en la comunidad de Discord y uno de los mayores simplemente dijo: "No te preocupes; eventualmente hará clic para ti", y así fue, tomó algo de tiempo, pero así fue. Si está experimentando esto, sepa que todos hemos pasado por eso; Vamos a ayudarle a comprender por qué necesita codificar en una interfaz .

Escribamos un código

Dado que la IA está tomando el control y todo el mundo está perdiendo la cabeza por ello, no queremos llegar tarde a la fiesta. Queremos agregarlo a nuestro sitio web, lo hará un pequeño chatbot que responda preguntas sobre nuestro producto.


Usaré PHP para mi ejemplo; siéntase libre de utilizar cualquier idioma con el que se sienta cómodo. Lo que importa es el concepto.


Nuestro chatbot puede ser tan simple como esto:

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

Hay un método único ask() , que utiliza el SDK OpenAI para conectarse a su API, plantear una pregunta y luego simplemente devolver la respuesta.


Ya podemos empezar a utilizar nuestro chatbot

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


Hasta ahora, la implementación parece buena, funciona como se esperaba y el proyecto está implementado y en uso. Pero no podemos negar que nuestro chatbot depende en gran medida de la API Open AI; Estoy seguro de que estás de acuerdo.


Ahora, consideremos un escenario donde los precios de Open AI se duplican y continúan aumentando, ¿cuáles son nuestras opciones? O simplemente aceptamos nuestro destino o buscamos otra API. La primera opción es fácil, simplemente les seguimos pagando, y la segunda no es tan simple como parece. Es probable que el nuevo proveedor tenga su propia API y SDK; Tendremos que actualizar todas las clases, pruebas y componentes relacionados diseñados originalmente para Open AI, eso es mucho trabajo.


Esto también genera preocupaciones; ¿Qué pasa si la nueva API no cumple con nuestras expectativas en términos de precisión o aumenta el tiempo de inactividad? ¿Qué pasa si queremos experimentar con diferentes proveedores simultáneamente? Por ejemplo, ¿proporcionar a nuestros clientes suscritos el cliente OpenAI mientras utilizamos una API más simple para los invitados? Puedes ver lo complejo que esto puede ser, ¿y sabes por qué? Porque nuestro código estaba mal diseñado.


No teníamos una visión; simplemente elegimos una API y dependíamos completamente de ella y de su implementación. Ahora bien, el principio de "Código a interfaz" nos habría salvado de todo esto. ¿Cómo? Vamos a ver.


Comencemos creando una interfaz:

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


Tenemos nuestra interfaz, o como me gusta llamarla, un contrato. Implementémoslo o codifíquelo.

 <?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(); } }


En realidad, tanto OpenAiSDK como RandomAiSDK se inyectarán a través del constructor. De esta manera, delegamos la compleja lógica de creación de instancias a un contenedor DI , un concepto conocido como inversión de control . Esto se debe a que cada proveedor suele requerir determinadas configuraciones.


Ahora tenemos dos proveedores que podemos utilizar para responder preguntas. Independientemente de su implementación, estamos seguros de que cuando se les haga una pregunta, se conectarán a su API y la responderán. Deben cumplir con el contrato AIProvider .


Ahora, en nuestro ChatBot , podemos hacer lo siguiente

 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); } }


Tenga en cuenta que el ejemplo tiene como objetivo demostrar las múltiples formas en que puede inyectar una dependencia, en este caso, un AIProvider . No es necesario utilizar constructores y definidores.


Puedes ver que hicimos algunos ajustes; Ya no dependemos de OpenAI y no encontrará ninguna referencia al respecto. En cambio, dependemos del contrato/interfaz. Y, de alguna manera, podemos identificarnos con este ejemplo en la vida real; Todos hemos sido ChatBot al menos una vez.


Imagínese comprar un sistema de paneles solares. La empresa promete enviar técnicos para instalarlo, asegurándole que, independientemente del empleado que envíen, el trabajo estará hecho y al final tendrá sus paneles instalados. Entonces, realmente no te importa si envían a Josh o a George. Pueden ser diferentes, uno mejor que el otro, pero ambos están contratados para instalar los paneles.


No dirán, ya sabes, estoy reparando tu televisor, sino que la empresa los obliga a realizar el trabajo especificado. Tanto RandomAi como OpenAi actúan como empleados de AIProvider ; usted hace una pregunta y ellos le darán una respuesta. Así como a usted no le importa quién instala los paneles, al ChatBot no debería importarle en absoluto quién hace el trabajo. Sólo necesita saber que cualquier implementación proporcionada será suficiente.


Ahora, puedes utilizar libremente uno u otro.

 $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$

Ahora tiene la flexibilidad de cambiar todo el proveedor de API y su código siempre se comportará igual. No tiene que cambiar nada porque codificó una interfaz , por lo que ninguna de las preocupaciones que planteamos anteriormente será un problema.

Siempre hay bonificaciones

En nuestro ejemplo, al codificar una interfaz, también hemos respetado tres de los principios SOLID , sin siquiera saberlo, déjame explicarte.


No entraré en detalles; cada uno de los principios puede tener un artículo largo. Esta es solo una breve explicación para mostrar lo que obtuvimos al codificar una interfaz.

Principio abierto-cerrado

El primer principio que respetamos es el principio abierto-cerrado, que establece que el código debe estar abierto a extensiones y cerrado a modificaciones. Por más desafiante que parezca, lo has logrado. Piénselo, el ChatBot está cerrado a modificaciones ahora; No volveremos a tocar el código. Este fue nuestro objetivo desde el principio.


Pero está abierto a prórroga; Si añadimos un tercer, cuarto o incluso un quinto proveedor, nada nos detendrá. Podemos implementar la interfaz y nuestra clase puede usarla de inmediato, no se requieren cambios.

Sustitución de Liskov

No te aburriré con su definición, pero básicamente establece que puedes sustituir clases con TODAS sus subclases y viceversa. Técnicamente, todos nuestros proveedores de IA are-a AIProvider , y sus implementaciones se pueden intercambiar entre sí, sin afectar la corrección de ChatBot , este último ni siquiera sabe qué proveedor está utilizando 😂, así que sí, respetamos a la Sra. Liskov. .

Inversión de dependencia

Debo admitir que éste podría tener su propio artículo. Pero, para decirlo de forma sencilla, el principio establece que se debe depender de abstracciones más que de lo concreto, que es exactamente lo que estamos haciendo. Dependemos de un proveedor, no de uno específico como Open AI.


Recuerde, todo esto se debe a que codificamos una interfaz.

Eventualmente hará clic para usted

Cada vez que actualizas una clase que sabes que no deberías actualizar y tu código se vuelve complicado con las declaraciones if, necesitas una interfaz. Pregúntese siempre: ¿esta clase realmente necesita saber cómo? ¿Utilizaré siempre este proveedor de servicios? ¿O controlador de base de datos? Si no, ya sabes qué hacer.


Dicho esto, dale un poco de tiempo y eventualmente hará clic para ti .