PR 사이즈를 200줄로 강제했더니 일어난 일
HEDVION 결제·정산·자동화 팀이 PR 200줄 상한을 도입한 3개월 기록. 리뷰 댓글 수 2배 증가, 설계 결합도 탐지, 피처 플래그 트레이드오프까지 실전 관점으로 정리했다.
왜 결제·정산 팀에서 PR 크기가 특히 위험한가
결제·정산 시스템을 운영하는 팀에게 코드 리뷰는 단순한 품질 게이트가 아니다. 잘못 머지된 로직 하나가 이중 정산, 누락 정산, 혹은 잘못된 수수료 계산으로 이어질 수 있다. 우리 팀이 처리하는 결제 데이터는 하루에도 수천 건이 넘고, 정산 배치는 매일 밤 정해진 시간에 실행된다. 한 번 틀린 금액이 나가면 정정하는 데 드는 공수와 신뢰 비용은 코드 한 줄의 버그보다 훨씬 크다. 자동화 파이프라인도 마찬가지다. 트리거 조건 하나가 잘못 바뀌면 배치가 두 번 돌거나, 아예 안 도는 상황이 생긴다.
그런데 묘하게도 결제 코드는 유독 PR이 커지기 쉽다. 결제 플로우 하나를 건드리면 검증 로직, 상태 전이, 외부 PG사 연동, 정산 집계까지 줄줄이 얽혀 있다. 리팩터링 한 줄을 시작했다가 800줄짜리 PR이 완성되는 건 우리 팀이 반복적으로 겪어 온 패턴이었다. 리뷰어는 전체를 읽기 버거워서 "LGTM"을 빠르게 누르거나, 리뷰가 밀려 머지가 3~4일씩 지연됐다. 결제 도메인에서 빠른 핫픽스가 필요한 상황에 머지 파이프라인이 막혀 있다면 그 자체로 운영 리스크다.
200줄 규칙의 시작: 숫자 하나가 팀 문화를 건드리다
우리가 세운 규칙은 단순하다. PR 하나당 순수 로직 변경 200줄 이하. 테스트 파일, 설정 파일, DB 마이그레이션 파일은 카운트에서 제외한다. 실제로 로직이 바뀌는 줄만 센다. 이 규칙은 처음에 슬랙 채널에서 나온 제안 수준이었고, 공식 문서화도 없었다. 그러나 PR을 열 때마다 서로 상기시키기 시작하면서 두 달 만에 팀 전체의 암묵적 기준으로 자리잡았다.
200이라는 숫자 자체에 과학적 근거를 붙이고 싶다면, SmartBear가 2011년에 발표한 코드 리뷰 연구에서 "리뷰어가 한 세션에 집중할 수 있는 코드는 200~400줄"이라는 데이터가 자주 인용된다. 하지만 팀마다 맥락이 다르고, 결제 로직처럼 도메인 배경 지식이 필요한 코드는 같은 200줄이라도 인지 부하가 다르다. 우리에게 200줄이 맞았던 이유는 숫자 자체보다, 리뷰어가 맥락을 잃지 않고 끝까지 읽을 수 있는 크기를 팀이 의식하게 만들었다는 데 있다. 숫자가 대화를 유발했고, 그 대화가 습관을 만들었다.
한 달의 저항이 드러낸 것: 분리의 어려움은 설계 문제다
처음 한 달은 불편했다. "이건 붙어 있어야 의미 있는 코드인데"라는 말이 주간마다 나왔다. 정산 집계 로직을 리팩터링하면서 배치 스케줄러와 알림 발송 코드를 함께 건드리게 됐는데, 이걸 어디서 끊어야 하냐는 질문이 반복됐다. 억지로 나누면 중간 상태가 메인에 들어가고, 그 상태가 실제로 잘못된 정산 데이터를 만들 수도 있다는 우려도 있었다.
그런데 실제로 쪼개는 시도를 반복하면서 흥미로운 패턴이 보이기 시작했다. 분리가 어렵다고 느꼈던 코드는 대부분 결합도가 실제로 높았다. 정산 집계 함수가 알림 발송을 직접 호출하고 있었고, 배치 스케줄러가 DB 커넥션을 직접 보유하고 있었다. 이건 "코드가 붙어 있어야 맞다"가 아니라 "코드가 잘못 설계돼서 붙어 있는 것"이었다. PR 쪼개기가 아키텍처 냄새를 탐지하는 리트머스가 된 것이다. 결제·자동화 시스템처럼 여러 컴포넌트가 얽히는 도메인에서 이 신호는 특히 가치가 있다. 어디가 묶여 있는지 알아야 어디를 먼저 풀어야 할지 판단할 수 있기 때문이다.
리뷰 품질의 실질적 변화: 수치로 본 두 번째 달
두 번째 달부터 수치가 변하기 시작했다. 팀 내에서 비공식으로 추적한 데이터를 보면, PR당 평균 리뷰 댓글 수가 규칙 도입 전 1.8개에서 도입 후 4.3개로 늘었다. 댓글이 늘었다고 무조건 좋은 게 아닐 수도 있지만, 내용이 달라졌다. 이전에는 전체 맥락 파악 질문("이게 왜 바뀐 건가요?")이 많았다면, 이후에는 구체적인 로직 질문과 엣지 케이스 제안이 주를 이뤘다. 특히 정산 금액 계산 로직에서 리뷰 단계에 잡아낸 버그가 3건 있었는데, 이 중 두 건은 특정 PG사의 취소 수수료 처리 방식 차이에서 비롯된 케이스였다. 작은 PR이었기 때문에 리뷰어가 해당 로직을 끝까지 꼼꼼히 읽을 수 있었다.
변화는 PR 설명 품질에서도 나타났다. 작은 PR은 "왜 이 변경이 필요한가"를 한두 문단으로 설명하기가 쉽다. 맥락이 좁기 때문에 작성자도 명확하게 이유를 쓸 수 있고, 리뷰어도 그 맥락 안에서만 집중하면 된다. 반면 800줄짜리 PR의 설명은 "정산 로직 개선 및 관련 리팩터링"처럼 모호해지기 쉽다. 모호한 설명은 리뷰어에게 전체 코드를 다 읽어야 한다는 부담을 주고, 그 부담이 다시 표면적 리뷰로 이어지는 악순환이 된다. 결제 도메인에서 표면적 리뷰는 그냥 아쉬운 게 아니라 잠재적인 운영 사고 리스크다.
피할 수 없는 트레이드오프: 브랜치 체인과 피처 플래그 전략
단점을 솔직히 이야기해야 한다. 큰 피처를 여러 PR로 나누면 의존성 관리 오버헤드가 생긴다. 결제 수단 추가 피처처럼 DB 스키마 변경 → 서비스 레이어 → API → 프론트 연동이 순차적으로 필요한 작업은 브랜치 체인이 불가피하다. 앞 PR이 머지되기 전에 다음 PR을 올리면 뒤 PR들이 앞 브랜치를 base로 갖게 되고, 앞에서 수정이 일어나면 이후 PR 전체를 리베이스해야 한다. 우리 팀이 세 개짜리 체인에서 앞 PR 하나의 리뷰 피드백을 반영하느라 나머지 두 개를 두 번씩 리베이스한 경험이 있다. 개발자 한 명이 오전의 절반을 리베이스에 쓴 날도 실제로 있었다.
우리가 찾은 절충점은 피처 플래그다. 결제·정산 코드에서 피처 플래그는 단순한 편의 도구가 아니다. 새 정산 로직이 절반만 구현된 상태로 메인에 들어가도, 플래그가 꺼져 있으면 실제 배치에서 실행되지 않는다. 각 PR은 독립적으로 머지 가능하고, 플래그를 켜는 마지막 PR이 피처를 완성한다. 이 방식으로 브랜치 체인의 리베이스 오버헤드가 눈에 띄게 줄었다. 다만 피처 플래그도 관리 대상이다. 켜놓고 잊어버린 플래그가 코드에 남으면 조건 분기가 영구적으로 누적된다. 우리는 피처 플래그를 만들 때 반드시 "플래그 제거" 작업 티켓을 함께 생성하고, 피처 안정화 이후 조건 분기를 정리하는 PR을 따로 올리는 것을 규범으로 정했다.
3개월 후, 지금 바로 써먹을 수 있는 실행 지침
세 달이 지나면서 200줄이라는 숫자보다 규칙이 만들어낸 습관이 더 중요하다는 것을 느꼈다. 팀원들이 코드를 작성할 때부터 "이걸 어떻게 나눌 수 있을까"를 먼저 생각하기 시작했다. PR을 올리기 전에 이미 분리 가능한 단위로 코드를 구조화하는 연습이 쌓였고, 결제 시스템처럼 복잡도가 높고 실수 비용이 큰 도메인에서 이 습관은 코드 품질과 직결된다. "빠른 LGTM"이 가장 위험한 리뷰 패턴이고, 작은 PR은 그 패턴을 구조적으로 줄인다.
지금 바로 적용할 수 있는 것을 구체적으로 정리한다.
- 팀 합의 숫자를 먼저 정하라. 200이 아니어도 된다. 숫자가 있어야 대화가 생기고, 대화에서 규범이 나온다. 숫자 없이 "작게 올리자"는 말은 실행되지 않는다.
- 분리가 어렵다면 그게 설계 신호임을 팀이 공유하라. 리뷰 자리에서 "이 PR은 왜 쪼개기 어려웠나"를 잠깐 이야기하는 것만으로도 설계 리뷰가 된다. 결제 코드에서 이 질문은 특히 효과적이다.
- 큰 피처를 나눌 때는 피처 플래그 전략을 처음부터 설계하라. 나중에 붙이는 플래그는 어설프지만, 처음부터 설계한 플래그는 안전하다. 플래그 제거 티켓도 함께 만들어야 부채가 되지 않는다.
- PR 설명에 "왜 이 변경이 필요한가"를 의무화하라. 이 한 문단이 리뷰어의 인지 부하를 가장 효과적으로 줄인다. 작은 PR은 이 규범을 지키기가 훨씬 쉽고, 그게 작은 PR을 유지할 동기도 된다.
규칙 하나가 팀 문화를 만든다. 단, 숫자가 목적이 아니라 수단이라는 걸 팀이 알고 있을 때만.
* 위 링크는 인프런 affiliate 활동의 일환이며, 일정액의 수수료를 제공받을 수 있습니다.
* 위 추천 링크는 쿠팡파트너스 활동의 일환이며, 일정액의 수수료를 제공받을 수 있습니다.