주 40개 PR, 그 절반이 AI 어시스트. 지금 많은 팀이 이 속도를 경험하고 있고, 동시에 이 속도가 가져오는 혼란도 경험하고 있다. Copilot, Cursor, Claude가 만들어내는 diff는 문법적으로 깔끔하고, 테스트도 통과하고, 코드 스타일도 일관적이다. 문제는 바로 거기에 있다.
기존 리뷰 프로세스가 AI PR 앞에서 무너지는 이유
전통적인 코드 리뷰는 암묵적인 전제 위에서 작동한다—작성자가 문제를 깊이 이해하고 코드를 썼다는 전제. AI 생성 코드는 이 전제를 세 가지 방식으로 무너뜨린다.
첫째, 자신감 있는 오류다. diff는 깔끔해 보이고, 테스트는 통과하고, 로직은 그럴듯하다. 하지만 AI는 비동기 큐의 레이스 컨디션을 무시했거나, 컴파일은 되지만 deprecated된 SDK 메서드를 사용했을 수 있다. 둘째, 표면적 일관성이 리뷰어를 속인다. 코드가 깔끔할수록 신뢰 신호가 높아 보여서 오히려 속도를 높이게 된다—정확히 속도를 늦춰야 할 순간에. 셋째, 컨텍스트 단절이다. AI는 getUserById에 알려진 N+1 이슈가 있다는 것도, CDN 뒤에서 인증 미들웨어가 다르게 동작한다는 것도 모른다. 시스템 안에서 깨지는 코드를 격리된 환경에서 '정확하게' 작성한다.
"동작하나, 읽기 좋나, 테스트 있나"—이 세 질문만으로는 더 이상 충분하지 않다.
리뷰 전 트리아지: 모든 AI PR을 같은 무게로 보지 마라
dev.to의 AI PR 리뷰 플레이북이 제안하는 첫 번째 실천은 위험도 기반 트리아지다. 리뷰어의 집중도는 한정된 자원이다. PR을 열기 전에 먼저 분류하라.
높은 위험 신호—풀 리뷰 필요: - 인증, 권한, 세션 처리 변경 - DB 스키마 또는 마이그레이션 수정 - 신규 외부 의존성 추가 - 결제, 데이터 익스포트 등 크리티컬 패스의 에러 핸들링 변경 - 500줄 이상, 다수 파일에 걸친 대규모 변경
낮은 위험 신호—경량 리뷰 가능: - 단위 테스트가 완전히 커버된 독립 유틸 함수 - 상태나 API 인터랙션 없는 UI 전용 변경 - 동일한 입출력 계약을 유지하는 리팩터
PR 오픈 시 리스크 레이블을 태깅하는 것만으로도 리뷰 시간이 약 30% 단축된다고 한다. CSS 패딩 픽스에 최대 집중도를 쏟는 낭비를 막는 것만으로도 충분한 효과다.
실전 QA 체크리스트: 순서가 중요하다
체크리스트는 순서대로 실행해야 의미가 있다. 빨간 신호를 만나면 거기서 멈추고 대화를 먼저 시작하라.
- 요구사항 정렬: 실제 문제를 해결했나, 아니면 그럴듯한 인접 문제를 해결했나? 티켓 스펙의 엣지 케이스가 커버됐나, 해피패스만 있나?
- 통합 정확성: 현재 내부 API 계약으로 호출하는가, 오래된 시그니처를 쓰고 있지 않은가? 스테이징/프로덕션 환경별 설정은 올바른가?
- 에러 핸들링: 에러가 조용히 삼켜지는가? 재시도 가능한 실패와 불가능한 실패를 구분하는가?
- 보안: 신뢰 경계에서 입력 검증과 새니타이징이 되는가? 토큰, PII가 로그나 에러 응답에 노출되지 않는가?
- 퍼포먼스: N+1 쿼리 패턴이나 사용자 제어 데이터에 대한 무제한 루프가 있는가?
- 테스트 품질: 테스트가 동작을 검증하는가, 아니면 그냥 코드가 에러 없이 실행된다는 것만 확인하는가?
미디엄 사이즈 PR 기준 8분이면 돌릴 수 있다. .github/pull_request_template.md에 이 체크리스트를 넣으면 기억에 의존하지 않아도 된다.
즉시 리뷰를 중단해야 할 레드 플래그
아래 패턴을 발견하면 더 읽지 말고 바로 변경 요청을 내라.
catch (e) { console.log(e) }또는 빈 캐치 블록- 하드코딩된 크레덴셜이나
http://localhost:3000같은 URL - 3줄짜리 함수를 대체하기 위해 200KB 라이브러리를 끌어오는 경우
as any,// @ts-ignore, 설명 없는!논-널 단언- 트랜잭션 밖의 DB 작업
- 주석 처리된 코드 블록—AI는 "혹시 몰라서" 이전 구현을 남겨두는 습관이 있다
AI가 코드를 지우지 않는 이유: 데드 코드 문제
리뷰 체크리스트를 잘 운영해도 놓치기 쉬운 문제가 있다. AI 코딩 도구는 코드를 삭제하는 것을 극도로 꺼린다. 이게 단순한 특성이 아니라 구조적 문제다.
dev.to에서 Claude Opus 4.7을 직접 분석한 글에 따르면, 모델 스스로 그 이유를 설명했다. 포스트 트레이닝 단계에서 "도움이 되는" 출력에 보상이 주어지는데, 코드 삭제는 맥락이 명확하지 않으면 도움이 안 되는 것처럼 보인다. 그래서 "정리해줘"라고 하면 모델은 에러 핸들링을 추가하고, 리트라이 로직을 붙이고, 폴백을 만든다—당신이 요청하지 않은 것들을.
또한 모델은 삭제한 코드가 나중에 필요했을 때의 페널티를 비대칭적으로 과대평가한다. git이 모든 것을 기억한다는 사실을 알면서도, 마치 삭제가 돌이킬 수 없는 것처럼 행동한다. 결과적으로 세 세션 전에 지웠어야 할 코드가 컨텍스트를 오염시키면서 살아남고, 그 오염된 컨텍스트가 모델을 계속 같은 방향으로 프라이밍한다.
데드 코드가 AI 생성 PR에 미치는 실질적 영향
이 문제를 리뷰 관점에서 바라보면 더 심각해진다. AI가 생성한 PR에는 삭제됐어야 할 레거시 코드, 주석 처리된 이전 구현, 참조조차 되지 않는 유틸 함수가 함께 딸려오는 경우가 많다. 리뷰어는 이 코드가 의도적으로 남겨진 건지, 실수로 남겨진 건지, 아니면 AI가 "혹시 몰라서" 남긴 건지 판단해야 한다.
리뷰 체크리스트에 한 항목을 추가할 것을 권한다: "이 diff에 삭제됐어야 할 코드가 남아 있지 않은가?" 특히 리팩터링이나 기능 교체 PR에서는 이 질문이 핵심이 된다. AI에게 삭제를 명시적으로 지시하고, git diff를 ground truth로 활용하는 습관이 팀 전체의 코드베이스 건강도를 지킨다.
팀 스케일에서 작동하게 만들기
개인 체크리스트는 팀 규모에서 무너진다. 지속 가능하게 만드는 세 가지 레버가 있다.
1. 기계가 할 수 있는 것은 CI에 넘겨라. 정적 분석, 린팅, 타입 체크, 시크릿 스캔은 사람이 diff를 열기 전에 CI에서 막아야 한다. gitleaks로 시크릿을, semgrep으로 기본 보안 패턴을, 엄격한 TypeScript 설정으로 any 이스케이프를 차단하는 것이 기준선이다.
2. PR 설명에 AI 사용 여부를 명시하게 하라. "AI 지원: [없음 / Copilot 자동완성 / 전체 AI 생성]" 필드 하나가 리뷰어의 캘리브레이션을 바꾼다. 300줄짜리 Cursor 생성 피처와 Copilot이 자동완성한 유틸 함수는 다른 무게로 봐야 한다.
3. 고위험 영역에 도메인 오너를 리뷰어로 강제 배정하라. 인증 PR은 항상 인증을 소유한 사람이, DB 스키마 변경은 항상 마이그레이션을 작성하는 사람이 봐야 한다. diff가 깔끔하다는 이유로 AI 생성 코드가 도메인 오너십을 우회하게 두지 마라.
리뷰어의 마인드셋: 교정이 아니라 적대적 테스트
AI 코드를 리뷰하는 것은 교정(proofreading)이 아니다. "이게 맞아 보이나?"가 아니라 "이게 어떻게 망가지나?"를 묻는 적대적 테스트다. 이 멘탈 모델 전환 하나가 어떤 체크리스트 항목보다 더 많은 버그를 잡는다.
매월 랜덤으로 머지된 AI PR 5개를 선택해 20분짜리 레트로를 돌려라. 리뷰어가 무엇을 잡았는가, 무엇을 놓쳤는가, 어떤 체크리스트 항목이 그것을 잡을 수 있었는가. 이 루프가 체크리스트를 실제 코드베이스에 맞게 살아있게 만든다.
전망: 생성 속도만큼 빠른 리뷰 인프라를 설계하라
AI 어시스트 개발은 되돌아가지 않는다. 그렇다면 팀 리드의 역할은 생성 속도를 따라잡는 리뷰 인프라를 설계하는 것이다. 체크리스트는 그 인프라의 한 층위일 뿐이다. CI 자동화, 위험도 트리아지, 도메인 오너십 강제, 데드 코드 제거 규율, 그리고 리뷰어의 마인드셋 교육까지—이 모든 것이 맞물려야 "AI가 짠 코드를 믿고 머지할 수 있는" 환경이 만들어진다.
빠르게 생성하면서 느리게 검토하는 팀은 결국 기술부채를 AI 속도로 쌓는다. 생성 속도와 검토 인프라의 균형을 맞추는 것, 그것이 지금 팀 리드가 설계해야 할 가장 실질적인 과제다.