생산성 있는 Review 문화가 되기까지

입에 쓴 좋은 약, Review

AB180에서는 다양한 review를 합니다. 작성한 코드에 대한 review, Tech spec에 대한 review, 좀 더 넓은 관점에서는 회고, 동료 평가 등이 있습니다. 단어 뜻 그대로 다시 한번 보면서(review) 더 좋은 방법은 없는지, 잘못된 부분은 없는지 검토하는 거죠. 지금 작성된 이 블로그 글 또한 review 한 글입니다.
Review가 좋은 것은 다들 알지만 실제로는 문화로 잘 자리 잡기 어렵습니다. 많은 회사에서 바쁘다는 이유로 review를 하지 못하기도 합니다. 그 시간에 코드 한 줄을 더 작성하는 게 낫다는 이유로요. AB180에서도 지금의 review 문화로 발전하기까지는 매우 긴 시간이 걸렸습니다. 4년 이상 전부터 code review를 했었지만, 지금의 문화와는 약간의 차이가 있었습니다.
오늘은 팀에서 만족하는 review 문화가 되기까지의 여정을 함께 살펴보겠습니다.

Review 문화가 자리 잡게 된 배경

Code review를 시작한 것은 제가 입사를 하기 전부터였습니다. 정말 오래된 일이다 보니 code review를 시작한 이유를 꼽기는 어렵지만, 그동안 code review를 해야 할 이유로 많이들 이야기했던 것을 들어보자면 크게 두 가지입니다.
1.
실수를 줄이는 것
2.
변경 사항 공유
다른 회사에서도 비슷한 이유로 code review를 하고 있을 거라 생각합니다.

Code Review를 통해 실수 줄이기

이런저런 기능들을 추가하고, 기존 기능들을 수정하다 보면 버그가 생기기 쉽습니다. 어떤 버그는 매우 심각해서 큰 장애로 번지기도 합니다. 이유는 다양하면서도 비슷합니다. 잘못된 코드 수정을 하고 테스트나 QA에서 문제를 발견하지 못하는 거죠. 또는, 설계를 처음부터 잘못해서 좋은 코드를 작성하지 못하기도 합니다. 그리고 나중에 가서야 “이 코드 누가 짠 거냐"며 git blame을 합니다. 이런 실수를 줄이기 위해 code review를 시작하는 경우가 정말 많습니다.
위 캡처는 아주 오래전 포스트모텀 결과를 정리해뒀던 것인데요. 간단한 문법 실수를 미리 잡지 못했던 것을 방지하기 위해 code review의 도움을 받자는 의견을 확인할 수 있습니다.

Approve를 통해 follow up 확인하기

또 다른 이유로는 변경 사항 공유가 있는데요. 혼자서 프로덕트를 개발하는 게 아니다 보니 비즈니스 로직 변경 등이 있을 때 다른 팀원분들도 알게 하는 방법으로 code review를 하게 하는 겁니다. 다른 사람이 코드를 읽고 approve를 해야만 PR merge를 할 수 있게 규칙을 정하면 코드 작업을 한 사람 말고도 누군가는 꼭 변경을 알게 되는 거죠.

Tech Spec도 Review 하자!

Tech spec에 대해서는 slack을 뒤져봤을 때 2020년 10월 무렵부터 처음 이야기가 나오기 시작했었습니다. 뱅크샐러드 조직의 Tech spec 문화를 보고 감명받아 팀에 도입한 뒤 지금까지도 Tech spec을 계속 작성하고 있습니다.
Tech spec을 처음부터 체계적으로 review 했던 것은 아니었습니다. 하지만 Tech spec 작성 후 code review 단계에서 설계상 지적을 하는 일이 반복되면서 Tech spec 또한 review가 필요하다는 의견이 나오기 시작했습니다. 다들 그 필요성을 인정하고 합의가 이루어진 뒤 Tech spec 또한 체계적으로 review 하기로 했습니다.

Review를 더 많이 하다보니 생긴 문제들

Review 문화를 시작하면 모두가 경험하는 문제들을 AB180에서도 똑같이 겪었습니다.

업무량 증가

