PR 리뷰가 병목이 될 때

HANUI·
애자일프론트엔드코드리뷰PR스프린트

이 시리즈 마지막 편으로 "PR 리뷰가 병목이 될 때"를 쓰려고 했어요. 리뷰 대기가 사흘씩 걸리고, 그동안 브랜치가 쌓이고, 결국 대충 승인 누르게 되는 그 얘기요.

3편에서 배운 대로 감으로 쓰지 않으려고 제 저장소부터 열었어요. 그런데 반대 결과가 나왔어요.

병목이 없었어요. 리뷰가 없었으니까요.

숫자부터

hanui 저장소의 PR 전부예요. 7건이고, 하나도 안 빠졌어요.

PR규모리뷰열림 → 머지
#7214파일 +1,2910건7초
#682파일 +90건2분 36초
#66188파일 +21,1750건10분 5초
#6917파일 +4150건24분
#713파일 +1100건10분
#73140파일 +26,8580건1시간 35분
#513파일 +120건(버전 자동화)

리뷰 0건이 일곱 번이에요.

제일 눈에 걸리는 건 #72예요. 04시 44분 19초에 열려서 04시 44분 26초에 머지됐어요. 7초요. 브랜치를 만들고 PR을 여는 절차만 남고, 그 절차가 원래 하려던 일은 사라진 거예요.

#66도 마찬가지예요. 188개 파일에 21,175줄이 들어갔는데 10분 만에 머지됐어요. 그 10분에 21,175줄을 읽는 건 물리적으로 불가능해요. PR을 연 게 아니라 머지 버튼을 누르는 절차를 밟은 거예요.

변명은 있어요, 근데 안 통해요

혼자 하는 프로젝트예요. 커밋 기여자가 여러 명으로 보이지만 계정이 갈렸을 뿐 사실상 한 사람이에요. 내가 짠 코드를 내가 리뷰하는 게 무슨 의미냐 싶죠.

그런데 3편에서 확인한 숫자가 여기에 붙어요. 블록 42개 중 16개가 "완성" 후에 다시 열렸어요. 그때 추가된 게 에러 상태, 로딩 상태, 접근성, 폼 검증이었고요.

7초 만에 머지된 그 순간에 아무도 이렇게 안 물어봤다는 뜻이에요. "에러 나면 어떻게 되는데?" "키보드로 되나?" 그 질문이 3주 뒤에 fix: 커밋으로 돌아온 거예요.

리뷰를 건너뛰면 빨라지는 게 아니라, 계산서가 미뤄져요. 7초에 아낀 게 나중에 며칠로 청구돼요.

밀리는 팀과 없는 팀은 원인이 같아요

한쪽 극단이 이거라면, 반대쪽 극단은 흔히 보는 그림이에요. 리뷰가 사흘씩 밀리고, PR이 열 개씩 쌓이고, 리뷰어는 500줄짜리 diff를 보다가 결국 "LGTM"을 눌러요.

정반대로 보이지만 원인이 같아요. 리뷰가 무슨 자리인지 합의가 없어요.

합의가 없으면 리뷰어는 뭘 봐야 할지 몰라요. 그래서 눈에 띄는 걸 봐요 — 변수명, 들여쓰기, 이 함수를 왜 여기 뒀는지. 작성자는 사소한 걸로 발목 잡혔다고 느끼고, 리뷰어는 자기가 뭘 놓쳤는지 불안해요. 이 상태가 반복되면 두 갈래로 가요. 리뷰가 무거워져서 밀리거나, 무의미해져서 사라지거나. 제 저장소는 후자로 간 경우예요.

크기부터 자르는 게 먼저예요

188파일짜리 PR은 리뷰가 불가능해요. 리뷰어 탓이 아니라 읽을 수 없는 걸 줬기 때문이에요.

2편에서 화면 단위로 티켓을 쪼개지 말고 컴포넌트 단위로 쪼개라고 했는데, 그 효과가 여기서 나와요. "게시판 목록 화면 완성" PR은 300줄이 넘지만, "DataTable 컴포넌트" PR은 60줄이에요. 60줄은 사람이 실제로 읽어요.

