리뷰 단계가 늘어날수록 팀은 느려진다
코드 리뷰를 많이 한다고 코드가 좋아지지는 않습니다. 과도한 리뷰 절차가 병목을 만들고 개발자를 지치게 하며 오히려 코드 품질을 떨어뜨리는 이유를 살펴봅니다.

한 스타트업이 버그를 프로덕션에 배포합니다. 경영진의 대응은 코드 리뷰 필수화입니다. 또 다른 버그가 빠져나가자 리뷰어를 두 명으로 늘립니다. 그 다음엔 보안 사고가 나고, 보안 리뷰 단계가 추가됩니다. 이어서 디자인 일관성 문제가 생기면 디자인 리뷰가 붙습니다. 2년 뒤에는 아주 작은 변경이라도 네 단계의 리뷰를 거치고, 병합까지 3일이 걸립니다. 한때 매일 배포하던 개발자들은 이제 코드를 짜는 시간보다 리뷰하는 시간이 더 많아졌습니다.
이 패턴은 조직 행동의 법칙이라고 부를 만큼 흔합니다. 사고가 날 때마다 리뷰 단계가 하나씩 생기지만, 한 번 생긴 리뷰 단계가 없어지는 경우는 거의 없습니다. 그 결과 리뷰 절차는 지난번 사고를 막는 데만 최적화되고, 앞으로의 진행을 막는 대가를 치르게 됩니다.
리뷰 대기열의 수학
리뷰 단계는 단순히 더해지는 게 아니라 곱해지며 누적됩니다. 리뷰 한 번이 평균 4시간 걸린다고 해봅시다. 실제 리뷰에 걸리는 시간은 20분뿐이고, 나머지는 PR이 리뷰어의 차례를 기다리며 대기열에 머무는 시간입니다. 그러면 순차적인 리뷰 두 번은 8시간, 세 번은 12시간, 네 번은 16시간이 걸립니다.
실제로는 여기서 끝나지 않습니다. 컨텍스트 전환 비용이 있기 때문입니다. 개발자가 PR을 올리고 다른 작업을 시작하면, 몇 시간 뒤 리뷰 피드백이 도착했을 때 이전 작업으로 다시 돌아가야 합니다. 맥락을 다시 불러오고, 피드백을 반영하고, 다시 제출한 뒤 또 기다려야 합니다. 리뷰 라운드 한 번마다 대기열 시간 외에 30~60분의 컨텍스트 전환 비용이 추가로 듭니다.
여기에 연쇄 효과까지 더해집니다. 리뷰어 A가 수정을 요청하면 개발자가 반영하고 다시 제출합니다. 그러면 아직 PR을 보지 않은 리뷰어 B가 검토하면서 전혀 다른 수정을 요청합니다. 개발자가 이것도 반영하고 나면, A는 자신의 피드백이 제대로 반영됐는지 다시 확인해야 하는데 이미 다른 일을 하고 있고 PR은 다시 대기열 뒤로 밀려 있습니다.
Timeline of a PR through a 3-reviewer process:
Day 1 9:00 — Developer submits PR
Day 1 14:00 — Reviewer A reviews, requests changes
Day 1 15:00 — Developer addresses feedback, resubmits
Day 2 10:00 — Reviewer B reviews, requests different changes
Day 2 11:00 — Developer addresses, resubmits
Day 2 16:00 — Reviewer A re-reviews, approves
Day 3 11:00 — Reviewer C reviews, approves
Day 3 11:30 — Reviewer B re-reviews, approves
Day 3 12:00 — PR merges
Elapsed time: ~3 business days
Actual review time: ~90 minutes total
Actual code change time: ~2 hours
Time waiting in queues: ~22 hours
Queue time is 80% of the total elapsed time.
품질의 역설
리뷰 단계를 추가하는 근거는 리뷰를 많이 할수록 코드가 좋아진다는 가정입니다. 이 말은 어느 지점까지는 맞지만, 그 이후에는 거꾸로 됩니다.
꼼꼼한 리뷰어 한 명이면 실제 문제를 잡아냅니다. 로직 오류, 놓친 예외 케이스, 보안 문제, API 설계 문제 같은 것들이죠. 두 번째 리뷰어는 첫 번째가 놓친 것을 가끔 잡아내는데, 대략 10~20% 정도입니다. 세 번째 리뷰어는 앞의 두 명이 놓친 것을 거의 잡지 못합니다. 리뷰어를 한 명 추가할 때마다 얻는 한계 가치가 급격히 떨어지는 것입니다.
한편 병합이 느려지는 데서 오는 품질 비용은 실재하지만 아무도 계산하지 않습니다. 오래 살아남은 브랜치는 main과 점점 어긋나고, 그러면 리베이스가 필요해지며 그 과정에서 병합 오류가 생깁니다. 개발자들은 PR마다 드는 리뷰 부담을 피하려고 변경 사항을 한꺼번에 묶어 올리고, 그러면 PR이 커져서 꼼꼼히 검토하기가 더 어려워집니다. 리뷰어도 지칩니다. 대기열에 PR이 15개나 쌓여 있으면 꼼꼼히 읽기보다 대충 훑어보게 됩니다.
역설은 이것입니다. 품질을 높이려고 리뷰 단계를 더하는 행위가 오히려 품질을 떨어뜨릴 수 있습니다. 큰 PR, 급하게 끝내는 리뷰, 오래된 브랜치 같은 인센티브가 생기고, 이것이 리뷰 과정 자체를 무너뜨리기 때문입니다.
무거운 리뷰 절차가 실제로 막아주는 것
리뷰 절차는 대개 특정 사고를 근거로 정당화됩니다. '아무도 코드를 리뷰하지 않아서 버그가 나갔다'는 식이죠. 하지만 리뷰가 특정 버그를 잡았을지 묻는 것과, 리뷰 필수화가 전체 결과를 개선하는지 묻는 것은 전혀 다른 질문입니다.
코드 리뷰의 효과를 분석한 연구들을 보면, 리뷰가 잡아내는 결함은 대략 60% 정도입니다. 그마저도 대부분 네이밍, 포매팅, 눈에 띄는 로직 오류 같은 표면적인 문제입니다. 깊은 아키텍처 버그, 동시성 문제, 보안 취약점은 변경 사항(diff)만 봐서는 잡히기 어렵습니다. 전체 시스템을 이해해야 찾을 수 있기 때문입니다. 결국 프로덕션 사고를 일으키는 버그는 리뷰로 잡히지 않는 유형에 불균형하게 몰려 있습니다.
실제로 프로덕션 사고를 막는 것은 테스트, 모니터링, 그리고 빠르게 배포하고 되돌릴 수 있는 능력입니다. 좋은 테스트와 피처 플래그, 즉시 롤백이 갖춰진 채 빠르게 배포하는 팀이, 리뷰 단계는 네 개인데 통합 테스트가 없고 배포 주기가 한 시간씩 걸리는 팀보다 프로덕션 사고가 적습니다.
적절한 리뷰의 양
코드 리뷰는 분명 가치가 있습니다. PR마다 리뷰어를 한 명 두고, 무엇을 봐야 하는지 명확히 정해두는 것이 대부분의 팀에게 가장 적절한 균형점입니다. 실제로 어떻게 하면 되는지 살펴보겠습니다.
- 두 명, 세 명이 아니라 한 명입니다. 첫 번째 리뷰어가 리뷰로 잡을 수 있는 것의 80%를 잡아냅니다. 두 번째 리뷰어가 더하는 가치는 미미한데 드는 비용은 큽니다. 다중 리뷰는 정말 위험도가 높은 변경(데이터베이스 마이그레이션, 인증 변경, 공개 API 수정)에만 남겨두세요.
- 리뷰 대기열에 시간 제한을 두세요. PR이 4시간 안에 리뷰되지 않는다면 이는 리뷰어가 게으른 문제가 아니라 프로세스의 실패입니다. 팀이 리뷰 여력에 우선순위를 두거나, 리뷰 프로세스가 감당할 수 있는 것보다 개발자가 많다는 사실을 받아들여야 합니다.
- 큰 PR 대신 작은 PR을 올리세요. 50줄짜리 PR은 10분이면 꼼꼼히 리뷰할 수 있습니다. 500줄짜리 PR은 30분을 들여도 대충 훑게 됩니다. 시간이 더 적게 드는데도 50줄짜리 PR이 더 좋은 리뷰를 받습니다. 크기 제한(최대 200~300줄)은 리뷰어를 늘리는 것보다 리뷰 품질을 높이는 데 훨씬 효과적입니다.
- 위험도가 낮은 변경은 리뷰를 생략하세요. 설정 변경, 문구 수정, 의존성 업데이트, 테스트 추가는 비즈니스 로직 변경과 같은 수준의 검토가 필요하지 않습니다. '저위험' 범주를 정의하고, 병합 후 리뷰를 조건으로 셀프 머지를 허용하세요.
- 기계가 더 잘하는 일은 자동화하세요. 린팅, 포매팅, 타입 체크, 테스트 커버리지는 사람보다 기계가 더 빠르고 일관되게 처리하는 리뷰 작업입니다. CI 체크가 처리할 수 있는 일에 리뷰어의 주의력을 낭비하지 마세요.
문화의 문제
리뷰 단계를 줄이는 일이 어려운 이유는 안전을 줄이는 것처럼 느껴지기 때문입니다. 프로덕션 사고가 터지기 직전에 리뷰를 줄이자고 주장했던 사람이 되고 싶은 사람은 없습니다. 이것은 기술의 문제라기보다 조직 문화의 문제입니다.
도움이 되는 관점은 이렇습니다. 리뷰는 여러 안전 장치 중 하나이고, 그 효용은 점점 줄어듭니다. 버그를 막으려고 네 번째 리뷰어를 추가하는 것은, 도둑을 막으려고 자물쇠를 네 개 다는 것과 같습니다. 첫 번째 자물쇠가 대부분의 일을 해내고, 이후의 자물쇠는 불편함만 더할 뿐 보안은 비례해서 늘지 않습니다. 자물쇠를 네 개 달지는 않겠죠. 리뷰어도 네 명을 두지 마세요.
빠르게 배포하면서도 사고가 적은 팀은 실제로 사고를 막아주는 장치에 투자하는 경향이 있습니다. 포괄적인 자동화 테스트, 점진적 배포를 위한 피처 플래그, 알림이 잘 갖춰진 모니터링, 원클릭 롤백, 그리고 사고를 책임 추궁이 아닌 학습 기회로 여기는 비난 없는(blameless) 문화가 그것입니다. 이런 투자는 시간이 갈수록 복리처럼 쌓이는데, 리뷰 단계를 더하는 방식은 그렇지 않습니다.
리뷰 단계 줄이기
팀에 리뷰 요구 사항이 너무 많이 쌓였다면, 혼란 없이 줄이는 방법은 다음과 같습니다.
먼저 현재 프로세스를 측정하세요. PR을 올린 뒤 병합되기까지 얼마나 걸리나요? 그 시간 중 대기 시간은 얼마이고, 실제 리뷰 시간은 얼마인가요? 어느 시점이든 리뷰 대기열에 PR이 몇 개나 쌓여 있나요? 이 수치를 보면 비용이 눈에 보이기 시작합니다. 평균 PR이 병합되는 데 3일이 걸린다는 사실을 알고 놀라는 팀이 대부분입니다.
그다음 실험을 해보세요. 한 달 동안 리뷰어 두 명 대신 한 명만 두는 것입니다. 같은 지표를 계속 추적하세요. 사고율이 바뀌었나요? 코드 품질(감이 아니라 결함률로 측정한)이 바뀌었나요? 대부분은 사고가 늘지 않았고, 품질은 그대로였으며, 처리량은 눈에 띄게 좋아졌다는 결과가 나옵니다.
목표는 리뷰를 아예 없애는 것이 아닙니다. 품질을 유지하면서 처리량을 극대화하는 최소한의 리뷰를 찾는 것입니다. 그 최소치는 대부분 팀이 지금 하고 있는 것보다 적습니다. 리뷰 단계는 사고 대응을 거치면서 쌓이지만, 프로세스 최적화를 통해 제거되는 일은 드물기 때문입니다. 훌륭한 소프트웨어를 만드는 일의 대부분이 그렇듯, 답은 더 많은 프로세스가 아니라 올바른 프로세스에 있습니다.


