AI가 잘 짜려면 코드가 먼저 AI 친화적이어야 한다

AI가 잘 짜려면 코드가 먼저 AI 친화적이어야 한다

바이브 코딩의 달콤한 함정, Angular 함수형 설계의 교훈, CopilotKit의 빠른 통합이 함께 가리키는 하나의 결론—AI가 틀리는 건 AI 탓이 아니라 코드 구조 탓이다

바이브 코딩 AI 친화적 코드 LLM 컨텍스트 창 함수형 프로그래밍 CopilotKit 코드 품질 Angular FP 프롬프트 엔지니어링
광고

20분 만에 기능을 만드는 도파민, 그 이면

"Claude가 다 해줘요. 저는 그냥 프롬프트만 씁니다." 요즘 개발자 커뮤니티에서 심심찮게 듣는 말이다. 틀린 말은 아니다. AI 코딩 도구는 실제로 놀랍도록 빠르고, 보일러플레이트를 20분 안에 뚝딱 만들어내는 경험은 일단 맛보면 되돌아가기 힘들다. 문제는 그 다음이다.

dev.to에 올라온 "The Vibe Coding Trap"은 이 달콤함의 이면을 세 가지 실제 사례로 꼬집는다. 50개가 넘는 툴 콜을 가진 에이전트가 테스트에서는 완벽하게 동작하다가 프로덕션에서 50% 실패율을 기록한 사례, temperature=0.7로 설정해놓고 왜 출력이 들쭉날쭉하냐고 묻는 개발자, 그리고 LLM이 확신에 찬 태도로 존재하지 않는 API를 호출해 팀 전체가 6시간을 날린 케이스. 공통점은 하나다. AI가 틀린 게 아니라, AI가 틀릴 수밖에 없는 환경을 개발자가 만들었다는 것이다.

컨텍스트 창은 생각보다 훨씬 빨리 찬다

바이브 코딩의 함정을 이해하려면 LLM이 어떻게 '생각'하는지를 조금은 알아야 한다. 컨텍스트 창은 단순히 대화 내용만 담지 않는다. 툴 정의, 시스템 프롬프트, 대화 히스토리가 모두 토큰을 소비한다. 128k 컨텍스트라도 복잡한 에이전트 설정 앞에서는 순식간에 바닥을 드러낸다. 잘린 프롬프트는 소리 없이 실패한다. 디버그 로그 어디에도 "컨텍스트가 잘렸습니다"라는 친절한 메시지는 없다.

이 문제는 단순히 프롬프트 엔지니어링의 문제가 아니다. 코드베이스 자체가 얼마나 많은 컨텍스트를 소비하도록 설계되었느냐의 문제다. 여기서 Angular의 함수형 프로그래밍 논의가 전혀 다른 각도에서 맞닿는다.

5,000줄 클래스는 사람도, AI도 이해하지 못한다

dev.to의 "Functional Programming in Angular"는 표면적으로는 FP 패러다임 전환을 다루는 글이지만, 핵심 논지 중 하나는 놀랍도록 AI 협업 관점과 직결된다. ! 어서션으로 도배된 뮤터블 상태, 5,000줄짜리 컴포넌트 클래스, 암묵적인 필드 의존성—이것들은 인간의 작업 기억(7±2 컨텍스트)을 넘치게 만드는 요소인데, LLM도 정확히 같은 이유로 망가진다는 것이다.

LLM이 뮤터블 상태가 가득한 코드를 수정하려면, 각 필드가 언제 초기화되는지, 어떤 메서드가 어떤 필드를 읽는지, 변경이 어디까지 전파되는지를 모두 추론해야 한다. 이 암묵적 의존성들이 컨텍스트 창을 잡아먹으면서 실제 문제를 풀 여유를 없애버린다. 결과는 예측 가능하다. 없는 변수를 만들어내고, 데이터 흐름을 잘못 추정하고, 하나를 고치면 둘을 망가뜨린다. 이것이 이 글에서 말하는 '수리 불가능의 임계점'이다. AI 능력의 부재가 아니라, 코드 복잡도가 추론 용량을 초과해버린 상태.

반대로 생각하면 답이 보인다. 순수 함수로 구성된 데이터 파이프라인, 명시적 타입 계약, 불변 데이터 흐름은 사람의 인지 부하를 낮추는 동시에 LLM이 소비해야 할 컨텍스트 토큰도 극적으로 줄인다. TypeScript strict 모드와 readonly 필드, 유니온 타입으로 명확한 계약을 만드는 것은 "컴파일러가 버그를 잡게 하라"는 원칙이기도 하지만, 동시에 AI가 더 적은 컨텍스트로 더 정확한 코드를 생성하게 만드는 설계이기도 하다.

빠른 통합의 진짜 조건

그렇다면 AI를 실제로 빠르게 통합하는 건 어떻게 가능한가. CopilotKit의 "5분 AI 통합" 튜토리얼은 흥미로운 접근을 보여준다. 에이전트 루프, 툴 레지스트리, 스트리밍 레이어를 직접 구현하는 대신 useAgentContextuseFrontendTool 두 훅으로 추상화한다. Next.js 앱에 API 라우트 하나와 Provider 래핑만으로 동작하는 AI 사이드바를 만든다.

여기서 주목할 점은 속도 자체가 아니다. CopilotKit이 빠른 이유는 "AI가 알아야 할 것"과 "AI가 할 수 있는 것"을 명확하게 분리했기 때문이다. useAgentContext는 앱 상태의 현재 스냅샷을 구조화된 방식으로 컨텍스트에 밀어 넣고, useFrontendTool은 LLM이 호출할 수 있는 액션을 명시적으로 정의한다. 프리폼 텍스트에 의존하지 않고 스키마와 구조화된 출력을 강제하는 방식은 앞서 말한 "바이브 코딩 함정"에서의 핵심 처방과 정확히 일치한다.

인프라 문제처럼 보이던 AI 통합이 프론트엔드 문제로 환원되는 것도 같은 맥락이다. 컨텍스트를 잘 정의하고, 툴의 책임 범위를 명확히 하고, 구조화된 인터페이스로 소통하는 것—이것은 좋은 컴포넌트 설계의 원칙과 다르지 않다.

AI 친화적 코드란 결국 좋은 코드다

세 가지 사례를 하나의 흐름으로 읽으면 결론은 선명해진다. 바이브 코딩은 생산성 배수기다. 하지만 그 배수기가 제대로 돌아가려면 돌아갈 재료가 AI 친화적이어야 한다. 그리고 AI 친화적인 코드란 사실 우리가 오래전부터 알던 좋은 코드—명시적 의존성, 순수 함수, 강한 타입, 작고 명확한 인터페이스—와 다르지 않다.

역설적으로, AI 도구가 강력해질수록 코드 구조 설계의 중요성은 더 커진다. 엉킨 뮤터블 상태 위에서 AI가 만들어내는 코드는 빠르게 쌓이는 기술 부채일 뿐이다. 반면 명확한 계약과 데이터 흐름 위에서 AI와 협업하면, 그 속도는 진짜 레버리지가 된다. 바이브 코딩의 80%를 살리는 건 나머지 20%의 설계 투자다. 그 20%를 AI에게 맡길 수 없는 이유이기도 하다.

출처

더 많은 AI 트렌드를 Seedora 앱에서 확인하세요