AI 시대의 코드 리뷰
직접 작성한 코드 리뷰에서 AI 생성 코드를 검증하고 판단하는 리뷰로의 전환
코드 리뷰는 개발 문화의 핵심이다. 그런데 코드의 작성자가 사람이 아니라 AI가 되면, 리뷰의 초점도 근본적으로 달라질 수밖에 없다.
기존 코드 리뷰의 질문: "이 코드를 왜 이렇게 짰나?" AI 시대 코드 리뷰의 질문: "이 코드가 우리 시스템에서 의도대로 동작하는가?"
이 장에서는 AI 생성 코드를 리뷰하는 관점의 변화를 탐구한다.
기존 코드 리뷰의 전제가 흔들리는 지점
전통적 코드 리뷰는 동료 개발자가 작성한 코드를 전제로 한다. AI가 코드를 작성하면 이 전제가 무너진다.
| 리뷰 항목 | 기존 전제 | AI 시대 현실 |
|---|---|---|
| 코딩 스타일 | 팀 컨벤션을 아는 사람이 작성 | AI는 컨벤션을 학습 데이터에서 추론 |
| 설계 의도 | 작성자가 PR에 기술 | AI는 프롬프트의 의도를 해석 |
| 비즈니스 로직 | 요구사항을 이해하고 구현 | AI는 명시된 것만 반영 |
| 엣지 케이스 | 경험과 도메인 지식 기반 | AI는 일반적 패턴만 고려 |
| 성능 고려 | 시스템 맥락을 파악하고 최적화 | AI는 로컬 최적화에 머무름 |
이 전제가 무너지면, 기존 리뷰 습관은 핵심을 놓치는 형식적 절차가 되기 쉽다.
AI 생성 코드의 4가지 특성
AI가 생성한 코드에는 사람이 작성한 코드와 구별되는 패턴이 있다.
1. 문법적으로 거의 완벽하다
AI는 린터 경고, 타입 에러, 구문 오류를 거의 만들지 않는다. 이로 인해 "문법적으로 깨끗한 코드 = 좋은 코드"라는 착각이 생기기 쉽다.
2. 맥락 이해에 한계가 있다
AI는 주어진 파일과 프롬프트만으로 코드를 생성한다.
- 다른 서비스와의 암묵적 계약을 모를 수 있음
- 레거시 코드가 왜 그렇게 작성되었는지 모를 수 있음
- 운영 환경의 제약을 반영하지 못할 수 있음
3. 과도하게 일반적이거나 과도하게 특수하다
AI는 학습 데이터의 평균적 패턴을 따르는 경향이 있어, 우리 프로젝트에 너무 범용적인 솔루션을 제안하거나, 프롬프트의 예시에 과적합된 코드를 생성하는 경우가 많다.
4. 자신감 있게 잘못된 코드를 만든다
AI는 확신 없이 코드를 생성하는 법이 없다. 모든 코드가 동일한 자신감으로 제시된다.
깔끔한 코드의 함정
AI 생성 코드가 lint 경고 0개라고 리뷰를 가볍게 넘기면 핵심을 놓칠 수 있다. 문법이 완벽하더라도 비즈니스 로직이 틀릴 수 있고, 시스템 컨텍스트를 반영하지 못한 코드일 수 있다.
AI 시대 리뷰 워크플로우의 변화
AI가 코드를 작성하는 환경에서 리뷰의 전체 흐름이 어떻게 달라지는지 살펴보면 흥미롭다.
핵심 변화는 리뷰어의 관심이 스타일에서 안전성과 정합성으로 이동한다는 점이다.
리뷰 관점의 이동
구체적으로 어디에 시간을 쓰는가가 달라진다.
| 기존 관점 | AI 시대 관점 | 이유 |
|---|---|---|
| 네이밍 컨벤션 | 비즈니스 로직 정확성 | AI는 네이밍을 잘 하지만 로직을 틀릴 수 있음 |
| 코드 스타일 | 시스템 안전성 | 포매터가 스타일을 처리 |
| DRY 원칙 준수 | 맥락 적합성 | AI가 만든 추상화가 불필요할 수 있음 |
| 성능 최적화 | 의도-구현 정합성 | 프롬프트의 의도가 정확히 반영되었는지 |
| 코드 양 | 변경 영향 범위 | 생성 코드가 기존 시스템에 미치는 부수 효과 |
리뷰 우선순위 매트릭스
모든 리뷰 항목의 중요도가 동일하지는 않다. 영향도와 AI 실수 빈도를 기준으로 우선순위를 시각화하면 다음과 같다.
이 매트릭스를 기반으로 한 리뷰 우선순위를 정리하면 다음과 같다.
관찰 기반 모델
리뷰 우선순위와 시간 배분은 업계 평균 통계가 아니라, AI 생성 코드 리뷰에서 반복적으로 관찰되는 운영 비중을 설명하기 위한 모델입니다.
| 우선순위 | 리뷰 항목 | 시간 배분 | 적합한 담당 |
|---|---|---|---|
| P0 - 즉시 확인 | 보안 취약점, 인증 누락 | 30% | 시니어 필수 |
| P1 - 주의 검토 | 비즈니스 로직, 동시성, API 계약 | 40% | 도메인 전문가 |
| P2 - 선별 확인 | 에러 핸들링, 타입 안전성 | 20% | 일반 리뷰어 |
| P3 - 자동화 | 스타일, 포매팅, 네이밍 | 10% | CI/CD |
리뷰 시간은 어디에 투자되는가
리뷰 시간의 배분 비율 변화가 흥미롭다.
기존에는 스타일과 컨벤션에 30% 이상을 투자하는 경우가 많았지만, AI 시대에는 5%면 충분하다. 나머지를 비즈니스 로직과 안전성에 집중할 수 있게 된다.
실제 사례: AI가 만든 코드에서 발견되는 문제들
사례 1: 조용히 실패하는 에러 핸들링
AI가 생성한 결제 처리 코드다. 문법적으로 완벽하지만 치명적 문제가 있다.
// AI 생성 코드 - 결제 웹훅 처리
export async function handlePaymentWebhook(payload: WebhookPayload) {
try {
const order = await db.order.findUnique({
where: { paymentId: payload.paymentId },
});
if (!order) {
console.log('주문을 찾을 수 없습니다');
return { success: true }; // 문제 1: 에러인데 success: true 반환
}
await db.order.update({
where: { id: order.id },
data: { status: 'PAID' },
});
await sendConfirmationEmail(order.userId);
return { success: true };
} catch (error) {
console.error('웹훅 처리 실패:', error);
return { success: false }; // 문제 2: 웹훅 재시도를 위해 500을 반환해야 함
}
}이 코드에서 리뷰어가 발견해야 할 세 가지 문제가 있다.
| 문제 | 위치 | 영향 | 수정 방향 |
|---|---|---|---|
| 주문 없음을 성공으로 반환 | return { success: true } | 결제는 됐지만 주문 미처리 | 에러 로깅 + 알림 + 재시도 |
| 에러 시 200 반환 | catch 블록 | 웹훅 재시도가 안 됨 | HTTP 500 반환으로 재시도 유도 |
| 멱등성 미보장 | 전체 함수 | 동일 웹훅 중복 처리 | 처리 여부 확인 로직 추가 |
사례 2: N+1 쿼리 문제
// AI 생성 코드 - 팀원 목록 조회
export async function getTeamMembers(teamId: string) {
const team = await db.team.findUnique({
where: { id: teamId },
include: { members: true },
});
// 문제: 멤버 수만큼 추가 쿼리 발생
const membersWithProjects = await Promise.all(
team.members.map(async (member) => {
const projects = await db.project.findMany({
where: { assigneeId: member.id },
});
const recentActivity = await db.activity.findFirst({
where: { userId: member.id },
orderBy: { createdAt: 'desc' },
});
return { ...member, projects, recentActivity };
})
);
return membersWithProjects;
}| 문제 | 분석 | 수정 방향 |
|---|---|---|
| N+1 쿼리 | 멤버 10명이면 쿼리 21개 실행 | JOIN 또는 include로 한 번에 조회 |
| 무제한 프로젝트 조회 | 프로젝트가 수백 개일 수 있음 | take 옵션으로 제한 |
| 에러 처리 없음 | team이 null이면 크래시 | null 체크 추가 |
AI는 단일 멤버에 대한 쿼리를 잘 구성하지만, 이것이 루프 안에서 반복될 때의 성능 영향을 고려하지 못하는 경우가 많다.
사례 3: 보안 취약점
// AI 생성 코드 - 사용자 검색 API
export async function GET(req: NextRequest) {
const query = req.nextUrl.searchParams.get('q');
// 문제 1: 인증 체크 없음
const users = await db.user.findMany({
where: {
OR: [
{ name: { contains: query } },
{ email: { contains: query } }, // 문제 2: 이메일 노출
],
},
// 문제 3: select 없이 전체 필드 반환 (비밀번호 해시 포함 가능)
});
return NextResponse.json(users);
}| 취약점 | 심각도 | 수정 방향 |
|---|---|---|
| 인증 없는 사용자 검색 | 높음 | 세션 검증 추가 |
| 이메일 기반 검색 허용 | 중간 | 이름만 검색 가능하도록 제한 |
| 전체 필드 반환 | 높음 | select로 공개 필드만 지정 |
| 입력값 검증 없음 | 중간 | 최소 길이, 특수문자 필터링 |
AI는 보안을 알아서 챙기지 않는다
AI는 "기능이 동작하는 코드"를 만들지, "안전한 코드"를 만들지 않는다. 보안은 리뷰어가 의식적으로 확인해야 하는 영역이다. 특히 인증, 인가, 입력값 검증, 데이터 노출은 AI가 가장 자주 놓치는 부분이기도 하다.
AI 생성 코드 리뷰에서 중요한 네 가지 관점
AI 생성 코드를 리뷰할 때 특히 주의가 필요한 영역은 네 가지로 정리된다.
의도 정합성
프롬프트의 의도와 생성된 코드 사이의 간극을 확인하는 관점이다. AI가 해석한 요구사항이 실제 요구사항과 다를 수 있고, 명시하지 않은 요구사항을 완전히 누락하는 경우도 흔하다.
시스템 맥락
기존 코드베이스의 패턴과 일관성이 있는지, 다른 서비스/모듈과의 인터페이스가 올바른지, 환경 변수와 설정값이 올바르게 참조되는지 확인하는 관점이다. AI가 가장 약한 영역이기도 하다.
안전성
에러 핸들링이 시스템 관례를 따르는지, 인증/인가가 올바르게 적용되었는지, SQL 인젝션이나 XSS 등 보안 취약점이 없는지, 동시성/경쟁 조건 처리가 되어 있는지 확인하는 관점이다.
엣지 케이스
null, undefined, 빈 배열, 빈 문자열 처리가 되어 있는지, 대량 데이터 입력 시 성능 문제가 없는지, 네트워크 실패나 타임아웃 시나리오가 고려되었는지 확인하는 관점이다.
PR 성격에 따라 초점이 달라진다
모든 관점을 매번 동일한 깊이로 확인할 필요는 없다. 새 기능은 의도 정합성 + 안전성, 리팩토링은 시스템 맥락 + 엣지 케이스, 버그 수정은 안전성 + 엣지 케이스에 집중하는 것이 효율적인 경우가 많다.
AI 생성 코드에 적합한 PR 구조
AI로 코드를 생성했을 때, PR에 어떤 정보가 포함되면 리뷰어가 맥락을 빠르게 파악할 수 있는지 살펴보면 다음과 같다.
## 개요
<!-- 이 PR이 해결하는 문제 -->
## AI 사용 정보
- **사용 도구**: Claude Code / GitHub Copilot / 기타
- **프롬프트 요약**: (의도를 한 줄로)
- **AI 생성 비율**: 전체 코드의 약 ___%
## 리뷰어 주의사항
<!-- AI가 놓쳤을 수 있는 맥락 -->
- 이 기능은 __와 상호작용한다
- __ 환경에서 테스트가 필요하다
- __ 관련 레거시 코드가 영향받을 수 있다
## AI 코드 리뷰 포인트
- 비즈니스 로직이 요구사항과 일치하는지
- 인증/인가가 올바르게 적용되었는지
- 에러 핸들링이 시스템 관례를 따르는지
- 기존 코드 패턴과 일관성이 있는지
- 엣지 케이스 처리가 되어 있는지
## 테스트
- 단위 테스트 추가/수정 여부
- 통합 테스트 확인 여부
- 수동 테스트 시나리오: __| 섹션 | 목적 | 기존 PR과의 차이 |
|---|---|---|
| AI 사용 정보 | 리뷰어가 AI 특유의 맹점을 인지 | 기존에는 불필요 |
| 리뷰어 주의사항 | AI가 모르는 맥락을 명시 | 기존에는 작성자가 암묵적으로 알고 있음 |
| AI 코드 리뷰 포인트 | AI 코드 특화 관점 | 기존 리뷰와 초점이 다름 |
흥미로운 점은 이런 구조의 PR이 AI 코드뿐 아니라 사람이 작성한 코드에도 유용하다는 것이다. "리뷰어가 알아야 할 맥락을 명시한다"는 원칙은 작성자가 누구든 적용된다.
10분 리뷰 런북
리뷰어가 매번 처음부터 관점을 조합하지 않도록, 10분 기준의 최소 리뷰 루틴을 만들어두면 효과가 크다.
| 시간 | 확인할 것 | 핵심 질문 |
|---|---|---|
| 0-2분 | PR 설명과 AI 활용 범위 | 무엇을 바꾸려는가, 어디까지 AI가 만들었는가 |
| 2-5분 | 의도 정합성과 비즈니스 로직 | 요구사항과 구현이 정확히 맞는가 |
| 5-7분 | 안전성 | 인증/인가, 에러 처리, 데이터 노출 문제가 없는가 |
| 7-9분 | 시스템 맥락과 영향 범위 | 기존 패턴, 성능, 외부 계약을 깨지 않는가 |
| 9-10분 | 테스트와 머지 판단 | 테스트가 의미 있는가, 추가 확인이 필요한가 |
## AI 코드 리뷰 코멘트 템플릿
[의도 확인]
- 이 변경이 해결하려는 문제는 ___로 이해했습니다. 맞나요?
[안전성]
- 인증/인가, 입력 검증, 에러 처리 중 특히 ___를 다시 봐야 합니다.
[맥락]
- 이 코드는 ___ 모듈 / ___ 운영 규칙과의 정합성을 확인해 주세요.
[테스트]
- 현재 테스트는 ___를 검증하지만, ___ 케이스가 빠져 있습니다.
[머지 조건]
- ___ 확인 전에는 머지하지 않는 편이 안전합니다.리뷰의 질을 올리는 핵심은 길게 쓰는 것이 아니라, 같은 관점으로 반복 가능하게 만드는 것이다.
자동화와 사람 리뷰의 역할 분담
기계가 잘하는 것은 기계에게, 사람만 할 수 있는 것은 사람에게 나누는 것이 핵심이다.
자동화 도구 조합
| 영역 | 도구 예시 | 역할 | 투자 대비 효과 |
|---|---|---|---|
| 린트 | ESLint, Biome | 스타일, 패턴 자동 검사 | 매우 높음 |
| 타입 | TypeScript strict | 타입 안전성 보장 | 매우 높음 |
| 테스트 | CI/CD 파이프라인 | 기능 정상 동작 확인 | 높음 |
| 보안 | CodeQL, Snyk | 알려진 취약점 탐지 | 높음 |
| AI 리뷰 | Claude, Copilot Review | 패턴 이상 감지 | 중간 |
AI 리뷰 도구의 한계
AI 리뷰 도구는 유용하지만, AI가 생성한 코드를 같은 AI가 리뷰하면 동일한 맹점을 공유할 수 있다. 실제로 생성 모델과 리뷰 모델이 같은 학습 데이터 기반일 때, 같은 종류의 보안 취약점을 동시에 놓치는 사례가 관찰되었다.
리뷰가 AI를 가르치는 피드백 루프
리뷰는 단방향이 아니다. AI 생성 코드를 리뷰하면서 발견한 패턴을 AI에게 되먹임하면, 다음 생성의 품질이 올라가는 선순환이 형성된다.
피드백 루프의 구조
1단계: 반복되는 리뷰 코멘트 수집
같은 종류의 피드백이 3회 이상 반복되면, CLAUDE.md에 규칙으로 추가하는 것이 효과적이다.
# CLAUDE.md에 추가할 내용 예시
## 코드 작성 규칙
- 에러 핸들링: 모든 API 호출에 try-catch 적용, 에러는 AppError로 래핑
- 날짜 처리: dayjs 사용, 타임존은 항상 KST 명시
- DB 쿼리: N+1 쿼리 금지, 반드시 JOIN 또는 batch 쿼리 사용
- 웹훅: 멱등성 보장 필수, 처리 완료 여부 확인 후 진행2단계: AI가 자주 틀리는 것 목록 관리
| AI가 자주 틀리는 것 | 원인 | CLAUDE.md 대응 |
|---|---|---|
| 인증 미들웨어 누락 | 라우트 보호 규칙 미인지 | 인증 필수 라우트 패턴 명시 |
| KST 타임존 무시 | UTC 기본 가정 | "날짜는 항상 KST" 규칙 |
| 레거시 API 호출 | 최신 API 미인지 | deprecated API 목록 관리 |
| N+1 쿼리 생성 | 관계 조회 패턴 미숙지 | include/JOIN 필수 규칙 |
| 전체 필드 반환 | select 미사용 | API 응답 시 select 필수 |
3단계: 성공 패턴도 기록
AI가 잘 생성한 코드의 패턴도 기록하면, "이 패턴을 따라서"라고 지시할 수 있게 된다. 실패 패턴만 기록하는 것보다 성공 패턴을 함께 관리하는 팀이 프롬프트 품질을 더 빠르게 올리는 경향이 있다.
리뷰 문화의 변화
"누가 짰는가"에서 "무엇이 맞는가"로
AI 시대의 코드 리뷰는 작성자의 역량을 평가하는 자리가 아니라 코드의 정확성과 적합성을 판단하는 품질 보증 프로세스에 가깝다.
이 전환은 예상외로 긍정적인 부수 효과를 가져온다는 보고가 많다.
- 주니어 개발자가 리뷰에서 위축되지 않게 됨
- 코드에 대한 개인적 감정이 줄어듦
- "무엇이 맞는가"에 집중하는 건강한 토론 문화가 형성됨
리뷰 속도와 깊이의 균형
AI가 코드를 빠르게 생성하면서, 리뷰 병목이 커지는 현상이 관찰된다.
| 상황 | 관찰된 대응 |
|---|---|
| AI 생성 PR이 대량으로 올라올 때 | 자동화 게이트 강화, 사람은 핵심 로직만 집중 |
| 리뷰어가 AI 코드에 익숙하지 않을 때 | 팀 세션으로 AI 코드 리뷰 사례 공유 |
| 빠른 머지가 필요할 때 | 자동화 통과 + 시니어 1인 승인으로 간소화 |
코드 리뷰가 새로운 병목이다 — Addy Osmani의 경고 (2026)
Google의 Addy Osmani는 2026년 초 AI 도입 팀에서 관찰되는 심각한 불균형을 데이터로 정리했다.
| 메트릭 | AI 도입 후 변화 | 의미 |
|---|---|---|
| PR 생성량 | 98% 증가 | AI가 코드 생성 속도를 극적으로 높임 |
| 리뷰 시간 | 91% 증가 | 리뷰어가 AI 코드를 이해하는 데 더 오래 걸림 |
| 코드 이해도 | 하락 추세 | "Comprehension debt" 누적 |
Comprehension debt(이해 부채)는 Osmani가 제시한 개념으로, 직접 다시 작성할 수 없는 코드가 코드베이스에 누적되는 현상을 가리킨다. AI가 생성한 코드를 리뷰어가 "동작은 하는 것 같다"고 승인하지만, 그 코드를 스스로 재현하거나 수정할 수 없는 상태가 반복되면, 코드베이스 전체의 유지보수 비용이 급증한다.
Comprehension debt가 위험한 이유
기존 기술 부채는 "나쁜 코드"가 쌓이는 것이었다. Comprehension debt는 **"이해할 수 없는 코드"**가 쌓이는 것이다. AI가 만든 깔끔한 코드조차, 팀이 이해하지 못하면 부채가 된다. PR 98% 증가에 리뷰 역량이 따라가지 못하면, 이 부채는 기하급수적으로 늘어난다.
이 데이터가 시사하는 바는 명확하다. AI 도입의 효과를 체감하려면, 코드 생성 속도만 올려서는 안 되고 리뷰 프로세스의 효율화가 반드시 병행되어야 한다. 이 챕터 앞부분의 10분 리뷰 런북, 자동화와 사람의 역할 분담, PR 구조 표준화가 바로 그 해법에 해당한다.
다음 장 미리보기
코드 리뷰 관점이 전환되었다면, 다음은 테스팅 전략이다. AI 시대에 테스트는 단순한 검증 도구가 아니라, AI에게 구현을 위임하기 위한 작업 지시서 역할을 한다.
참고 자료
참고 자료 안내
이 장의 관점과 프레임워크를 뒷받침하는 참고 자료입니다. 본문의 모든 주장이 아래 자료에서 직접 인용된 것은 아니며, 실무 경험과 커뮤니티 사례를 종합한 해석이 포함되어 있습니다.
- OWASP Foundation. "OWASP Top Ten." https://owasp.org/www-project-top-ten/
- OWASP Foundation. "OWASP Code Review Guide." https://owasp.org/www-project-code-review-guide/
- Osmani, A. (2026). "AI Code Reviews: From 98% More PRs to Comprehension Debt." https://addyosmani.com/blog/ai-code-reviews/