PR의 절반이 AI로 생성되었을 때의 코드 리뷰
요약
AI로 인한 코드 생성 속도의 급증이 리뷰어의 인지 대역폭을 초과하며 리뷰 품질 저하를 야기하는 문제를 다룹니다. AI가 생성한 코드는 겉보기에 멀쩡하지만 존재하지 않는 라이브러리나 잘못된 API 사용 등 치명적인 결함을 포함할 수 있음을 경고합니다.
핵심 포인트
- AI로 인해 코드 작성 속도가 리뷰 속도를 압도함
- 리뷰 품질 하락은 리뷰어의 태만이 아닌 대역폭 문제
- AI 생성 코드는 겉보기에 완벽해 보이는 함정을 가짐
- 존재하지 않는 라이브러리 및 잘못된 API 호출 위험
- 코드에 명시되지 않은 위험한 가정(Assumption)의 존재
월요일 아침, 리뷰어가 PR(Pull Request)을 여는 상황을 상상해 보세요. 제목은 "사용자 검색 엔드포인트 추가"입니다. 그들은 Files 탭을 클릭합니다.
+847 −12
847줄이 추가되었습니다. 리뷰어에게는 다음 회의까지 아마 15분 정도의 시간이 있습니다. 그들은 diff(차이점)를 스크롤합니다. 코드는 깔끔해 보입니다. 변수명은 서술적이고, 함수의 길이는 적절하며, 테스트도 포함되어 있습니다. 그들은 훑어보고, 명백히 잘못된 점이 없는 것을 확인한 뒤 승인(Approve)합니다.
3주 후, 해당 기능이 배포됩니다. 사용자들은 검색이 느리다고 불평합니다. 그로부터 2주 후, 데이터베이스 팀에서 긴급 티켓을 발행합니다. 하나의 쿼리가 매 요청마다 400만 개의 행을 스캔하고 있다는 내용입니다. 수정하는 데 하루가 걸립니다. 사후 분석(Post-mortem)에서는 "불충분한 부하 테스트"를 원인으로 지목합니다.
사후 분석은 틀렸습니다. 문제는 15분의 여유가 있는 리뷰어가 AI로 생성된 847줄의 코드를 의미 있게 리뷰할 수 없었다는 점입니다. 그리고 이것이 2026년에 대부분의 팀이 마주하게 될 PR 절반의 새로운 현실입니다.
AI가 만들어낸 리뷰 문제
AI 이전에는 리뷰 대역폭(Bandwidth)이 작성 대역폭과 대략적으로 일치했습니다. 팀이 하루에 5개의 PR을 작성한다면, 그것은 대략 인간의 속도로 생성된 것이며, 이는 곧 대략 인간의 속도로 리뷰가 가능하다는 것을 의미했습니다. 리뷰어는 코드가 작성된 속도에 맞춰 읽을 수 있었습니다.
AI는 그 방정식을 깨뜨렸습니다. 이제 작성자는 동일한 시간 내에 10배 더 많은 코드를 생성할 수 있습니다. 하지만 리뷰어는 여전히 인간의 속도로 읽습니다. 동일한 팀, 동일한 수의 리뷰어, 하지만 리뷰해야 할 코드는 10배 더 많아졌습니다.
그 결과는 제가 대화해 본 모든 테크 리드(Tech Lead)들이 확인해 주는 바와 같습니다. AI 도입 이후 업계 전반에 걸쳐 리뷰 품질이 하락했습니다. 리뷰어들이 게을러졌기 때문이 아닙니다. 기존에 유지하던 기준치에서 코드를 제대로 리뷰하는 것이 불가능할 정도로 양이 많아졌기 때문입니다.
잘못된 AI 생성 코드는 실제로 어떤 모습인가
AI가 생성한 PR을 리뷰해 보았다면, 문제는 눈에 확 띄는 종류의 것이 아니라는 점을 아마 눈치챘을 것입니다. AI는 명백하게 망가진 코드를 생성하는 경우가 드뭅니다. 위험한 코드는 겉보기에 멀쩡해 보입니다.
제가 반복적으로 목격하는 몇 가지 패턴은 다음과 같습니다:
존재하지 않는 라이브러리. AI가 패키지를 발명합니다. 코드는 @acme/super-fast-cache를 임포트(import)하고 코드 전반에서 사용하지만, 그런 패키지는 존재하지 않습니다. 설치 단계에서 실패하므로 발견되기는 하지만, 리뷰어는 이를 잡아내지 못합니다. 리뷰어는 임포트되었다면 당연히 존재할 것이라고 믿어버립니다.
작동 방식이 다른 API. AI가 실제 라이브러리에 존재하지 않는 메서드(method)를 사용하거나, 존재하더라도 시그니처(signature)가 다른 메서드를 사용합니다. redis.mget(keys, { default: 0 }) — Redis에는 default 옵션이 없습니다. 코드는 실행되고 옵션은 무시되며, 기본값은 적용되지 않은 채 프로덕션(production) 환경에서 버그가 드러납니다.
침묵하는 가정. AI는 검증하지 않은 가정을 바탕으로 코드를 작성합니다. 입력값이 UTF-8이라고 가정합니다. 타임스탬프(timestamp)가 UTC라고 가정합니다. 데이터베이스 타임아웃(timeout)이 서비스 타임아웃과 일치한다고 가정합니다. 코드를 읽는 리뷰어는 아무런 문제가 없다고 느끼는데, 그 이유는 이러한 가정들이 눈에 보이지 않기 때문입니다. 즉, '쓰여지지 않은 것' 속에 존재합니다.
'튜토리얼에서는 작동하는' 패턴. AI는 튜토리얼 사례에서는 작동하지만 규모가 커지면 실패하는 코드를 생성합니다. 페이지네이션(pagination) 예시, 토큰 갱신(token refresh)을 처리하지 못하는 인증 미들웨어(authentication middleware), 모든 것을 메모리에 버퍼링(buffering)하는 파일 업로드 등이 이에 해당합니다. 이 모든 것들은 개별적으로 보면 깔끔해 보입니다.
이것들은 주니어 리뷰어가 잡아낼 수 있는 종류의 버그가 아닙니다. 시니어 리뷰어가 이전에 경험해 보았기 때문에 잡아낼 수 있는 종류의 버그들입니다.
갑자기 매우 가치 있어진 기술
만약 AI가 작성 대비 리뷰 비율을 깨뜨렸다면, 이를 다시 바로잡는 사람들은 신호(signal)를 놓치지 않으면서도 방대한 디프(diff)를 빠르게 훑어볼 수 있는 리뷰어들입니다. 그것은 하나의 기술입니다. 그것은 항상 가치 있는 일이었지만, 이제는 희소해졌습니다.
시니어 리뷰어가 실제로 주니어와 다르게 하는 것:
디프를 선형적이 아니라 하향식(top-down)으로 읽습니다. 주니어 리뷰어는 1행부터 시작하여 쭉 읽어 내려갑니다. 시니어 리뷰어는 먼저 구조를 스캔합니다: 어떤 파일이 변경되었는가? 변경의 형태는 어떠한가? 변경 범위가 PR 제목에서 주장하는 바와 일치하는가? 구조를 이해한 후에야 비로소 코드를 세부적으로 파고듭니다.
그들은 무엇이 있는지(what's there)가 아니라, 무엇이 빠졌는지(what's missing)를 찾습니다. AI가 작성한 코드를 한 줄씩 읽는 리뷰어는 오타나 스타일 문제를 발견할 것입니다. 하지만 "내가 이것을 망가뜨리려 한다면 어떤 테스트가 실패할까?"라고 질문하는 리뷰어는 진짜 문제들을 찾아냅니다. 누락된 에러 핸들링 (error handling), 누락된 엣지 케이스 (edge cases), 실패 경로에서의 누락된 정리 작업 (cleanup) 같은 것들 말입니다.
그들은 단순한 버그가 아니라 가정을 지적합니다. 시니어 리뷰어들은 다음과 같이 코멘트를 남깁니다: "사용자 리스트가 비어 있다면 어떻게 되나요?", "업스트림 서비스 (upstream service)가 타임아웃되면 동작이 어떻게 되나요?", "이 엔드포인트 (endpoint)는 멱등성 (idempotent)을 보장하나요? 보장하지 않는다면, 보장해야 할까요?". 이러한 질문들은 고장 난 코드를 가리키는 것이 아니라, AI가 기본값으로 선택해버린 보이지 않는 결정들을 가리킵니다.
그들은 코드베이스 (codebase)의 80/20 법칙을 알고 있습니다. 해당 코드베이스에서 1년 동안 근무한 시니어 리뷰어는 어떤 파일이 핵심적인 지지대 역할을 하는지, 어떤 서비스가 지연 시간 (latency)에 민감한지, 어떤 모듈이 운영 환경 (production) 사고를 일으켰는지 알고 있습니다. 그들은 그에 따라 주의의 무게를 조절합니다. 결제 서비스 (payment service)에서의 한 줄 변경은 마케팅 페이지에서의 100줄 변경보다 더 엄격한 검토를 받습니다.
이 중 새로운 것은 없습니다. 다만 이 모든 것의 가치가 더 높아졌을 뿐입니다.
이제 리뷰의 기준은 어떠해야 하는가
리뷰어의 임무가 바뀌었습니다. 과거에는 "명백한 버그를 잡아내는 것"이었다면, 이제는 "이 코드베이스에서, 이 규모로, 이 비즈니스를 위해 코드가 올바른지 검증하는 것"이 되어야 합니다.
성숙한 팀들이 채택하고 있는 구체적인 변화들은 다음과 같습니다:
더 작은 PR을 강제합니다. AI 덕분에 개발자들이 아침 한나절 만에 800줄짜리 PR을 작성할 수 있게 되었다면, 팀은 제도적으로 PR 크기를 제한해야 합니다. 대부분의 팀은 최대 약 400줄로 제한하며, 이를 초과할 경우 여러 개의 PR로 나눕니다. 그 근거는 다음과 같습니다: 400줄짜리 PR은 여전히 20~30분 내에 제대로 리뷰할 수 있지만, 800줄은 불가능합니다.
PR 설명에 "컨텍스트 (context)" 섹션을 필수화합니다. 단순히 "이것이 무엇을 하는가"가 아니라, "이것이 처리해야 할 규모는 어느 정도인가? 어떤 실패 모드 (failure modes)를 고려했는가? AI가 작성한 내용 중 당신이 주의 깊게 검증한 것은 무엇인가?"를 작성하게 합니다. 이는 보이지 않는 결정들을 가시화합니다.
AI 비중이 높은 코드를 집중적인 리뷰와 결합하기. 만약 PR (Pull Request)이 실질적으로 AI에 의해 생성되었다면, 기본적으로 더 숙련된 리뷰어가 배정되도록 합니다. 팀은 이를 CODEOWNERS 또는 라우팅 규칙 (routing rules)을 통해 할당합니다.
일정 내 리뷰 예산 편성. 과거에는 리뷰가 엔지니어들이 일과 중 틈틈이 하는 작업이었습니다. 하지만 AI로 인한 작업량 증가와 함께, 리뷰는 이제 일급 시민 (first-class) 활동이 되었습니다. 이를 진지하게 받아들이는 팀은 매일 1~2시간을 심층 리뷰를 위해 예약하며, 다른 집중 업무와 마찬가지로 이 시간을 보호합니다.
실질적인 설정 방법
다음은 PR 크기 제한을 강제하는 GitHub Actions 스니펫 (snippet)입니다:
# .github/workflows/pr-size-check.yml
name: PR size check
on:
...
이것이 완벽한 도구는 아닙니다. 일부 정당한 PR은 더 클 수 있습니다 (대규모 리팩터링 (refactor), 생성된 코드 등). 핵심은 엄격하게 제한하는 것이 아니라, PR이 합리적인 크기를 초과할 때마다 대화를 강제하는 것입니다. 때로는 그 대화가 "네, 이번 건은 괜찮습니다"로 결론 나기도 합니다. 하지만 종종 "이것은 세 개의 PR로 나눌 수 있습니다"라는 결론에 도달하게 됩니다.
그리고 보이지 않는 AI의 결정 사항을 드러내 주는 PR 설명 템플릿 (template)입니다:
<!-- .github/pull_request_template.md -->
## 변경 사항
...
이 템플릿을 작성하는 데는 2분이 더 소요됩니다. 하지만 이는 리뷰어의 시간을 그보다 훨씬 더 많이 아껴주며, PR 작성자가 AI가 스스로 생성할 수 없었던 맥락 (context)을 드러내도록 강제합니다.
이 모든 과정에서 가장 어려운 점
AI 시대의 코드 리뷰에서 가장 어려운 점은 기술적인 것이 아닙니다. 바로 문화적인 것입니다.
가벼운 리뷰만으로도 잘 운영되던 팀들이 갑자기 운영 장애 (production incident) 발생률이 상승하는 것을 발견하게 되고, 그 장애의 원인을 추적해 보면 겉보기에 멀쩡해 보였던 머지(merge)된 PR들로 거슬러 올라가게 됩니다. 이때 AI를 탓하며 사용을 줄여야 한다고 주장하고 싶은 유혹에 빠지기 쉽습니다. 하지만 그것은 잘못된 결론입니다. AI는 이미 존재하며, AI가 가져다주는 생산성 향상은 포기하기에는 너무나 실질적이기 때문입니다.
올바른 결론은 더 어렵습니다. 바로 _리뷰의 기준(review bar)을 높여야 한다_는 것이며, 팀은 코드를 작성할 때 투자하는 만큼 리뷰에도 투자해야 한다는 것입니다. 이는 명시적인 시간을 예산으로 할당하고, 주니어 리뷰어를 위한 교육을 실시하며, 복잡한 리뷰에서는 페어링 (pairing)을 수행하고, 10배 더 많은 코드를 배포한다는 것은 품질에 쓰는 총 시간이 줄어드는 것이 아니라 오히려 더 늘어남을 받아들여야 함을 의미합니다.
만약 당신이 이 글을 읽고 있는 테크 리드 (tech lead)라면: 당신의 팀은 이 새로운 맥락에서 무엇이 좋은 리뷰인지에 대한 명시적인 가이드라인이 필요합니다. 아무도 스스로 이를 알아낼 수 없습니다. 과거의 본능은 AI 시대의 볼륨에 맞춰 확장(scale)되지 않습니다.
만약 당신이 시니어 IC (Individual Contributor)라면: 당신의 리뷰 기술은 방금 가장 가치 있는 자산 중 하나가 되었습니다. 여기에 투자하십시오. 필요하다면 본인의 코드 작성 속도를 늦추십시오. 프로덕션 (production)에 반영되기 전에 확장성 문제 (scaling issue)를 잡아내는 사려 깊은 리뷰 하나가, 리뷰 없이 병합된 수십 개의 PR (Pull Request)보다 더 가치 있습니다.
만약 당신이 주니어라면: 리뷰는 코드베이스를 배우고 시니어 수준의 판단력을 기르는 가장 빠른 방법입니다. 당신이 놓치는 것을 잡아내는 사람들과 리뷰 페어링 (pairing)을 하십시오. 그들에게 그들의 논리적 근거를 설명해달라고 요청하십시오. 이제 진정한 훈련은 AI가 점점 더 대신 작성해 줄 코드를 쓰는 것이 아니라, AI의 결과물이 당신의 특정 맥락에 맞는지 평가하는 과정에서 이루어집니다.
다시 증폭기로
2주 전, 저는 AI가 개발자들이 이미 가지고 있는 특성을 증폭시킨다고 주장했습니다. 이는 리뷰어에게도 동일하게 적용됩니다.
새로운 리뷰 관행 — 더 작은 PR, 명시적인 컨텍스트 (context), 확보된 시간 — 을 사용하는 시니어 리뷰어는 이전보다 10배 더 많은 문제를 잡아냅니다. 왜냐하면 더 높은 밀도의 코드를 더 신중하게 리뷰하기 때문입니다.
AI가 생성한 PR을 단순히 승인(rubber-stamping)만 하는 주니어 리뷰어는 이전보다 10배 더 많은 문제를 놓칩니다. 왜냐하면 코드의 볼륨이 그들의 경험치보다 더 빠르게 증가했기 때문입니다.
동일한 AI. 동일한 리뷰어. 하지만 근본적으로 다른 결과입니다.
누락된 케이스를 읽어내고, 가정을 지적하며, 코드베이스를 파악하는 것과 같은 코드 리뷰의 기본 원칙은 변하지 않았습니다. 다만 이러한 원칙들이 AI 시대에 번영하는 팀과 프로덕션 장애 (production incidents) 속에서 허우적거리는 팀을 가르는 기준이 되었을 뿐입니다.
그것들을 건너뛰지 마세요. 그것들은 선택 사항이 아닙니다. 이제 그 어느 때보다 중요해졌습니다.
이 포스트는 AI와 엔지니어링 기초 (engineering fundamentals)에 관한 시리즈의 일부입니다. 저의 저서 Git in Depth에는 코드 리뷰 (code review)에 관한 전체 장이 포함되어 있습니다. 코드 리뷰는 코드가 사람이 작성했든 AI가 생성했든 변하지 않는 원칙입니다.
관련 글: 왜 AI가 기초를 덜 중요한 것이 아니라 더 가치 있게 만들었는가 · AI 에이전트가 당신의 리포지토리 (repo)에 커밋하면 발생하는 일.
Git 및 엔지니어링 실무에 관한 저의 모든 글 보기: [dev.to/mdenda].
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기