프로그래밍에 대해 좀 더 진지해지면 비디오, 책, 기사에서 필연적으로 "인터페이스 코드"라는 문구를 접하게 됩니다. 그리고 그것은 나에게 전혀 이해가 되지 않았습니다. 인터페이스를 만들고 구현해야 하는지 의문이 들었습니다. 이러한 인터페이스를 언제 어디서 사용할지 어떻게 결정합니까?
튜토리얼을 보거나 기사를 읽을 때마다 인터페이스가 무엇인지 설명해주시는데, "구현이 없는 클래스다"라고 해주시는데, 저는 "으음, 고마워요😏"라고 하더군요. 내 말은, 나는 이미 그것을 알고 있었다는 것입니다. 제가 정말 알고 싶었던 것은 왜, 언제 사용해야 하는가였습니다.
어느 날 Discord 커뮤니티에 질문을 했을 때 선배 중 한 명이 간단히 "걱정하지 마세요. 결국 클릭하게 될 것입니다"라고 말했고, 시간이 좀 걸렸지만 그렇게 되었습니다. 만약 당신이 이런 일을 겪고 있다면 우리 모두가 그런 경험을 했다는 사실을 알아두세요. 인터페이스에 코딩 해야 하는 이유를 이해하도록 도와드리겠습니다.
AI가 장악하고 있고 모두가 그것에 대해 넋을 잃고 있기 때문에 우리는 파티에 늦고 싶지 않습니다. 우리는 그것을 우리 웹사이트에 추가하고 싶습니다. 우리 제품에 대한 질문에 답하는 작은 챗봇이 그것을 할 것입니다.
저는 예제로 PHP를 사용할 것입니다. 당신이 편한 언어를 자유롭게 사용하십시오. 중요한 것은 컨셉입니다.
우리의 챗봇은 다음과 같이 간단할 수 있습니다:
<?php class ChatBot { public function ask(string $question): string { $client = new OpenAi(); $response = $client->ask($question); return $response; } }
OpenAI
SDK를 사용하여 API에 연결하고 질문을 한 다음 간단히 응답을 반환하는 단일 메서드 ask()
가 있습니다.
이제 챗봇을 사용할 수 있습니다
$bot = new ChatBot(); $response = $bot->ask('How much is product X'); // The product costs $200.
지금까지 구현은 양호해 보이고 예상대로 작동하며 프로젝트가 배포되어 사용 중입니다. 그러나 우리의 챗봇이 Open AI API에 크게 의존하고 있다는 점은 부인할 수 없습니다. 나는 당신이 동의한다고 확신합니다.
이제 Open AI 가격이 두 배로 증가하고 계속 증가하는 시나리오를 고려해 보겠습니다. 우리의 옵션은 무엇입니까? 우리는 운명을 받아들이거나 다른 API를 찾습니다. 첫 번째 옵션은 쉽습니다. 계속 비용을 지불하기만 하면 되고, 두 번째 옵션은 말처럼 간단하지 않습니다. 새로운 공급자는 자체 API와 SDK를 갖게 될 가능성이 높습니다. 원래 Open AI용으로 설계된 모든 클래스, 테스트 및 관련 구성 요소를 업데이트해야 하는데, 이는 많은 작업입니다.
이는 또한 우려를 불러일으킵니다. 새 API가 정확성 측면에서 우리의 기대를 충족하지 못하거나 가동 중지 시간이 늘어나면 어떻게 되나요? 여러 제공업체를 동시에 실험하고 싶다면 어떻게 해야 할까요? 예를 들어, 게스트를 위해 더 간단한 API를 사용하면서 구독 클라이언트에 OpenAI 클라이언트를 제공한다고요? 이것이 얼마나 복잡할 수 있는지 알 수 있으며, 그 이유가 무엇인지 아십니까? 우리 코드가 제대로 설계되지 않았기 때문입니다.
우리에게는 비전이 없었습니다. 우리는 단지 API를 선택했고 그것과 그 구현에 전적으로 의존했습니다. 이제 "인터페이스에 대한 코드"라는 원칙이 이 모든 것에서 우리를 구했을 것입니다. 어떻게? 어디 보자.
인터페이스 생성부터 시작해 보겠습니다.
<?php interface AIProvider { public function ask(string $question): string; }
우리는 인터페이스, 혹은 제가 부르고 싶은 대로 계약을 갖고 있습니다. 그것을 구현하거나 코딩해 봅시다.
<?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(); } }
실제로
OpenAiSDK
와RandomAiSDK
모두 생성자를 통해 주입됩니다. 이런 방식으로 복잡한 인스턴스화 논리를 제어 반전 이라는 개념인 DI 컨테이너 에 위임합니다. 이는 일반적으로 각 공급자에 특정 구성이 필요하기 때문입니다.
이제 질문에 답변하는 데 사용할 수 있는 두 명의 제공자가 있습니다. 구현 여부에 관계없이 질문이 주어지면 API에 연결하여 응답할 것이라고 확신합니다. AIProvider
계약을 준수해야 합니다.
이제 ChatBot
에서 다음을 수행할 수 있습니다.
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); } }
이 예제의 목적은 종속성(이 경우에는
AIProvider
을 주입할 수 있는 다양한 방법을 보여주는 것입니다. 생성자와 설정자를 모두 사용할 필요는 없습니다.
우리가 몇 가지 조정을 한 것을 볼 수 있습니다. 우리는 더 이상 OpenAI에 의존하지 않으며 이에 대한 참조도 찾을 수 없습니다. 대신 우리는 계약/인터페이스에 의존합니다. 그리고 어떻게든 우리는 실제 생활에서 이 예를 연관시킬 수 있습니다. 우리 모두는 적어도 한 번은 ChatBot
경험해 본 적이 있습니다.
태양광 패널 시스템을 구입한다고 상상해 보십시오. 회사는 설치를 위해 기술자를 보낼 것을 약속하며 그들이 파견한 직원에 관계없이 작업이 완료되고 결국 패널이 설치될 것이라고 확신합니다. 따라서 그들이 Josh를 보내든 George를 보내든 상관하지 않습니다. 둘 중 하나가 다른 것보다 낫다는 점에서 다를 수 있지만 둘 다 패널 설치 계약을 체결했습니다.
그들은 내가 당신의 TV를 수리하는 대신 회사에서 지정된 작업을 수행할 의무가 있다는 것을 알지 못할 것입니다. RandomAi
와 OpenAi
모두 AIProvider
의 직원으로 활동합니다. 당신이 질문하면 그들은 답변을 제공할 것입니다. 패널을 설치하는 사람이 누구인지 신경 쓰지 않는 것처럼 ChatBot
작업을 수행하는 사람이 누구인지 전혀 신경 쓰지 않아야 합니다. 제공된 구현이 이를 수행할 것이라는 점만 알면 됩니다.
이제 둘 중 하나를 자유롭게 사용할 수 있습니다.
$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$
이제 전체 API 제공자를 유연하게 변경할 수 있으며 코드는 항상 동일하게 작동합니다. 인터페이스로 코딩했기 때문에 아무것도 변경할 필요가 없습니다. 따라서 앞서 제기한 우려 사항 중 어느 것도 문제가 되지 않습니다.
우리의 예에서는 인터페이스에 코딩하여 SOLID 원칙 중 세 가지를 존중했습니다. 심지어 자신도 모르게 자세히 설명하겠습니다.
자세한 내용은 다루지 않겠습니다. 각 원칙에는 긴 기사가 있을 수 있습니다. 이는 인터페이스를 코딩하여 얻은 결과를 보여주는 간략한 설명일 뿐입니다.
우리가 존중하는 첫 번째 원칙은 개방-폐쇄 원칙입니다. 즉, 코드는 확장을 위해 개방되고 수정을 위해 폐쇄되어야 한다는 것입니다. 어렵게 들리겠지만, 당신은 그것을 달성했습니다. 생각해 보세요. ChatBot
현재 수정을 위해 닫혀 있습니다. 우리는 코드를 다시 건드리지 않을 것입니다. 이것이 처음부터 우리의 목표였습니다.
그러나 확장이 가능합니다. 3번째, 4번째 또는 5번째 공급자를 추가하더라도 우리를 막을 수 있는 것은 없습니다. 우리는 인터페이스를 구현할 수 있고 우리 클래스는 이를 즉시 사용할 수 있으며 변경이 필요하지 않습니다.
그 정의에 대해 지루하게 설명하지는 않겠지만, 기본적으로 클래스를 모든 하위 클래스로 대체할 수 있고 그 반대의 경우도 가능하다고 명시되어 있습니다. 기술적으로 우리의 모든 AI 제공자는 AIProvider
are-a
, ChatBot
의 정확성에 영향을 주지 않고 구현을 서로 교체할 수 있습니다. ChatBot은 어떤 제공자를 사용하고 있는지조차 모릅니다 😂 따라서 우리는 Ms. Liskov를 존중했습니다. .
나는 이것이 자신의 기사를 가질 수 있다는 것을 인정해야합니다. 그러나 간단히 말해서, 그 원칙은 구체적인 것보다는 추상적인 것에 의존해야 한다는 것이며, 이것이 바로 우리가 하고 있는 일입니다. 우리는 Open AI와 같은 특정 공급자가 아닌 공급자에 의존합니다.
이 모든 것은 우리가 인터페이스에 코딩했기 때문이라는 것을 기억하십시오.
업데이트하면 안 되는 클래스를 업데이트하고 if 문으로 인해 코드가 해킹될 때마다 인터페이스가 필요합니다. 항상 스스로에게 물어보세요. 이 수업에서 정말 방법을 알아야 합니까? 이 서비스 제공업체를 영원히 이용할 수 있나요? 아니면 데이터베이스 드라이버? 그렇지 않다면 무엇을 해야할지 알 것입니다.
그렇게 말하면 잠시 시간을 주면 결국 클릭하게 될 것입니다 .