👀

회고에 진심인 팀이 코드리뷰 프로세스 개선하는 법

Created
2024/08/18 23:27
Tags
안녕하세요! 볼드나인 백엔드 개발자 최송이입니다. :)
오늘은 저희가 회고를 통해 코드리뷰 프로세스를 개선한 이야기를 공유하려고 합니다.

테스트 시간이 부족하다는 문제 인식

저희 회사는 올해 초부터 KPT회고를 꾸준히 진행하고 있습니다. 회고를 통해서 여러 문제들을 들여다보고 하나씩 개선해나가고 있는데, 계속해서 제기되는 문제 중 하나는 “배포 전 스테이징 환경에서 테스트를 충분히 하지 못 한다.”는 점과 “PR 리뷰가 늦어진다.” 였습니다.
그 원인을 들여다보니 아래와 같았습니다.
Problem 스테이징 테스트 시간이 부족함.
WHY 1 스테이징 환경에 작업이 급박하게 올라옴.
WHY 2 PR이 늦게 Merge 됨.
WHY 3 리뷰를 기다리는 시간이 오래 걸림.
WHY 4 개인 작업을 하느라 리뷰를 해야 한다는 걸 놓침.

리뷰의 방

이 문제를 해결하기 위해 "리뷰의 방"이라는 액션 아이템을 제안했습니다.
리뷰의 방은 특정 데드라인(예: 화요일 오후 2시)까지 리뷰가 완료되지 않으면, 미팅룸 같은 장소에 모여서 리뷰를 진행하는 방식입니다. 이를 통해 리뷰가 더이상 지연되지 않도록 하는 것입니다.
이 액션 아이템을 실천하려면, 먼저 백엔드와 프론트 레포지토리에 올라온 모든 PR에서 리뷰를 하지 않은 사람을 파악한 뒤, 오후 2시에 회사 내부 채팅에서 PR별로 리뷰어를 멘션하는 단계가 필요했습니다.
그러나 이 작업을 직접 하는 것은 번거롭고 시간이 많이 소요되었습니다.
이 과정에서 백엔드 팀이 사용하는 리뷰 리마인더 봇이 떠올랐습니다. 백엔드 팀은 여러 레포지토리를 관리해야 해서, 약 1년 전에 동료 개발자분이 개발한 봇을 유용하게 활용하고 있었습니다.
그래서 이 리뷰 리마인더 봇을 살짝 개선하여 리뷰의 방 액션 아이템에 활용하기로 했습니다.

리뷰 리마인더봇

기존 리뷰 리마인더 봇은 GCP의 Cloud Function을 활용하여 동작하고 있습니다.
현재 구현된 방식을 설명하겠습니다.
먼저, 특정 리포지토리의 PR 상태를 가져오기 위해 GitHub API를 호출하는 Cloud Function을 작성합니다. 코드 예시는 다음과 같습니다.
... const findNonReviewers = async (repos: Repos[]) => { for (const repoName of repos) { try { const axiosResponse = await axios({ url: `https://api.github.com/repos/${owner}/${repoName}/pulls`, headers: { "X-GitHub-Api-Version": "2022-11-28", Authorization: `Bearer ${process.env.GIT_HUB_TOKEN}`, }, method: "GET", }); const pullRequests: Result["pullRequests"] = []; axiosResponse.data.forEach((v) => { if(v.draft) return; pullRequests.push({ url: v.html_url, // PR 링크 title: v.title, // PR 제목 notApprovedUser: v.requested_reviewers.map((v) => v.login), // PR 리뷰어 }); }); if (pullRequests.length) { result.push({ repoName, // 레포지토리 이름 pullRequests, // 조건에 해당하는 PR들 }); } } catch (err) { if (axios.isAxiosError(err)) { console.log(err.response?.data); } } } }; ...
JavaScript
복사
Google Cloud Functions을 사용하는 Node.js 프레임워크인 gcpCloudFunction을 통해서 HTTP 트리거를 사용하는 Cloud Function을 정의합니다.
gcpCloudFunction.http( "main", async (req: gcpCloudFunction.Request, res: gcpCloudFunction.Response) => { const event = req.body; console.log(event); console.log(`before : ${new Date()}`); const result = await getPr(); console.log(`after : ${new Date()}`); // Google Chat에 JSON 형식으로 반환 return res.json({ text: result, }); } );
JavaScript
복사
그 다음 이 Cloud Function을 GCP에 배포하여, HTTP 요청을 통해 특정 레포지토리에서 PR 리뷰어를 확인할 수 있도록 합니다.
그 후, Google Cloud Console에서 Google Chat API를 활성화하고, Google Chat에 앱으로 등록하기 위해 Bot의 기본 정보를 설정합니다.
아래처럼 공개 상태를 따로 지정할 수 있습니다.
이후 Google Chat에 해당 봇을 추가하면 레포지토리의 PR 리뷰어를 확인할 수 있습니다.

요약

1.
GCP에서 Cloud Function을 통해 GitHub API로 PR 상태를 확인합니다.
2.
Google Chat Bot을 통해 이 Cloud Function을 호출하여 PR 상태를 Google Chat에서 바로 확인할 수 있도록 설정합니다.

아주 작은 개선

이미 잘 구현되어 있는 봇을 활용하여, 프론트엔드팀, 디자이너팀, 기획팀, 모두 활용할 수 있도록 하기 위해 슬래시 명령어를 사용했습니다.
아래처럼 Google Chat API에서 봇의 기본 정보를 설정할 때 슬래시 명령어를 등록할 수 있습니다.
/fe는 프론트엔드 레포지토리, /be는 백엔드 레포지토리, /all 는 리뷰의 방 액션 아이템에서 모든 레포지토리를 확인하기 위해 추가하였습니다.
코드는 명령어 id 마다 다른 레포들을 확인하도록 간단히 수정해주었습니다.
export const getPr = async (commandId: CommandId) => { ... switch (commandId) { case "1": await findNonReviewers(feRepos); break; case "2": await findNonReviewers(beRepos); break; default: // commandId가 3(all)일 경우 await findNonReviewers([...feRepos, ...beRepos]); }
JavaScript
복사
현재 리뷰의 방뿐만 아니라 리뷰어를 확인하는 데 모든 팀이 사용중입니다!
지금까지 회고를 통해 코드리뷰 프로세스에서 발견된 문제점을 간단한 작업으로 개선한 경험을 공유했습니다.
앞으로는 명령어를 입력하지 않아도 특정 시간마다 자동으로 알림이 발송되는 작업을 진행할 예정입니다.
긴 글 읽어주셔서 감사합니다.