"좋은 PR은 리뷰어에게 주는 선물이다. 나쁜 PR은 리뷰어에게 떠넘기는 숙제다."
프롤로그 — 작성자가 리뷰 지연을 통제한다
"왜 내 PR은 항상 늦게 머지될까?" 많은 개발자가 이 질문의 답을 리뷰어에게서 찾습니다. 리뷰어가 바쁘다, 우선순위가 낮다, 팀이 느리다. 일부는 사실입니다. 하지만 가장 큰 변수는 다른 곳에 있습니다. PR의 리뷰 지연 시간(review latency)은 대부분 작성자가 결정합니다.
리뷰어가 PR을 열었을 때 마주치는 것이 800줄짜리 디프에 설명 한 줄("기능 추가")이라면, 그 PR은 "나중에"로 미뤄집니다. 리뷰어도 사람이고, 큰 인지 부하를 요구하는 작업은 자연스럽게 뒤로 밀립니다. 반대로 120줄짜리 디프에 "무엇을·왜·어떻게 검증했는지"가 또렷하게 적혀 있다면, 리뷰어는 커피를 기다리는 5분 동안 그것을 끝냅니다.
이 글은 코드 리뷰를 하는 법에 관한 글이 아닙니다. 그건 리뷰어의 기술이고, 리뷰 에티켓·머지 큐·리뷰 우선순위는 받는 쪽의 이야기입니다. 이 글은 PR을 쓰는 법 — 작성자가 리뷰어의 일을 쉽고 빠르게 만들기 위해 할 수 있는 모든 것에 관한 글입니다.
좋은 PR은 협상이 아니라 배려다
PR을 "내 코드를 통과시키는 관문"으로 보는 사람과 "리뷰어와 함께 코드를 검증하는 자리"로 보는 사람은 전혀 다른 PR을 만듭니다. 전자는 디프를 크게 만들고, 설명을 짧게 쓰고, 질문에 방어적으로 답합니다. 후자는 디프를 작게 자르고, 맥락을 충분히 적고, 리뷰어가 어디부터 봐야 할지 안내합니다.
배려는 추상적인 덕목이 아닙니다. 측정 가능한 행동입니다 — PR을 작게 자르는 것, 설명에 검증 방법을 적는 것, 포매팅 변경을 분리하는 것, 셀프 리뷰를 먼저 도는 것. 이 글은 그 행동들의 목록입니다.
이 글에서 다룰 내용:
| 장 | 주제 |
|---|---|
| 1장 | 작은 PR이 이기는 이유 — 인지 절벽 |
| 2장 | 하나의 PR = 하나의 아이디어 |
| 3장 | PR 설명 — 가장 중요한 산출물 |
| 4장 | 읽히는 디프 만들기 — 커밋 위생 |
| 5장 | 스택 PR / 스택 디프 |
| 6장 | 리뷰 요청 전 셀프 리뷰 |
| 7장 | 리뷰 피드백에 잘 답하는 법 |
| 8장 | 드래프트 PR과 준비 완료 신호 |
| 9장 | AI 시대의 PR 작성 |
| 에필로그 | 체크리스트 + 안티패턴 + 다음 글 예고 |
1장 · 작은 PR이 이기는 이유
PR 작성의 모든 조언 중 가장 효과가 큰 단 하나를 고르라면, 작게 만들어라입니다. 다른 모든 기술은 이것 위에 쌓입니다.
1.1 리뷰 품질은 PR 크기에 반비례한다
리뷰어의 집중력은 무한하지 않습니다. 디프가 커질수록, 한 줄당 들이는 주의력은 줄어듭니다. 그래서 큰 PR에서는 역설이 생깁니다 — 변경이 많을수록 각 변경은 덜 검토됩니다.
| PR 크기 | 리뷰어의 실제 행동 | 결과 |
|---|---|---|
| ~50줄 | 모든 줄을 읽고 생각한다 | 버그·설계 문제를 잡는다 |
| ~200줄 | 핵심만 읽고 나머지는 훑는다 | 표면적인 것만 잡는다 |
| ~500줄 | "큰 문제 없어 보이네" 하고 승인 | 사실상 검토 안 됨 |
| 1000줄+ | 죄책감과 함께 승인하거나 무한정 미룬다 | 리뷰가 형식이 된다 |
500줄짜리 PR에 달린 "LGTM"은 리뷰가 아니라 항복입니다. 작성자가 정말 원하는 것이 검토라면, 검토 가능한 크기로 줘야 합니다.
1.2 인지 절벽
PR 크기와 리뷰 품질의 관계는 선형이 아닙니다. 어느 지점을 넘으면 급격히 떨어지는 절벽(cliff) 이 있습니다. 정확한 숫자는 팀과 코드베이스마다 다르지만, 경험적으로 그 절벽은 대략 200~400줄 사이에 있습니다.
절벽 아래에서 리뷰어는 PR 전체를 머릿속에 한 번에 담을 수 있습니다. 절벽 위에서는 그게 불가능해지고, 리뷰어는 PR을 "조각으로" 읽기 시작합니다. 조각으로 읽으면 조각 사이의 상호작용 — 가장 버그가 많이 숨는 곳 — 을 놓칩니다.
목표는 단순합니다. 모든 PR을 절벽 아래에 두는 것. 작업이 크면 작업을 자르는 것이지, PR을 키우는 것이 아닙니다.
1.3 작은 PR의 복리 효과
작은 PR은 리뷰 품질만 올리는 게 아닙니다.
- 빠른 피드백 — 작은 PR은 빨리 리뷰되고, 빨리 머지되고, 빨리 배포됩니다. 잘못된 방향이면 일찍 알게 됩니다.
- 쉬운 롤백 — 문제가 생겼을 때 되돌릴 단위가 작습니다. 800줄 중 어디가 문제인지 찾는 대신, 80줄짜리 PR 하나를 되돌립니다.
- 적은 충돌 — 작은 PR은 오래 살지 않으므로
main과 멀어질 시간이 없습니다. 리베이스 지옥이 줄어듭니다. - 명확한 히스토리 —
git log가 "기능 추가" 같은 거대 커밋이 아니라, 의미 단위의 변경 기록이 됩니다.
작게 만드는 것은 비용이 아니라 투자입니다. 자르는 데 드는 10분이, 큰 PR이 만드는 며칠의 지연을 막습니다.
2장 · 하나의 PR = 하나의 아이디어
작게 만드는 것만큼 중요한 것이 하나만 담는 것입니다. 크기가 작아도 두 개의 무관한 변경이 섞이면 리뷰는 어려워집니다.
2.1 "섞인 PR 금지" 규칙
가장 흔하고 가장 해로운 안티패턴은 리팩터링과 동작 변경을 한 PR에 섞는 것입니다.
리뷰어가 변경된 함수를 봅니다. 이름이 바뀌었고, 위치가 옮겨졌고, 들여쓰기가 달라졌고, 그리고 그 안에서 if 조건 하나가 바뀌었습니다. 리뷰어는 이제 질문할 수 없습니다 — "이 동작 변경이 의도된 것인가, 아니면 리팩터링하다 실수한 것인가?" 노이즈가 시그널을 덮었습니다.
규칙은 단순합니다.
하나의 PR은 하나의 아이디어만 담는다. 리팩터링과 동작 변경은 절대 같은 PR에 넣지 않는다.
순서도 정해져 있습니다. 리팩터링 먼저, 동작 변경 나중. 리팩터링 PR은 "동작은 동일함, 구조만 변경"이라고 선언하면 리뷰어가 빠르게 훑을 수 있습니다. 그다음 동작 변경 PR은 깨끗한 토대 위에서 작은 디프로 들어옵니다.
2.2 무엇이 "하나의 아이디어"인가
| 잘못된 묶음 | 올바르게 자른 PR |
|---|---|
| 기능 A + 기능 A를 위한 리팩터링 + 무관한 오타 수정 | PR 1: 리팩터링 / PR 2: 기능 A / PR 3: 오타 |
| 버그 수정 + "하는 김에" 한 의존성 업그레이드 | PR 1: 의존성 업그레이드 / PR 2: 버그 수정 |
| 새 API 엔드포인트 + 전체 파일 포매팅 | PR 1: 포매팅 / PR 2: 엔드포인트 |
| 기능 + 그 기능의 테스트 | 한 PR에 둘 다 — 테스트는 기능의 일부다 |
마지막 줄이 핵심입니다. "하나의 아이디어"는 "하나의 파일"이나 "하나의 커밋"이 아닙니다. 기능과 그 기능의 테스트는 같은 아이디어이므로 함께 갑니다. 반면 기능과 무관한 오타는 작아도 다른 아이디어이므로 분리합니다.
2.3 "하는 김에"는 경고음이다
PR을 만들다 보면 유혹이 옵니다 — "이 파일 보는 김에 저 죽은 코드도 지우자", "여기 온 김에 저 변수명도 고치자". 이 "하는 김에"가 바로 섞인 PR이 태어나는 순간입니다.
원칙: "하는 김에"가 떠오르면 멈추고, 그것을 별도 PR이나 티켓으로 만든다. 좋은 발견을 버리라는 게 아닙니다. 그 발견을 별도의 리뷰 가능한 단위로 옮기라는 것입니다.
3장 · PR 설명 — 가장 중요한 산출물
PR에서 가장 많이 쓰이고 가장 적게 공들여지는 부분이 설명(description) 입니다. 많은 작성자가 디프를 쓰는 데 두 시간을 쓰고 설명에 20초를 씁니다. 이건 거꾸로입니다.
3.1 설명은 디프가 답하지 못하는 것을 답한다
디프는 무엇이(what) 바뀌었는지를 보여줍니다. 디프가 절대 보여주지 못하는 것은 왜(why) 입니다. 그리고 리뷰의 핵심 질문은 거의 항상 "왜"입니다 — "왜 이렇게 했는가", "왜 다른 방법이 아닌가", "왜 지금인가".
설명이 없으면 리뷰어는 "왜"를 추측해야 하고, 추측은 틀리고, 틀린 추측 위에 달린 리뷰 코멘트는 작성자와 리뷰어 모두의 시간을 태웁니다.
3.2 좋은 PR 설명의 여섯 가지 요소
| 요소 | 답해야 할 질문 | 없으면 생기는 일 |
|---|---|---|
| 무엇(What) | 이 PR이 무엇을 바꾸는가? | 리뷰어가 디프 전체를 읽고 요약해야 한다 |
| 왜(Why) | 왜 이 변경이 필요한가? | 리뷰어가 의도를 추측한다 |
| 어떻게(How) | 어떤 접근을 택했고 왜 그것인가? | 설계 의도가 전달되지 않는다 |
| 검증(Verification) | 어떻게 확인했는가? | "테스트는 했나요?" 왕복이 발생한다 |
| 범위 밖(Out of scope) | 이번에 하지 않는 것은? | "이것도 고쳐야 하는 거 아닌가요?" 코멘트가 달린다 |
| 시각 자료(Screenshots) | UI 변경이 어떻게 보이는가? | 리뷰어가 직접 브랜치를 받아 띄운다 |
이 여섯 가지 중 "범위 밖" 이 가장 자주 빠지고 가장 효과가 큽니다. "이 PR은 X를 하지 않습니다 — 그건 후속 PR입니다"라는 한 줄이, 리뷰어가 달려던 코멘트 다섯 개를 미리 막습니다.
3.3 리뷰어를 위한 읽기 가이드
큰 변경이 불가피할 때(예: 자동 생성된 파일이 포함될 때), 설명에 읽는 순서를 적어줍니다.
## 리뷰 가이드
- 핵심 로직은 `src/auth/session.ts` 입니다. 여기부터 보세요.
- `src/generated/*` 는 codegen 산출물입니다. 훑고 넘어가도 됩니다.
- `package-lock.json` 변경은 의존성 추가의 부수 효과입니다.
이 한 블록이 "디프가 600줄"이라는 사실의 체감 무게를 "실제로 봐야 할 건 80줄"로 바꿉니다.
3.4 복사해서 쓰는 PR 설명 템플릿
아래는 그대로 복사해 .github/pull_request_template.md 로 쓰거나, 팀 위키에 박제해 둘 수 있는 템플릿입니다. 바깥 펜스가 네 개의 백틱인 이유는 안쪽에 코드 블록과 ## 헤더가 들어 있기 때문입니다.
## 무엇 (What)
{이 PR이 바꾸는 것을 한두 문장으로}
## 왜 (Why)
{이 변경이 필요한 이유. 연결된 이슈: #123}
## 어떻게 (How)
{택한 접근과 그 이유. 고려했지만 버린 대안이 있으면 한 줄}
## 검증 (How to verify)
- [ ] {리뷰어가 따라 할 수 있는 확인 단계}
- [ ] {추가한/수정한 테스트}
- [ ] {수동 확인 절차 — 있으면}
```bash
# 재현/검증 명령 — 있으면
npm test -- src/auth
```
## 범위 밖 (Out of scope)
- {이번에 하지 않는 것 — 그리고 어디서 다룰지}
## 스크린샷 (UI 변경 시)
| 변경 전 | 변경 후 |
| --- | --- |
| {img} | {img} |
## 리뷰 가이드 (디프가 클 때)
- {어디부터 보면 되는지}
- {훑고 넘어가도 되는 파일}
칸을 다 채울 필요는 없습니다. UI 변경이 없으면 스크린샷 칸은 지웁니다. 하지만 무엇·왜·검증 세 칸은 어떤 PR에도 남깁니다. 이 세 칸이 리뷰 지연의 90%를 줄입니다.
3.5 제목도 설명이다
PR 제목은 git log에 영원히 남습니다. "fix", "update", "wip" 같은 제목은 6개월 뒤 아무 정보도 주지 않습니다.
- 나쁨:
update - 나쁨:
버그 수정 - 좋음:
auth: 세션 만료 시 토큰 자동 갱신 추가 - 좋음:
fix: 빈 장바구니에서 결제 버튼 비활성화
규칙: 제목은 "이 PR이 머지되면 무엇이 달라지는가"를 한 줄로 말한다. 접두어(auth:, fix:)로 영역과 종류를 신호하면 더 좋습니다.
4장 · 읽히는 디프 만들기 — 커밋 위생
PR을 작게, 하나의 아이디어로 만들었어도, 그 안의 커밋이 엉망이면 리뷰는 여전히 어렵습니다. 디프는 읽히도록 구성되어야 합니다.
4.1 논리적 커밋
리뷰어는 PR을 두 가지 방식으로 봅니다 — 전체 디프를 한 번에, 또는 커밋을 하나씩. 후자가 가능하려면 커밋이 논리적 단위여야 합니다.
| 나쁜 커밋 히스토리 | 좋은 커밋 히스토리 |
|---|---|
wip | auth: SessionToken 타입 추가 |
fix | auth: 토큰 만료 검사 로직 구현 |
fix again | auth: 만료 임박 시 자동 갱신 연결 |
oops | test: 세션 갱신 시나리오 테스트 추가 |
address review | (리뷰 반영은 4.3 참고) |
좋은 히스토리에서 리뷰어는 커밋 하나하나를 따라가며 "이 변경이 왜 이 순서로 일어났는지"를 이해할 수 있습니다. 각 커밋은 그 자체로 빌드·테스트를 통과하는 것이 이상적입니다.
4.2 포매팅 변경은 따로
자동 포매터(Prettier, gofmt, black 등)를 돌리면 의미 없는 줄들이 디프를 가득 채웁니다. 이 줄들이 진짜 변경을 덮습니다.
원칙: 포매팅·이름 변경 같은 기계적 변경은 별도 커밋, 가능하면 별도 PR로 분리한다. "전체 파일 포매팅" 커밋 하나는 리뷰어가 git diff -w(공백 무시)로 1초 만에 훑고 넘어갈 수 있습니다. 하지만 그게 동작 변경과 같은 커밋에 섞이면, 리뷰어는 한 줄 한 줄 봐야 합니다.
4.3 리뷰 전 히스토리 정리
PR을 올리기 전, 작업 중 쌓인 wip / fix / oops 커밋을 정리합니다.
# 작업 브랜치에서: 마지막 5개 커밋을 논리 단위로 재구성
git rebase -i HEAD~5
# 또는 전부 합쳐서 다시 논리적으로 쪼개기
git reset --soft main
git add -p # 의미 단위로 골라 담기
주의: 이미 리뷰가 시작된 PR에서는 함부로 히스토리를 갈아엎지 않습니다(4.3 후반과 7장 참고). 정리는 첫 리뷰 요청 전에 끝내는 것이 원칙입니다.
4.4 한 줄짜리 무관한 변경을 섞지 않기
디프에 import 순서만 바뀐 줄, 안 쓰는 공백이 지워진 줄이 끼어 있으면 리뷰어는 "이건 의도된 건가?"를 매번 멈춰서 판단해야 합니다. 에디터가 자동으로 만든 변경은 커밋 전에 git add -p로 걸러냅니다.
5장 · 스택 PR / 스택 디프
작업을 작게 자르려는데 변경들이 서로 의존할 때가 있습니다. PR 2가 PR 1의 코드 위에서만 동작하는 경우입니다. 이때 스택 PR(stacked PRs) 이 답입니다.
5.1 스택 PR이란
스택 PR은 PR을 일렬로 쌓는 것입니다. 각 PR은 main이 아니라 바로 아래 PR의 브랜치를 베이스로 합니다.
main
└─ PR 1: auth 타입 추가 (base: main)
└─ PR 2: 토큰 검증 로직 (base: PR 1)
└─ PR 3: 자동 갱신 UI 연결 (base: PR 2)
리뷰어는 PR 1부터 차례로 봅니다. 각 PR은 작고, 하나의 아이디어만 담고, 디프는 바로 아래 PR과의 차이만 보여줍니다. 800줄짜리 단일 PR이 200줄짜리 PR 네 개가 됩니다.
5.2 언제 스택을 쓰는가
| 상황 | 스택? |
|---|---|
| 큰 기능을 의존성 있는 단계로 나눌 수 있다 | 예 — 전형적인 스택 사용처 |
| 리팩터링 → 그 위에 동작 변경 | 예 — PR 1 리팩터, PR 2 동작 |
| 변경들이 서로 독립적이다 | 아니오 — 그냥 별도 PR을 병렬로 |
| 단계가 다섯 개를 넘어간다 | 주의 — 너무 깊은 스택은 관리 비용이 큼 |
스택은 의존성이 있을 때만 씁니다. 독립적인 변경을 굳이 쌓으면, 아래 PR이 막혔을 때 위 PR도 같이 막힙니다.
5.3 스택 운영의 현실
스택의 가장 큰 비용은 베이스 PR이 바뀌면 위의 모든 PR을 리베이스해야 한다는 것입니다.
# PR 1이 리뷰 반영으로 바뀜 → PR 2를 PR 1 위로 다시 리베이스
git checkout pr-2-branch
git rebase pr-1-branch
# 스택 전체 갱신은 도구의 도움을 받는 게 낫다
# (Graphite, Sapling, spr 등 스택 전용 도구)
손으로 스택을 관리하면 리베이스가 금방 지옥이 됩니다. 스택을 자주 쓰는 팀은 스택 전용 도구(Graphite, Sapling, spr, ghstack 등)를 도입하는 것이 거의 필수입니다. 도구가 스택 전체의 리베이스·재제출을 한 번에 처리해 줍니다.
5.4 스택을 쓸 수 없을 때의 차선책
스택 도구가 없거나 팀이 스택에 익숙하지 않다면, 차선책은 하나의 PR 안에서 논리적 커밋으로 단계를 나누는 것입니다(4.1 참고). 리뷰어에게 "커밋 단위로 봐주세요"라고 설명에 적습니다. 스택만큼 깔끔하지는 않지만, 거대 단일 디프보다는 훨씬 낫습니다.
6장 · 리뷰 요청 전 셀프 리뷰
리뷰 요청 버튼을 누르기 전에 해야 할 일이 하나 있습니다. 자기 PR을 리뷰어의 눈으로 한 번 보는 것.
6.1 왜 셀프 리뷰가 효과적인가
작업 중에는 코드를 "쓰는 사람"의 시점에 갇혀 있습니다. PR을 올리고 디프 화면에서 다시 보면 시점이 바뀝니다. 에디터에서는 안 보이던 것들이 디프 뷰에서 보입니다 — 두고 온 console.log, 주석 처리한 코드, 디버그용 하드코딩, 안 지운 TODO, 빠진 에러 처리.
리뷰어가 이런 것을 잡아주길 기대하면 안 됩니다. 그건 리뷰어의 주의력을 사소한 것에 쓰게 만들고, 정작 설계 를 볼 여력을 빼앗습니다.
6.2 셀프 리뷰 체크리스트
리뷰 요청 전, GitHub/GitLab의 "Files changed" 탭을 열고 한 줄씩 봅니다.
- 디버그 흔적이 없는가 (
console.log,print, 주석 처리된 코드, 하드코딩된 값) - 무관한 변경이 섞이지 않았는가 (포매팅, import 순서, 우연한 공백)
- 모든 새 분기에 테스트가 있는가
- 에러·엣지 케이스가 처리되었는가 (빈 값, null, 실패 경로)
- PR 설명의 "검증" 칸을 내가 실제로 따라 할 수 있는가
- 디프가 절벽 아래인가 — 아니라면 자를 수 있는가
- 커밋 히스토리가 논리적인가
- 리뷰어가 처음 마주칠 줄이 가장 중요한 줄인가
마지막 항목이 미묘합니다. 디프 안에서 가장 중요한 변경이 가장 잘 보이도록 파일 순서나 커밋 순서를 조정할 수 있습니다.
6.3 셀프 리뷰는 시간을 절약한다
셀프 리뷰에 5분을 쓰면, 리뷰 왕복이 한 번 줄어듭니다. 리뷰 왕복 한 번은 보통 반나절에서 하루입니다(리뷰어가 다시 시간을 낼 때까지의 대기 포함). 5분 대 반나절. 이보다 수익률 높은 투자는 드뭅니다.
7장 · 리뷰 피드백에 잘 답하는 법
PR을 올리면 코멘트가 달립니다. 여기서 작성자의 태도가 다음 PR의 리뷰 속도까지 결정합니다.
7.1 모든 코멘트에 응답한다
리뷰 코멘트는 두 가지로 끝나야 합니다 — 반영했거나, 반영하지 않은 이유를 설명했거나. 무응답으로 남은 코멘트는 리뷰어에게 "내 의견이 무시됐다"는 신호를 줍니다.
| 코멘트 유형 | 좋은 응답 |
|---|---|
| 명백한 버그 지적 | 고치고 "수정했습니다 (커밋 abc123)" |
| 더 나은 접근 제안 | 동의하면 반영, 아니면 "이 방법을 택한 이유는 X입니다. 어떻게 생각하세요?" |
| 취향 차이 | 사소하면 그냥 반영(논쟁 비용 > 반영 비용), 또는 팀 컨벤션을 근거로 |
| 질문 | 코드가 아니라 코멘트로 답하고, 필요하면 코드에 주석 추가 |
| 범위 밖 제안 | "좋은 지적입니다. 이번 PR 범위 밖이라 #456 으로 만들었습니다" |
7.2 방어하지 말고 이해하라
리뷰 코멘트를 공격으로 받아들이면 응답이 방어적이 됩니다. 방어적인 응답은 리뷰어를 지치게 하고, 다음번에 그 작성자의 PR을 꼼꼼히 보고 싶지 않게 만듭니다.
코멘트가 틀린 것 같을 때조차, 첫 반응은 "왜 리뷰어가 이렇게 봤을까" 입니다. 리뷰어가 오해했다면, 그 오해 자체가 정보입니다 — 코드가 그렇게 오해될 만큼 불명확하다는 뜻이니까요. 코드를 명확하게 고치거나, 주석을 추가합니다.
7.3 리뷰 반영 커밋을 어떻게 쌓을까
리뷰가 이미 시작된 PR에서는 새 커밋으로 반영하는 것이 기본입니다. address review feedback 같은 커밋을 추가하면, 리뷰어가 "1차 리뷰 이후 무엇이 바뀌었는지"만 따로 볼 수 있습니다. 이미 본 부분을 다시 볼 필요가 없습니다.
머지 직전, 팀 컨벤션에 따라 이 커밋들을 squash 할 수 있습니다. 핵심은 리뷰가 진행 중인 동안에는 히스토리를 보존하고, 머지 시점에 정리하는 것입니다. 리뷰 도중 force-push로 히스토리를 갈아엎으면 리뷰어가 자기 코멘트의 맥락을 잃습니다.
8장 · 드래프트 PR과 준비 완료 신호
PR에는 두 가지 상태가 있습니다 — "아직 보지 마세요"와 "이제 봐주세요". 이 둘을 명확히 신호하지 않으면 리뷰어의 시간이 낭비됩니다.
8.1 드래프트 PR의 용도
드래프트(Draft) PR은 "코드는 올라왔지만 아직 리뷰 요청은 아니다"라는 명시적 신호입니다. 쓰는 경우:
- CI를 미리 돌려보고 싶을 때 — 빌드·테스트 결과만 먼저 확인
- 방향에 대한 조기 피드백을 받고 싶을 때 — "전체를 보지 말고, 이 접근이 맞는지만 봐주세요"라고 명시
- 작업이 진행 중임을 팀에 보이고 싶을 때 — 중복 작업 방지
드래프트의 핵심은 리뷰어의 기대를 관리하는 것입니다. 드래프트에 "방향만 봐주세요"라고 적으면, 리뷰어는 변수명이나 테스트 누락을 지적하지 않습니다 — 그건 아직 볼 단계가 아니니까요.
8.2 "준비 완료"를 명확히 신호하라
드래프트를 "Ready for review"로 전환하는 것 자체가 신호입니다. 하지만 그것만으로는 부족할 때가 있습니다.
- 드래프트에서 받은 조기 피드백을 반영했다면, 무엇을 바꿨는지 코멘트로 남깁니다.
- 리뷰 요청 시 누구에게 요청하는지 명확히 합니다 — "아무나"는 보통 "아무도"가 됩니다.
- PR이 다른 PR이나 배포에 블로킹이라면 그 긴급성을 적습니다.
8.3 드래프트를 방치하지 마라
오래된 드래프트 PR은 노이즈입니다. 며칠째 멈춰 있는 드래프트는 팀에게 "이 작업이 살아 있는가 죽었는가"를 헷갈리게 합니다. 드래프트는 활성 작업일 때만 열어두고, 멈췄으면 닫거나 상태를 코멘트로 남깁니다.
9장 · AI 시대의 PR 작성
2026년, PR 작성의 풍경이 바뀌었습니다. 코드의 상당 부분을 AI 에이전트가 생성하고, PR 설명도 AI가 초안을 잡을 수 있습니다. 하지만 핵심 원칙은 바뀌지 않았습니다 — 오히려 더 중요해졌습니다.
9.1 AI가 잘하는 것: 설명 초안과 셀프 리뷰
AI는 PR 작성의 특정 부분에서 탁월합니다.
- PR 설명 초안 — 디프를 입력으로 주면 "무엇·어떻게"를 요약해 줍니다. 단, "왜" 는 사람만 압니다 — AI 초안의 "왜" 칸은 작성자가 반드시 다시 씁니다.
- 셀프 리뷰 보조 — "이 디프에서 두고 온 디버그 코드, 빠진 에러 처리, 테스트 없는 분기를 찾아줘"는 AI가 잘하는 작업입니다. 6장의 체크리스트를 AI에게 1차로 돌리게 할 수 있습니다.
- 커밋 메시지 정리 — 논리적 커밋으로 재구성할 때 메시지 초안을 잡아줍니다.
9.2 AI가 못하는 것: 책임과 맥락
AI가 절대 대신할 수 없는 것이 있습니다.
- "왜"의 진짜 맥락 — 이 변경이 어떤 사업적·기술적 결정에서 나왔는지는 사람의 머릿속에만 있습니다.
- 검토되지 않은 출력에 대한 책임 — PR에 올린 코드는, AI가 썼든 사람이 썼든, 작성자가 보증하는 코드입니다.
9.3 절대 하지 말 것: 검토되지 않은 에이전트 출력 덤프
AI 시대의 가장 해로운 안티패턴은 이것입니다 — 에이전트가 생성한 코드를 작성자가 읽지도 않고 PR로 올리는 것.
이건 리뷰어에게 "내가 안 본 코드를 당신이 봐주세요"라고 말하는 것과 같습니다. 리뷰의 사회적 계약이 깨집니다. 리뷰어는 "작성자가 한 번 검토한 코드"를 검토한다고 가정하는데, 그 가정이 거짓이 되면 리뷰어는 작성자가 했어야 할 1차 검토까지 떠안게 됩니다.
규칙: AI가 생성한 코드도 사람이 쓴 코드와 똑같은 PR 기준을 통과해야 한다. 작게 자르고, 하나의 아이디어만 담고, 작성자가 셀프 리뷰를 돌고, 작성자가 모든 줄을 이해하고 보증한다. AI는 디프를 빨리 만들어 줄 뿐, 리뷰 가능하게 만드는 책임은 여전히 작성자의 것입니다.
9.4 AI 시대에 작은 PR이 더 중요해진 이유
AI는 코드를 빠르게, 많이 만들 수 있습니다. 이것은 작은 PR 원칙을 더 중요하게 만듭니다 — 생성 속도가 빨라질수록, 그것을 검토 가능한 단위로 자르는 규율이 없으면 리뷰어는 더 빨리 익사합니다.
AI는 작성 속도를 올렸을 뿐, 리뷰 대역폭을 올리지 않았습니다. 그 격차를 메우는 것이 작성자의 PR 작성 기술입니다.
에필로그 — 좋은 PR은 리뷰어에게 주는 선물이다
PR의 리뷰 지연 시간은 작성자가 통제합니다. 리뷰어가 느린 게 아니라, 리뷰 불가능한 PR이 느린 것입니다. 작게 자르고, 하나의 아이디어만 담고, 설명에 "왜"와 "검증"을 적고, 디프를 읽히게 구성하고, 올리기 전에 셀프 리뷰를 돌면 — 같은 리뷰어가 같은 코드를 몇 배 빠르게 승인합니다.
이건 리뷰어를 위한 호의이자, 결국 작성자 자신을 위한 일입니다. 빠른 리뷰는 빠른 머지이고, 빠른 머지는 빠른 피드백이며, 빠른 피드백은 잘못된 방향을 일찍 잡습니다. 좋은 PR을 쓰는 기술은 협업 스킬인 동시에, 자기 작업의 사이클을 짧게 만드는 기술입니다.
리뷰 가능한 PR 체크리스트
- 크기 — 디프가 인지 절벽 아래다 (대략 200~400줄 미만)
- 하나의 아이디어 — 리팩터링과 동작 변경을 섞지 않았다
- 무엇 — PR 설명이 바뀐 것을 한두 문장으로 요약한다
- 왜 — 이 변경이 필요한 이유가 적혀 있다 (AI 초안이라면 사람이 다시 썼다)
- 검증 — 리뷰어가 따라 할 수 있는 확인 단계가 있다
- 범위 밖 — 이번에 하지 않는 것이 명시되어 있다
- 시각 자료 — UI 변경이면 스크린샷이 붙어 있다
- 커밋 위생 — 커밋이 논리적 단위이고, 포매팅이 분리되어 있다
- 셀프 리뷰 — "Files changed"를 한 줄씩 봤고 디버그 흔적이 없다
- 신호 — 드래프트/준비 완료 상태와 리뷰 대상자가 명확하다
피해야 할 안티패턴
- 거대 PR — 800줄에 "기능 추가" 한 줄. LGTM은 항복이지 리뷰가 아니다
- 섞인 PR — 리팩터링 + 동작 변경 + 오타가 한 디프에. 시그널이 노이즈에 묻힌다
- "하는 김에" — 무관한 변경을 슬쩍 끼워 넣지 않는다. 별도 PR/티켓으로
- 빈 설명 — "왜"와 "검증" 없이 디프만 던지지 않는다
- 포매팅 혼입 — 자동 포매터 결과를 동작 변경과 같은 커밋에 섞지 않는다
- 방어적 응답 — 리뷰 코멘트를 공격으로 받지 않는다. 오해는 코드가 불명확하다는 정보다
- 리뷰 중 force-push — 리뷰가 진행 중일 때 히스토리를 갈아엎지 않는다
- 에이전트 출력 덤프 — 자기가 안 읽은 AI 코드를 PR로 올리지 않는다
다음 글 예고
다음 글은 **"리뷰어의 기술 — 빠르고 친절하고 엄격한 코드 리뷰를 하는 법"**입니다. 이번 글이 PR을 쓰는 쪽의 기술이었다면, 다음 글은 PR을 읽는 쪽의 기술입니다. 무엇을 먼저 보는지, 어떤 코멘트가 도움이 되고 어떤 코멘트가 노이즈인지, 승인과 변경 요청의 기준선을 어디에 두는지 — 그리고 AI 리뷰 봇과 사람 리뷰어의 역할을 어떻게 나누는지를 다룹니다.
좋은 PR을 쓰는 데 드는 10분은, 리뷰 왕복 한 번의 반나절을 막습니다. 그 10분은 리뷰어에게 주는 선물이자, 미래의 자신에게 보내는 투자입니다.
현재 단락 (1/196)
"왜 내 PR은 항상 늦게 머지될까?" 많은 개발자가 이 질문의 답을 리뷰어에게서 찾습니다. 리뷰어가 바쁘다, 우선순위가 낮다, 팀이 느리다. 일부는 사실입니다. 하지만 가장 큰 ...