
GitHub Actions를 이용한 코드 리뷰 문화 개선기
GitHub Actions를 이용한 코드 리뷰 문화 개선기 관련
SmartEditor 팀은 항상 높은 수준의 코드 품질을 유지하기 위해 노력하고 있습니다. 그런 모습이 코드 리뷰에서도 드러납니다.

하지만 열심히 노력하는 팀임에도 불구하고 몇몇 부분에서 개선의 여지가 있었습니다. 코드 품질을 엄격하게 관리하다 보니 가끔은 리뷰가 길어지고 그로 인해 pull request(이하 PR) merge까지 긴 시간이 소요되기도 했습니다. 또한 바쁜 일정 속 우선순위에서 밀려 리뷰에 적극적으로 참여하지 못할 때도 있었습니다.
이에 팀의 코드 리뷰 문화 개선에 관심이 있는 소수 인원이 모여 개선 활동을 시작했습니다.
문제점
먼저 저희를 제외한 팀원들의 의견을 파악하고자 했습니다. 다른 팀원들도 이 문제에 대해 같은 생각을 가지고 있는지 궁금했습니다. 그래서 다음을 포함한 몇 가지 문항을 구성하여 설문을 진행했습니다.
- 리뷰하기 어려웠던 경험을 알려주세요.
- 요청받은 리뷰를 늦게 확인/승인하게 된 이유는 무엇일까요?
- 코드 변경 라인 수는 몇 라인이 적당할까요?
설문 결과, 팀원들도 문제에 대해 저희와 비슷하게 인식하고 있었습니다. 주요 응답은 다음과 같았습니다.
- 코드 변경 사항이 많아서 리뷰가 어려웠다.
- 이해도가 부족하여 리뷰가 어려웠다.
- 나중에 리뷰하려다가 놓쳤다.
- 리뷰어의 코멘트 응답이 늦어서 불편했다.
정리해 보면 개선이 필요한 핵심 문제는 다음 두 가지였습니다.
- PR merge까지의 긴 소요 시간
- 낮은 리뷰 참여율
이를 해결하기 위해 GitHub Actions를 활용해 데이터를 수집하고 분석하여 개선 방향을 찾고자 했습니다.
데이터에서 인사이트 얻기
naver/pr-stats
PR 데이터에 대한 통계를 산출하는 pr-stats 액션을 만들었습니다. 각 PR에 대한 통계, 전체 PR 통계, 사용자별 통계 정보를 제공하는 액션입니다.
이 액션을 실행하여 CSV 파일이나 콘솔로 통계 결과를 얻을 수 있습니다. 다음은 콘솔로 통계 결과를 출력한 화면입니다. 각각 PR에 대한 통계, 전체 PR 통계, 사용자별 통계 결과입니다.

각 PR에 대한 통계에서는 제목, PR 생성 시점, merge 시점, 변경된 라인 및 파일 수 등의 정보를 얻을 수 있고, 전체 PR 통계에서는 대상 PR의 평균 데이터를 얻을 수 있습니다. 마지막으로 사용자별 통계에서 개인별 리뷰 참여 수, 참여율, 평균 응답 시간 등을 확인할 수 있습니다.
액션에 대한 더 자세한 내용은 GitHub (naver/pr-stats)를 확인 바랍니다.
데이터 수집 결과
pr-stats 액션을 이용해 최근 2년의 데이터를 수집해 봤습니다.
수집 결과 merge까지 평균 약 4일의 시간이 소요되었고, 평균 리뷰 참여율은 67%임을 확인할 수 있었습니다. 예상했던 것처럼 merge까지 긴 시간이 소요되고 리뷰 참여율도 그다지 높지 않았습니다.
해결 과정
앞서 언급한 두 가지 문제를 각각 어떻게 해결했는지 알아보겠습니다.
1. PR merge까지 소요되는 시간 단축
상관관계 분석
먼저 어떤 데이터가 PR merge까지 소요된 시간과 관련이 있는지 알아보고자 했습니다.
이에 생성형 AI를 활용하여, pr-stats 액션으로 얻은 데이터로부터 지표 간 상관관계를 분석해 봤습니다. 린트 룰 변경 적용 등 단순히 변경 사항만 많고 통계에 대한 의미가 떨어지는 PR은 제외하기 위해 변경 라인 수가 3,000라인 이하인 PR을 대상으로 했습니다.