너무 당연하게도 원래 코드 작성만 할 때보다 비해 업무가 늘어납니다. 다른 사람의 코드를 review 해야 하니까요. 단순히 훑어보기만 하는 것은 의미 없는 review가 될 것이므로 꼼꼼하게 review 하다 보면 생각보다 많은 시간을 써야 합니다.
특히 오래전부터 일했던 팀원분들의 고통이 컸습니다. 당연하게도 오래된 팀원일수록 많은 코드를 작성해왔고, context를 알고 있으므로 review를 해줘야 할 일이 많았기 때문입니다. 어떤 날에는 온종일 review만 하고 새로운 코드는 작성하지 못했다며 한탄하기도 했습니다. 이렇게 review를 주고받는 건 흔한 일이었고요.
Reviewer를 한 명에서 두 명으로 늘린 적도 있었습니다. 한 명으로부터 Code review를 받은 뒤 배포한 코드에서도 문제가 발생했기 때문입니다. 별다른 뾰족한 수가 없어서 review를 두 명에게 받기로 했습니다. 하지만 reviewer가 두 명으로 늘어나면서 실수가 사라질 것이라는 기대는 헛된 희망이었습니다. 실수가 줄어들긴 했지만, 반대급부로 review에 과도하게 리소스를 사용해야 했습니다.

느려진 속도

규칙대로 Review가 완료되기 전까지는 이후 작업을 하지 않으려 하다 보니 속도가 느려졌습니다. Tech spec review가 완료되기 전까지는 코드 작업을 섣불리 시작하지 않다 보니 코드 작업을 시작하는 게 느려졌고, 코드 작업이 끝나더라도 code review를 기다리느라 배포가 늦어졌습니다.

예상할 수 없는 일정

Review를 받아야 한다는 것은 누군가는 review를 해줘야 한다는 뜻입니다. 하지만 모두가 바쁘다 보니 어떤 PR은 review 대기 상태로 오래 머무르기도 합니다. 중요도가 조금 떨어지는 작업의 경우 차일피일 review를 미루고, 그 결과 한 달 이상 review 대기 상태로 있는 PR이 생겨나기도 했습니다.
게다가 아주 간단한 변경이 아니라면 review 단계에서는 의견 교환을 하면서 여러 번의 review를 거치는 경우가 많습니다. 이러다 보면 hard due가 있는 작업이 아니라면 기약 없이 일정이 늘어집니다. 과거의 PR을 찾아봤는데요. 부끄럽지만 5월 2일에 요청받았던 review를 제가 5월 13일이 되어서야 한 것을 보실 수 있습니다.

문제 해결하기

이대로는 너무 불편하고 생산성이 떨어진다는 이야기가 많이 나오기 시작했습니다. 그나마 초창기에는 적은 인원의 팀이었기 때문에 괜찮았지만, 팀이 5명, 10명, 15명으로 늘어날수록 review로 인한 생산성 저하가 커졌습니다.
PR을 작게 만드는 것 같은 뻔한 이야기들보다는 저희의 이야기 위주로 소개해보겠습니다.

의도적인 Review 분산

앞서 오래된 팀원분들의 과도한 업무 증가를 언급했습니다. 한두 명으로부터 review 요청을 받는 것과 다섯 명으로부터 review 요청을 받는 것은 그 부하가 차원이 다릅니다. 다행인지 불행인지 항상 열심인 팀원분들이 계속 합류하면서 하루에도 수많은 code review를 해야 했습니다. 열심인 팀원분들은 보통 코드도 많이 작성하니까요.
팀장이 대부분의 코드를 review 하는 것을 보신 분이 많을 텐데요. 팀장이 대표적인 오래된 팀원이기 때문입니다. 이런 경우 의도적으로 review를 내려놓지 않으면 그 역학 구조가 바뀌기 어렵습니다.
의도적으로 분산해야 한다는 것을 알면서도 미안하다는 이유로 code review를 위임하지 못하는 경우가 많습니다. 하지만 전체 생산성을 위해서는 반드시 다른 사람도 code review를 하게 해야 합니다. 비즈니스가 커지면서 기능과 사람이 늘어나는 건 당연하겠죠. 10명을 넘어서 20명, 50명이 요청하는 code review를 소수의 초기 팀원분들이 계속 감당할 수 있을까요? 불가능한 것이 당연합니다.
잘못된 코드가 배포되는 실수를 할까 봐 두려워서 위임을 못하기도 하는데요. 저희 또한 마찬가지였습니다. 이것과 관련된 이야기는 이후 “얻은 교훈들”에서 다루겠습니다.

일정을 예상 가능하게 만들기

