The Vibe Coding Debt Trap: Why AI-Generated Code Breaks in Month 3
바이브 코딩 부채 함정 — AI가 생성한 코드가 3개월 차에 깨지는 이유
LLM 기반 '바이브 코딩'은 초기 생산성을 높이지만, 유지보수 3개월 차부터 인간이 작성한 코드에서는 드물게 보이는 구조적 기술 부채를 드러낸다고 저자는 지적합니다. 의존성 팽창, 아키텍처 경계 침범, 형식만 있는 테스트 등 구체적인 실패 패턴을 분석하고 '검증 기반' 워크플로로 전환할 것을 제안합니다.
- 주제
본문
LLM을 개발 워크플로에 통합하는 초기 단계에서 약속은 단순했습니다. 10배의 생산성 향상입니다. 보일러플레이트 생성, 단위 테스트 작성, 마이크로서비스 스캐폴딩까지 몇 분이면 끝납니다. 이른바 '바이브 코딩(vibe coding)', 즉 깊은 아키텍처 설계 대신 직관과 프롬프트 엔지니어링으로 코드를 작성하는 방식은 스타트업과 기능 스파이크에서 판도를 바꿨지만, 저자는 AI 생성 코드가 상당 부분을 차지하는 코드베이스에서 유지보수 3개월 차부터 전통적인 기술 부채와는 다른 부채가 나타나기 시작한다고 진단합니다.
부채의 원인 — 생성자의 한계
이 부채는 변수명이나 주석 누락 같은 표면적 문제가 아니라 구조적 문제입니다. LLM은 GitHub, StackOverflow 같은 공개 저장소에서 학습하는데, 그 코퍼스에는 일회성 문제를 해결한 복사-붙여넣기 코드, 2015년에는 모범 사례였지만 지금은 안티패턴이 된 구식 패턴, 실용성보다 순수성을 우선한 과도한 엔지니어링이 섞여 있습니다. 모델은 방금 작성한 try-catch 블록이 고처리량 Rust 서비스에 들어간다는 사실도, 임포트한 라이브러리 버전이 지난 분기에 deprecated되었다는 사실도 모릅니다. 맥락 속 정확성이 아니라 '그럴듯함(plausibility)'에 최적화되어 있기 때문입니다.
프랑켄슈타인 효과와 의존성 드리프트
첫 번째 구조적 실패 모드는 '프랑켄슈타인 효과'입니다. 개발자가 특정 함수 구현을 요청하면 AI는 함수뿐 아니라 주변 임포트를 수정하고, 공유 유틸리티를 리팩터링하고, 헤더 파일의 타입 시그니처까지 바꿔 코드가 컴파일되게 만듭니다. 부작용을 이해하지 못한 채 diff를 수용하면 은밀한 결합이 생기고, 1개월 차에는 동작하지만 3개월 차에 다른 개발자가 그 공유 유틸리티를 건드리는 순간 예상치 못한 장애가 터집니다. 두 번째는 '의존성 드리프트'입니다. 학습 데이터가 인기 프레임워크 활용 코드에 치우쳐 있어, 인간이라면 Date 객체로 10줄짜리 유틸을 쓸 상황에서 AI는 luxon, moment-timezone, 커스텀 변환 라이브러리를 제안합니다. 프롬프트 한 번에 패키지가 세 개씩 늘어나 3개월 뒤에는 빌드 산출물이 부풀고 공격 표면이 넓어지며 lockfile 관리가 악몽이 됩니다.
일관성 침식과 아키텍처 드리프트
린터(ESLint, Prettier, Black)로 강제되는 팀 컨벤션도 AI의 '국소 최적' 생성 방식 앞에서는 무너집니다. named export와 strict typing을 쓰는 TypeScript 코드베이스에서 CSV 파서를 요청하면 AI는 export를 빼먹고 루프에 var를 쓰는 식입니다. 개발자가 수동으로 고치면 재정렬되지만, 그대로 커밋하면 lint 경고가 쌓이고 '그냥 포맷팅 문제'로 무시되며 일관성이 침식됩니다. 저자는 '수용되는 모든 diff가 의도 대신 엔트로피에 던지는 한 표'라고 표현합니다. 더 교묘한 것은 아키텍처 드리프트입니다. 헥사고날 아키텍처로 설계된 Node.js 서비스에서 UserService가 userRepository를 통해 데이터를 다루는 구조인데, AI에게 '사용자 삭제' 기능을 요청하면 라우트에서 db.query로 직접 DELETE를 날리는 코드가 생성됩니다. 동작하고 테스트도 통과하지만 API 계층과 인프라 계층의 경계를 침범하며, 이후 트랜잭션 지원을 추가할 때 이 코드는 트랜잭션 경계도 검증도 이벤트 발행도 없는 '유지보수 섬'이 됩니다.
형식만 있는 테스트와 의도 상실
AI 생성 테스트는 포괄적으로 보이지만 잘못된 것을 검증합니다. 사용자 생성 시 status_code 201과 이름 반환만 확인하는 테스트는 중복 이메일, 잘못된 이메일 형식, 필수 필드 누락, SQL 인젝션, 레이트 리미팅 같은 실제 엣지 케이스를 놓칩니다. 커버리지 지표는 좋아 보이지만 프로덕션에서 무너집니다. 또한 인간 코드는 구조·네이밍·주석으로 의도를 기록하지만 AI 코드는 process(a, b, c)처럼 '무엇을 하는지'만 있고 '왜 존재하는지'가 없어, 원 개발자가 떠나거나 AI 도구의 동작이 바뀌면 추론 불가능한 코드가 남습니다.
대응 원칙
저자의 결론은 AI 거부가 아니라 '바이브 기반'에서 '검증 기반' 워크플로로의 전환입니다. AI 출력은 결과물이 아니라 초안으로 취급해 리뷰·리팩터링하고, 아키텍처 경계를 위반하는 코드는 수용하지 않으며, 커버리지 대신 정확성과 엣지 케이스를 테스트하고, 주석과 명명으로 의도를 문서화하고, AI 활용이 적절한 범위를 팀 가이드라인으로 정해야 한다고 제안합니다. 배포가 가장 빠른 길이 유지보수가 가장 빠른 길은 아니라는 것입니다.
원문: dev.to / 번역·요약: Trawling