피어슨 상관 계수
일반적으로 상관계수는 다음과 같은 상관관계를 나타냅니다.
0~0.1: 거의 무시할 수 있는 상관관계0.1~0.3/-0.1~-0.3: 약한 양적/음적 상관관계0.3~0.7/-0.3~-0.7: 뚜렷한 양적/음적 상관관계0.7~1/-0.7~-1: 강한 양적/음적 상관관계

위 그림은 상관계수별 대표적인 산포도 그래프의 모습입니다. 상관관계가 없으면 특정한 추세선이 나타나지 않고, 상관관계가 높을수록 뚜렷한 추세선의 형태를 볼 수 있습니다.
즉, 각 셀 내부에 표현된 상관계수가 1에 가까울수록 양의 상관관계가 있고, -1에 가까울수록 음의 상관관계가 있습니다. 0에 가깝다면 두 지표 사이에 상관관계가 거의 없음을 나타냅니다.
우리의 목표는 merge까지 소요되는 시간을 단축하는 것이었기 때문에 이를 나타내는 지표인 timeFromReviewToMerge와 상관계수가 높은 지표를 확인했습니다.
위 분석 결과에서 timeFromReviewToMerge와 상관계수가 가장 높은 지표 세 가지는 다음과 같습니다.
averageTimeToApproval(0.84)
먼저 averageTimeToApproval은 merge까지 소요된 시간과 가장 높은 상관관계가 있었습니다. 하지만 이 지표는 사실상 timeFromReviewToMerge와 거의 유사한 개념이므로 제외했습니다.
averageResponseTime(0.79)
두 번째로 상관관계가 높은 지표는 averageResponseTime입니다. 평균 응답 시간을 줄일 수 있다면 merge까지 소요되는 시간도 줄일 수 있다는 의미입니다.
commentCount(0.44)
마지막으로 commentCount도 merge까지 소요된 시간과 유의미한 상관관계가 있었습니다. 하지만 코멘트 수를 제한한다는 것은 코드 리뷰에서 활발한 의견 교환을 방해할 수 있습니다. 이는 오히려 코드 리뷰 문화에 부정적인 영향을 미칠 수 있다고 판단하여 이를 위한 시도는 하지 않았습니다.
이에 평균 응답 시간을 줄이는 것을 목표로 정했습니다.
리뷰 응답 시간 개선
pr-stats 액션으로 얻은 약 2년간의 통계 데이터에서 평균 응답 시간은 약 45시간 정도로, 개선이 필요해 보였습니다.
이에 저희 팀은 리뷰 응답 시간 개선을 위해 다음 두 가지 GitHub Actions를 개발했습니다.
naver/notify-pr-review리뷰를 요청하는 즉시 리뷰 요청이 들어왔음을 Slack 메시지로 알려주는 액션입니다.

기존에는 리뷰 요청을 보내면 메일로 알림을 받기 때문에 뒤늦게 확인하거나 놓치는 경우가 빈번했지만, 이 액션을 통해 리뷰어가 리뷰 요청을 빠르게 알 수 있게 되었습니다.
개인적으로 해당 액션으로 인해 많은 개선 효과를 체감했습니다. 특히 변경 사항이 적은 간단한 PR에 대해 효과가 컸다고 느꼈습니다. 이에 실제로 영향을 파악하기 위해 해당 액션 적용 전후로 변경 라인 수가 20라인 이하인 PR에 대한 평균 응답 시간 변화를 확인해 봤습니다.

위 그래프는 20라인 이하의 PR에서 액션 적용 전후 응답 시간 분포를 나타내는 밀도 그래프입니다. 확연히 오른쪽 그래프(적용 후)에서 전반적으로 응답 시간이 크게 줄어든 것을 볼 수 있습니다.
수치상으로도 20라인 이하 PR의 평균 응답 시간이 크게 감소한 것을 확인할 수 있습니다.
- 적용 전: 약 18시간
- 적용 후: 약 6.5시간(약 64% 감소)
naver/request-pr-review원하는 시간에 정기적으로 Slack 메시지로 PR 리뷰 요청을 보내는 액션입니다. 리뷰어에게 리뷰해야 하는 PR이 있음을 리마인드해 줍니다.