제 PR 목록에서도 갈려요. #68은 2파일 9줄이라 2분 36초에 머지된 게 이상하지 않아요. 그건 실제로 다 본 거예요. 문제는 188파일짜리가 같은 취급을 받은 거죠.

PR 크기는 리뷰 문화의 결과가 아니라 원인이에요. 작게 자르면 리뷰가 되고, 크게 뭉치면 안 돼요.

사람이 볼 것과 기계가 볼 것을 나누기

크기를 줄여도, 사람이 매번 같은 걸 확인하면 지쳐요. 4편에서 디자인 수치를 사람이 세지 않게 만든 것과 같은 접근이 리뷰에도 통해요.

그래서 저장소에 리뷰 에이전트를 하나 뒀어요(.claude/agents/code-reviewer.md). 보는 관점이 다섯 개로 고정돼 있어요.

파일명이 kebab-case인지, 'use client'가 최상단에 있는지, named export를 썼는지 — 이런 건 사람이 볼 이유가 없어요. 매번 같고, 사람은 자꾸 놓치고, 지적하면 감정이 상해요. 기계는 안 지치고 감정도 없고요.

여기서 중요한 건 자동화 자체가 아니에요. 기계가 컨벤션을 가져가면 사람 리뷰에 남는 게 달라진다는 것이에요.

"들여쓰기 맞춰주세요" 대신 "이 상태를 여기서 관리하는 게 맞나요?", "이거 빈 목록일 때 뭐가 보이죠?"가 남아요. 앞의 것은 기계가 더 잘하고, 뒤의 것은 사람만 할 수 있어요. 리뷰가 지겨워지는 건 대부분 사람이 기계 일을 하고 있어서예요.

혼자여도 리뷰는 필요해요

그래서 저는 뭘 바꿨냐면, 머지 전에 스스로 세 가지만 물어보기로 했어요. 3편에서 확인한 재작업 16건이 전부 이 세 가지에서 나왔거든요.

  • 이거 에러 나면 화면에 뭐가 보이지?
  • 이거 키보드로만 쓸 수 있나?
  • 이거 데이터가 0건일 때 어떻게 되지?

세 개뿐이라 30초면 돼요. 그리고 이건 코드 스타일 얘기가 아니라 상태 얘기예요. 혼자 하는 프로젝트에서 리뷰어를 구할 순 없지만, 이 세 질문은 혼자서도 할 수 있어요.

솔직히 말하면 AI 리뷰가 사람 리뷰를 대체하진 못해요. 컨벤션과 명백한 실수는 잘 잡는데, "이 기능이 애초에 필요한가", "사용자가 이 흐름을 이해할까" 같은 건 못 봐요. 그건 여전히 사람 몫이고, 혼자면 그 사람이 나예요. 대신 기계가 앞의 절반을 가져가면, 내가 볼 여력이 뒤의 절반에 남아요.

시리즈를 닫으며

다섯 편이 결국 한 얘기였어요.

1편에서 디자인을 기다리지 않는 법, 2편에서 화면 대신 컴포넌트를 먼저 만드는 법, 3편에서 화면 대신 상태를 세는 법, 4편에서 감각 대신 수치로 합의하는 법. 그리고 오늘은 리뷰에서 사람이 볼 것만 남기는 법이요.

전부 일의 단위를 다시 자르는 얘기였어요. 애자일이 빠른 건 빨리 짜서가 아니라 다시 안 짜서고, 다시 안 짜려면 처음에 제대로 잘라야 하니까요.

이 시리즈에서 제일 도움이 됐던 건 글감이 아니라 방법이었어요. 주장을 쓰기 전에 저장소를 여는 것요. 오늘도 그렇게 하다가 제가 쓰려던 것과 정반대 사실을 봤고, 그게 원래 쓰려던 글보다 나았어요.

본인 저장소에서도 한 번 돌려보세요.

숫자가 예상과 같으면 다행이고, 다르면 오늘 고칠 게 하나 생긴 거예요.

관련 링크

시리즈: 애자일과 프론트엔드 (완결)

HANUI

KRDS 기반 React 컴포넌트 라이브러리. 공공 웹 개발을 더 쉽게.