Review를 요청하는 사람은 언제 완료될지 모르고, 요청을 받는 사람은 얼마나 시간이 걸릴지 몰라 선뜻 PR에 손이 가지 않는 문제를 해결해야 했습니다. 그러기 위해 두 가지 규칙을 만들었습니다.
첫 번째 규칙으로 Review 요청을 받았을 때 4시간 이내, 혹은 다음 날 오전까지 반드시 하기로 했습니다. 이 규칙은 Google을 비롯한 다른 회사들에서 어떻게 code review를 하고 있는지 찾아보던 중 발견한 규칙이었습니다. 이렇게 예상할 수 있는 시간을 정하는 게 중요했습니다. Review를 요청하는 사람은 일정 시간 뒤 혹은 내일 오전에는 review가 되어 있을 테니까 예상 일정에 맞춰서 계획을 세울 수 있고, Review를 하는 사람은 일정 시간 뒤 혹은 내일 오전에 몰아서 하면 되니까 context switching 비용이 줄어듭니다.
두 번째 규칙으로 Review 요청 시 review 하는데 걸리는 예상 시간을 함께 전달하기로 했습니다. 이 또한 유효했습니다. Review 요청을 받는 사람은 context가 부족하다 보니 간단한 review도 섣불리 손 대기 어려울 수 있습니다. 하지만 아래 캡처와 같이 1분도 걸리지 않는 review라는 것을 알려주면 부담 없이 review를 해줄 수 있습니다.
내가 review를 빨리하지 않으면 다른 사람의 작업이 끝나는 속도가 느려지고, 그것이 팀 전체의 생산성 저하로 이어집니다. 그래서 내 작업만큼 다른 사람의 review 요청을 높은 우선순위로 처리해주는 것도 중요합니다. 위 규칙에 따라 review cycle이 빨라진 결과 전체 생산성도 크게 올라갔고, 과거처럼 review가 안 되어서 배포가 늦어지는 일도 훨씬 줄어들었습니다.

Review 요청을 자율적으로 판단하게 하기

이건 꽤 도전적인 주제일 수 있는데요. 왜냐하면 개발자들이 싫어하는 것 중 하나인 예외를 만들기 때문입니다.
Review는 많은 리소스가 들어가는 활동인 만큼 유의미해야만 합니다. 단순히 오타를 수정하는 PR에 대해서도 무조건 review를 받아야 한다면 reviewer의 리소스가 낭비됩니다. typo를 고친 것을 보고 review를 해줌으로써 얻을 수 있는 게 별로 없을 테니까요. 하지만 review를 해주는 사람은 원래 하던 일을 잠깐 제쳐둬야 하므로 집중력을 잃게 됩니다.
“나 혼자만이 아는 코드”를 수정할 때도 review를 받는 것을 생각해보겠습니다. 반드시 review를 받아야 한다는 규칙을 지키려다 보면 context가 없는 다른 팀원의 리소스를 사용해야 합니다. 누군가 review는 해줘야 하니까요. review를 기다리느라 배포가 늦어지는 것 또한 당연합니다.
물론 프로덕트에 치명적인 코드라면 review를 받아야 하는 게 맞겠지만 그렇지 않은 경우에도 기계적으로 review를 하려다 보면 결국 리소스 낭비로 이어지게 됩니다.
이렇게 예외를 허용하는 것은 쉽지 않습니다. 당연히 “어떤 경우에는 review를 받아야 하고, 어떤 경우에는 review를 받지 않아도 되냐?”는 질문이 이어지기 때문입니다. 저희는 주관적으로 판단하게 하고 있습니다. 모든 경우를 커버할 수 있는 규칙을 만들 수 없기도 하고, 자유와 책임을 가져가는 것이 우리의 문화이기 때문입니다.

얻은 교훈들

문제 해결 방법들을 보시면 해결 방법이 굉장히 특별하진 않습니다. 간단한 해결 방법들을 도입하면서 깨닫게 된 교훈을 공유해보려고 합니다.

Code Review로 실수를 막을 생각을 하지 말 것

더 좋은 코드를 더하기 위해 Code review를 하는 것이지 버그를 막기 위해 code review를 해선 안 됩니다. 왜냐하면 사람은 실수하는 동물이기 때문입니다. 버그는 테스트로 막아야 합니다. 복잡한 비즈니스 로직 수정에 대해 code review에서 실수를 발견하는 경우가 당연히 있긴 하겠지만 그것에 의존해선 안 됩니다.
극단적인 예시로 if else block이 1000개가 넘는 코드를 수정할 때를 생각해보겠습니다. 문제없이 수정했는지 code review를 통해 검증할 수 있을 리가 없습니다. 한 명이 아니라 두 명, 세 명 이상이 reviewer로 들어가도 마찬가지입니다.
if else block이 1000개가 넘는 코드가 존재한다니 말도 안 된다고 생각하실 수 있지만 실제로 존재하는 사례입니다. 다행히(?) 이 사례는 AB180이 아니라 지인에게서 들었던 일이었습니다. 이렇게 극단적인 경우가 많진 않지만 교묘하게 복잡한 로직을 수정해야 해서 난감한 상황은 여러분 모두 경험해보셨을 거라 생각합니다.
Code review에서 다뤄야 할 것은 코드가 얼마나 읽기 쉬운지, 필요한 테스트를 잘 추가했는지, 적절하게 구현했는지 등입니다. 코드에 실수가 없는지가 아니라요.