참고로 저희 팀은 매일 오전 10시에서 12시를 코드 리뷰 집중 시간으로 사용하고 있습니다. 따라서 오전 10시에 알림을 받도록 하여 어떤 PR을 리뷰해야 하는지 확인할 수 있게 했습니다.
또한 다음에 설명할 d-day-labeler 액션과 함께 사용하면 D-0 label이 붙은 PR을 강조하여, 리뷰어가 리뷰 우선순위를 결정하는 데에 도움을 줄 수 있습니다.
PR merge 데드라인 설정
응답 시간 개선 외에 직접적으로 merge까지 소요되는 시간을 단축할 수 있는 방법도 고민했습니다.
pr-stats 액션으로 데이터를 분석해 보니 timeFromReviewToMerge가 1, 2주 혹은 한 달 이상인 PR이 존재했습니다.

이런 결과를 보면서 코드 리뷰 기간에 대해 어느 정도의 데드라인이 필요하다는 생각이 들었습니다. 이에 D-n 룰을 도입하여 해당 PR의 코드 리뷰가 완료되어야 하는 시점을 나타내고자 했습니다.
이를 자동화하기 위해 다음 두 가지 GitHub Actions를 개발했습니다.
naver/d-day-labelerD-n 룰에 따라 원하는 주기(cron)로 D-0까지 자동으로 갱신하는 액션입니다. 저희 팀은 평일 오전 0시에 갱신하도록 했습니다.

리뷰이는 PR을 생성할 때 D-n 형식의 label에 해당 PR의 데드라인을 명시하여 PR의 긴급도를 나타낼 수 있습니다. 리뷰어는 이를 통해 코드 리뷰 시 우선순위를 결정하여 더 긴급한 PR을 먼저 리뷰할 수 있습니다.
D-n 룰을 사용하기 위해 리뷰이는 매번 PR 생성 시마다 D-n label을 직접 추가해야 했습니다. 이 액션을 사용하면 PR 생성 시 혹은 Draft에서 Open 상태로 전환 시 자동으로 원하는 label이 추가되어 이런 번거로움이 해소됩니다.
참고로 저희 팀은 D-3 label을 기본값으로 사용하고 있습니다.

D-n 룰을 사용하는 저희 팀 모습입니다. PR 생성 시 자동으로 D-3 label이 붙고, 하루가 지날 때마다 D-2, D-1, D-0까지 자동으로 갱신됩니다.
해당 액션의 효과를 확인하기 위해 액션 적용 전후 merge까지 3일(72시간) 이상 소요된 PR의 비율을 비교해 보았습니다.

적용 전에는 merge까지 3일 이상 소요된 PR의 비율이 약 42%였지만 적용 후에는 약 28%로 14%p 정도 감소한 효과를 보였습니다.
2. 참여율 개선
merge까지 소요되는 시간 단축과 함께 또 하나의 주요 목표는 리뷰 참여율을 높이는 것이었습니다. 앞서 본 내부 설문 결과, 리뷰 참여가 어려웠던 이유 1, 2위를 차지한 문항은 다음과 같았습니다.
- PR에 코드 변경 사항이 많아서
- 코드/프로젝트에 대한 이해도가 부족해서
이에 PR 변경 라인 수를 제한해 리뷰어의 부담을 줄여 리뷰 참여율 높이고자 했습니다. 또한, 하나의 PR에서 변경 라인 수가 많다면 리뷰이가 PR 설명회를 진행하여 리뷰어의 코드 이해를 돕고자 했습니다.
PR의 변경 사항이 특정 라인 수를 넘어가면 Slack으로 알림을 보내 PR 설명회가 필요한지 투표하는 액션입니다.

저희 팀의 경우 설문 결과를 반영하여 400라인을 초과한 PR이 생성될 경우 자동으로 Slack 알림을 보냅니다. 그 후, 팀원들이 PR 설명회 진행 여부를 이모지로 투표하고 PR 설명회를 진행합니다.

이외에도 PR 템플릿 개선, 코드 리뷰 가이드 작성 등 참여율 개선을 위한 활동을 진행했지만, 이 글에서는 GitHub Actions를 집중적으로 다루므로 넘어가겠습니다.
액션 적용 전후 지표 비교
pr-stats 액션 결과를 분석하여 액션 적용 전후 지표를 비교해 보겠습니다. 정확한 비교를 위해 동일하게 1년간의 3,000라인 이하 PR 데이터를 비교했습니다. 휴일을 포함한 수치임을 감안하고 봐주시길 바랍니다.
1. 리뷰 응답 시간 감소
개선 전 결과에서는 12시간 내의 빠른 리뷰 응답을 받은 PR이 30%인 반면, 개선 후 결과에서는 52%로 22%p 증가했습니다. 24시간 내에 리뷰 응답을 받은 PR은 60%에서 73%로 13%p 증가했습니다. 또한, 48시간 이상의 매우 느린 응답을 받은 PR은 20%에서 8%로 12%p 감소했습니다.


