AI가 코드를 빠르게 쌓을수록 번들과 가독성이 조용히 무너진다

AI가 코드를 빠르게 쌓을수록 번들과 가독성이 조용히 무너진다

Sloppification·Dead Code·Bundle Creep—세 현상이 수렴하는 곳에 AI 보조 개발의 숨겨진 품질 청구서가 있다

Sloppification comprehension debt Tree-shaking Vite 번들 최적화 AI 생성 코드 번들 크기 코드 가독성 buildwatch
광고

AI가 PR을 통과시키는 속도가 빨라졌다. 그런데 그 PR 안에 아무도 설명할 수 없는 코드가 조용히 쌓이고 있다면? 그리고 그 코드가 번들에 쓸모없는 킬로바이트를 매 빌드마다 밀어 넣고 있다면? 속도를 얻은 대신, 가독성과 성능을 조금씩 담보로 잡힌 셈이다.

코드가 읽히지 않는 새로운 방식

예전에는 ProGuard 같은 난독화 도구가 코드를 망가뜨렸다. 변수명을 a, b로 뭉개고, 문자열을 암호화해 decrypt(0x4F2A…)로 바꿔버렸다. 누가 봐도 이상했기 때문에, 리뷰어는 경계하고 조심했다.

dev.to에 올라온 글 Sloppification Is The New Obfuscation은 지금 벌어지는 현상이 그것보다 더 위험하다고 말한다. AI가 생성한 코드는 겉으로는 전혀 이상하지 않다. 변수명도 적절하고, 추상화도 그럴듯하고, 테스트도 통과한다. 그래서 리뷰어는 승인을 누른다. 문제는 세 달 뒤, 무언가 망가졌을 때 팀 안에 그 코드를 설명할 수 있는 사람이 아무도 없다는 것이다.

그 글에서 제시한 비교가 직관적이다. 단순한 사용자 조회 함수를 사람이 쓰면 4줄이다. AI가 쓰면 UserRetrievalService, IUserRepository, IRequestValidator, UserResponseMapper를 거쳐 18줄이 된다. 기능은 동일하다. 테스트도 동일하게 통과한다. 그러나 후자를 처음 보는 사람이 의도를 파악하는 데 드는 인지 비용은 전혀 다르다. Addy Osmani가 올해 'comprehension debt'(이해 부채)라고 명명한 바로 그것이다. 빌드 속도가 느려지거나 Slack에 에러 알람이 뜨는 기술 부채와 달리, 이해 부채는 아무 신호를 보내지 않는다. 그냥 조용히 쌓인다.

번들도 같은 방식으로 조용히 망가진다

코드 가독성 문제와 구조적으로 닮은 일이 번들에서도 일어난다. AI가 생성한 코드에는 과잉 추상화와 방어적 보일러플레이트가 많다. 쓰이지 않는 인터페이스, 호출되지 않는 팩토리, 죽은 브랜치. 이것들은 가독성만 해치는 게 아니라 번들 크기에도 직접 영향을 미친다.

Optimizing Vite Build Output: A Practical Guide to Tree-Shaking(dev.to)은 그 메커니즘을 실무 레벨로 풀어낸다. Vite의 Tree-shaking은 ES module의 정적 의존 그래프를 추적해 실제로 사용되지 않는 export를 제거한다. 그런데 이 기능은 개발자가 '명확한 신호'를 주었을 때만 제대로 작동한다. import * as utils from './utils'처럼 네임스페이스 전체를 가져오면, 번들러는 빌드 타임에 어떤 프로퍼티가 런타임에 쓰일지 알 수 없다. 결국 여덟 개 함수 중 하나만 필요해도 여덟 개를 모두 번들에 넣는다. AI가 생성하는 '방어적이고 포괄적인' 임포트 패턴은 이 함정에 빠지기 딱 좋다.

이 글의 저자가 실천하는 수칙은 단순하다. Named import만 사용하고, 네임스페이스 객체를 함수에 통째로 넘기지 않으며, 초기 렌더링에 필요하지 않은 것은 동적 import로 분리한다. 단 하나의 변경—import * asimport { resetPagination }으로 바꾸는 것—이 번들에서 쓸모없는 함수 일곱 개를 사라지게 만들었다고 한다.

로컬 개발 단계에서 잡지 못하면 PR까지 간다

그렇다면 번들 크기 변화를 언제 알아채야 할까. Bundle size creep goes unnoticed until PR review(dev.to)는 현실을 직시한다. 대부분의 팀이 번들 크기 증가를 인지하는 시점은 PR 리뷰, 혹은 프로덕션 성능 회귀 이후다. 그 간격 사이에 수십 킬로바이트가 조용히 쌓인다.

이 문제를 해결하려고 만들어진 buildwatch는 발상이 간단하다. npx buildwatch ./dist를 실행해두면 빌드 결과물 디렉터리를 감시하면서 파일별, 전체 합산 크기 변화를 터미널에 실시간으로 찍어준다. zero-dependency Node.js이고 CI 설정도 필요 없다. 코드를 저장하고 Vite가 빌드를 마치는 순간, main.js +12.1 KB (+9.7%)가 바로 보인다. 코드 리뷰 전에, 커밋 전에, 개발자가 가장 빠르게 피드백을 받을 수 있는 시점에 신호를 준다.

속도가 부채를 산업화한다

세 가지 현상—Sloppification, 과잉 임포트, Bundle Creep—은 서로 다른 층위에서 발생하지만 같은 원인을 공유한다. AI가 코드를 '충분히 그럴듯하게' 빠르게 만들어주는 동안, 그 코드가 팀의 이해 자산과 번들 예산에 미치는 영향을 확인하는 루프가 없다는 것이다.

David Parnas는 1994년에 이미 '소프트웨어 노화'를 경고했다—설계를 이해하지 못한 사람이 코드를 수정할 때 시스템이 조용히 썩는다고. AI는 그 현상을 발명한 게 아니라 산업화했다. 매 PR마다, 아무도 설명하지 못한 채 승인된 코드 한 조각이 이해 부채 계좌에 적립된다.

실질적으로 지금 당장 할 수 있는 것은 세 가지다. 첫째, AI가 생성한 코드를 리뷰할 때 '작동하는가'보다 '설명할 수 있는가'를 기준으로 삼는다. 코드 작성자가 왜 이 추상화 레이어가 필요한지 말하지 못한다면, 그건 통과시켜선 안 된다. 둘째, Named import를 기본값으로 삼고 네임스페이스 임포트는 의식적으로 회피한다—AI가 생성한 임포트 구문일수록 더 꼼꼼히 확인한다. 셋째, buildwatch 같은 로컬 피드백 도구를 개발 루프 안에 붙여둔다. 번들 크기 변화는 코드 변경과 가장 가까운 시점에 알아야 한다.

AI 보조 개발의 속도는 진짜 이점이다. 그 속도를 유지하면서 코드 품질과 성능 예산을 지키려면, 생성하는 루프만큼 검증하는 루프가 촘촘해야 한다. 조용히 쌓이는 부채일수록 의식적으로 설계한 피드백 구조가 필요하다.

출처

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