규칙에 얽매이지 말 것

이 글을 읽고 있는 여러분들도 아마 저처럼 명확한 것을 좋아하는 개발자분들이지 않을까 싶은데요. 저도 가끔은 만들어둔 규칙을 지키려는 태도가 나오기도 합니다. 정해진 규칙대로 하면 마음이 편한 것은 사실입니다. 뭔가 잘못되더라도 규칙을 탓하면 되니까요.
하지만 생산성이 떨어지는 규칙을 떨쳐내지 못하고 생산성이 낮은 상태로 살아가는 것은 지양해야 합니다. 저는 2명 이상의 code review를 받아야만 하도록 규칙을 정했던 것이 가장 후회됩니다. 당시에는 좋은 방법이라 생각했습니다. 실수를 줄여줄 수 있을 것 같았으니까요. 하지만 그렇게 만들어둔 규칙은 매우 오랜 시간 동안 팀에 남아서 생산성을 떨어뜨렸습니다.
무조건 review를 받아야 한다고 규칙을 정했던 것 또한 후회하고 있습니다. 팀원 여러분들이 판단하기 편하게는 만들어드렸지만, 스스로가 작성한 코드에 대한 주인 의식, 자유와 책임을 뺏어갔던 규칙이 아닐까 생각합니다. 납득하기 어렵겠지만 review를 조금 느슨하게 하면서 오히려 변경에 대해 더 높은 책임감을 가질 수 있게 됐다고 생각합니다.

일정을 예상 가능하게 만들 것

과거에는 review를 기다리느라 일정을 지키지 못하는 경우가 자주 있었습니다. 팀이 점점 커지고, 더 많은 티켓을 진행하면서 review 할 것도 그에 비례해 늘어났기 때문입니다. 내 작업만 하기에도 바쁜데 review도 더 많이 해야 하니 당연한 결과였습니다.
언제 review가 완료될지 예상할 수 있게 되면서 일정이 바뀌는 일이 훨씬 줄었습니다. Review 단계에서 걸릴 시간을 좀 더 잘 예상할 수 있게 됐기 때문입니다. 또한, review의 우선순위가 높아야 전체의 생산성이 높아진다는 사실에 대한 공감대가 형성되면서 서로 review를 더 빨리 해주려 노력하기 시작했습니다. Review cycle이 짧아지니 티켓이 완료되는 데 걸리는 시간도 자연스럽게 더 짧아졌습니다.
또 다른 부차적인 효과도 있었습니다. review를 예상할 수 있게 만들면서 시간을 좀 더 계획적으로 사용할 수 있게 됐습니다. “5시 정도에 작업이 끝나서 PR을 올려두면 내일 오전 정도에는 review가 되어 있을 테니 내일 오전까지는 다른 작업의 Tech spec을 작성해야겠다”와 같은 식으로 계획을 세울 수 있게 된 것입니다. 그러면서 스트레스가 적어지고 만족도가 올라갔습니다.

마치며

Code review를 통해 실수를 잡는 것, 모든 코드 변경을 review 하는 것, 들었을 때는 굉장히 좋은 말입니다. 하지만 실제로 했을 때 언제나 좋은 결과가 만들어지는 것은 아니라는 것을 배웠습니다. code review를 하더라도 실수는 발생할 수 있고, 모든 것을 review 하다 보면 생산성이 떨어지기도 하니까요.
Google에서는 모든 코드 변경을 review 한다고 합니다. 하지만 모든 코드 변경을 review 한다는 것은 Google이기 때문에 유지할 수 있는 방법일 수 있습니다. Google에는 충분히 많은 개발자가 있고, 문제가 생겼을 때 위험이 너무 크기 때문에 반드시 review를 거치게 하는 게 맞는 방법일 수 있으니까요.
작은 스타트업에서는 규칙 때문에 생산성이 과도하게 떨어지는 상황을 항상 경계해야 하는 것 같습니다.

References

ᴡʀɪᴛᴇʀ
Juhong Jung @toughrogrammer Product Div, Backend Group Lead
유니콘부터 대기업까지 쓰는 제품. 같이 만들어볼래요? 에이비일팔공에서 함께 성장할 다양한 직군의 동료들을 찾고 있어요! → 더 알아보기