응답이 빠른 상위 20% PR의 평균 리뷰 응답 시간은 1.1시간에서 0.2시간으로 82% 감소했습니다. 이는 notify-pr-review가 큰 영향을 미친 것으로 생각됩니다. 간단한 PR의 경우 알림을 강화하는 것만으로도 큰 효과를 얻을 수 있었습니다.

응답이 느린 하위 20% PR의 평균 리뷰 응답 시간은 108.2시간에서 47.7시간으로 56% 감소했습니다. d-day-labeler로 데드라인을 설정하고 notify-pr-review, request-pr-review로 알림을 강화해 방치되는 PR이 줄어드는 효과를 얻을 수 있었습니다.
2. merge까지 소요되는 시간 감소
리뷰 응답 시간이 감소함에 따라 merge까지 소요된 시간 역시 뚜렷하게 감소한 것을 볼 수 있었습니다. 개선 전 결과에서는 3일 이내에 merge되는 PR이 57%인 반면 개선 후 결과에서는 72%로 15%p 증가했고, 5일을 초과하여 장시간 소요되는 PR 역시 개선 전 결과에는 26%인 반면 개선 후 결과에서는 12%로 14%p 감소했습니다.



3. 리뷰 참여 활성화


팀원들의 리뷰 참여에도 큰 변화가 있었습니다. 위 그래프는 개선 전후 팀원들의 평균 리뷰 반응 속도(x축)와 리뷰 참여율(y축)에 대한 통계를 산점도와 밀도 그래프로 나타낸 것입니다.
개선 후 전반적으로 데이터가 왼쪽 위로 이동한 것을 볼 수 있습니다. 이는 팀원들의 리뷰 반응 속도는 대체로 빨라졌고 참여율은 높아졌음을 의미합니다.
뿐만 아니라 참여율의 80번째 백분위수(p80) 값이 약 44%에서 약 62%로 개선된 것을 볼 수 있습니다.
마치며
이전에는 코드 리뷰 요청을 메일로 알림받는 방식이었습니다. 하지만 하루에도 많게는 수십 통의 메일이 오가기에 뒤늦게 확인하거나 아예 놓치는 일도 있었습니다. 그 결과 코드 리뷰가 지연되면서 개발 생산성에도 영향을 미쳤습니다. 급할 때는 Slack으로 따로 리뷰를 요청해야 했고, 리뷰어와 피드백을 주고받는 과정에서 적지 않은 시간이 소모되곤 했습니다.

이번 활동 결과 코드 리뷰 프로세스가 크게 개선되었습니다. 이제는 코드 리뷰 요청이 오면 메일뿐만 아니라 Slack으로도 알림을 받습니다. 만약 이를 놓치더라도, 리뷰해야 할 PR 목록을 매일 오전 Slack으로 알림받습니다. 각 PR에 D-label로 마감일을 명시하여 PR이 방치되는 일이 줄었고, 복잡한 PR은 PR 설명회가 필요한지 Slack으로 묻는 절차를 도입하여 리뷰 진입 장벽을 낮췄습니다.

혹시 비슷한 고민을 하고 계신다면, 저희가 소개해 드린 방법을 시도해 보시길 추천드립니다.
참고로 저희가 사용한 모든 액션은 오픈소스로 공개되어 있으니 팀 상황에 맞게 활용하실 수 있습니다.
naver/pr-stats: PR 통계 데이터를 제공합니다. 단일 PR의 통계, 모든 PR 통계, 사용자 통계를 제공합니다.naver/notify-pr-review: 리뷰 요청 시 Slack 메시지로 알립니다.naver/request-pr-review: 정기적으로 원하는 시간에 리뷰가 필요한 PR 목록을 알립니다.naver/notify-pr-line-count: 기준 라인 수 이상의 PR이 등록되면 PR 설명회 개최 여부를 Slack으로 묻습니다.naver/d-day-labeler: D-n label을 자동으로 업데이트합니다.naver/simple-labeler: PR 생성 시 자동으로 label을 추가합니다.d-day-labeler와 함께 사용하면 PR 생성 시 자동으로 D-n label을 추가하고 갱신할 수 있습니다.
