코드 리뷰는 어렵습니다. 주는 입장에서도 그렇고, 받는 입장에서도 그렇습니다. 만약 코드 리뷰를 난생처음 해보거나, 익숙하지 않은 환경에서 코드 리뷰에 참여해야 한다면 혼란스러움은 더 커지곤 하죠.
4년 전, 새로운 회사로 이직을 한 것이 제가 코드 리뷰를 처음 접한 계기였습니다. 이전까지는 코드 리뷰를 경험한 적이 없었지만 그 필요성에 대해서는 익히 들어왔기 때문에, 새로운 회사에서의 코드 리뷰가 기대됐죠. 그리고 이러한 문화 속에서 더 많이 성장할 수 있겠다는 기대감도 함께 있었구요.
하지만 막상 코드 리뷰에 참여하게 되니 당황스러운 상황을 마주했습니다. 내가 올린 PR에서는 수백여 개의 코멘트가 달려있고, 내가 리뷰할 PR의 내용은 모르는 것 투성이었기 때문입니다. 그러다 보니 내가 잘하고 있는지 의구심이 들었고, 다른 사람들보다 못하다는 생각에 자존심은 떨어져 갔죠. 결국 언젠가부터 코드 리뷰가 부담스럽고 어렵게 느껴지기 시작했습니다.
2021년에 직접 집필한 책에서도 언급한 적이 있다
저는 이를 극복하기 위해 저만의 멘탈 모델을 만들게 되었습니다. 처음에는 코드 리뷰를 창과 방패의 싸움이라고 단순하게 생각했는데, 개념을 계속 확장하다 보니 어느 순간 코드 리뷰의 목표가 스포츠맨십과 크게 다르지 않다는 생각이 들었습니다. 이러한 멘탈 모델을 떠올린 덕분에 코드 리뷰에 참여하는 사람의 태도와 철학에 대해서도 고민을 해볼 수 있었죠.
그러던 와중에 저는 작년 9월부터 새 회사를 다니게 되었고, 새로운 리뷰 문화에 적응하는 과정 역시 다시 겪게 되었습니다. 그러다 보니 기존에 갖고 있던 멘탈 모델을 다시금 상기하게 됐는데, 여기에서 얻은 영감을 좀 더 구체적인 내용으로 정리하고자 하는 마음에서 글을 쓰게 되었습니다.
이번 글을 통해 코드 리뷰를 처음 접하거나, 코드 리뷰가 어렵고 힘들게 느껴지는 분들께 도움이 되었으면 좋겠습니다.
내가 코드 리뷰를 스포츠에 비유하는 이유
코드 리뷰는 소프트웨어 개발에서 매우 중요한 역할을 담당합니다. 프로젝트 내 전체적인 코드 베이스의 품질을 일정 수준 이상으로 유지하며, 코드 작성 단계에서 미처 발견하지 못한 오류를 다시 한번 검증하는 역할도 하기 때문이죠. 이 과정에서 각 개발자들의 역량이 향상되기도 합니다.
하지만 모든 개발자들이 코드 리뷰의 전체 과정을 긍정적으로 받아들인다고 생각하지는 않습니다. 코드 리뷰를 불편하게 만드는 이유는 다양하지만, 크게는 아래와 같은 세 가지 관점이 있을 수 있습니다.
- 자신의 코드가 비판을 받는 것에 대한 불안감
- 코드 리뷰를 받는다는 것은 내 작업물이 다른 사람으로부터 평가를 받는 것과 같습니다. 어떤 개발자는 실력이 부족하다는 평가를 받을까 봐 코드 리뷰를 두려워할 수 있습니다.
- 타인의 코드를 비판하는 것에 대한 불편함
- 다른 사람이 작성한 코드가 너무 어려워 이해하지 못할 수도 있고, 다른 사람이 작성한 코드가 마음에 들지 않을 수도 있습니다. 이를 표현하다 보면 정제되지 않은 의견이 나올 수 있고, 이것이 충돌을 야기할 수 있습니다.
- 코드 리뷰에 소요되는 시간과 노력
- 코드 리뷰를 진행하려면 개발자들이 각자 담당한 업무 외적으로 별도의 시간과 노력을 투입해야 합니다. 개발자들이 이미 많은 업무를 담당하고 있거나 일정이 빡빡한 경우에는 코드 리뷰를 하는 것이 부담스러울 수 있습니다.
하지만 저는 이러한 이유 때문이라도 개발자가 코드 리뷰에 몰입하기 위한 장치가 필요하다고 생각을 했습니다. 그래서 저는 코드 리뷰를 스포츠에 비유한 멘탈 모델을 떠올리게 된 것이구요.
아까 창과 방패 이야기를 했는데, 이와 유사한 스포츠인 펜싱 경기를 예로 들어보겠습니다.
득점으로 경쟁한다
펜싱 경기에서 승리하기 위해서는 상대방의 공격은 방어하면서 자신의 공격은 성공시켜야 합니다. 그러한 점에서 리뷰어(Reviewer) 와 리뷰이(Reviewee) 의 관계는 공격과 수비의 관계와 유사합니다.
리뷰이가 PR을 만든 후 리뷰어를 지정했다면, 그 코드는 이미 경기장에 올라간 펜싱 선수와도 같습니다. 곧 리뷰어로부터 질문과 수정 요청 같은 공격들이 들어올텐데, 리뷰이는 이를 적절하게 방어해야 하는 입장이라고 상상했습니다.
다만 공격을 잘 막아낸다는 것을 ‘상대방의 피드백에 대해서 방어적인 태도로 접근하라’ 고 오해하시면 곤란합니다. 공격을 막아낸다는 것 은 리뷰어가 코드 리뷰 과정에서 제안한 의견을 나의 근거를 바탕으로 납득시키는 과정입니다. 즉 우리가 손에 쥐고 있는 칼은 논리적인 근거여야만 합니다.
우선 리뷰이의 입장에서 생각해 봅시다. 상대방의 공격을 잘 막아내기 위해서는 어떤 방법을 취해야 할까요?
첫 번째 방법은 약점을 노출하지 않는 것이 중요합니다. 여기에서 말하는 약점이란, 누가 보더라도 논리적인 오류가 있거나 더 나은 코드로 개선이 가능한데 이를 놓치는 바람에 공격의 여지를 주는 것을 말합니다. 구체적으로 다음과 같은 예시가 있을 것 같네요.
- 코드 컨벤션이 잘 지켜졌는지
- 논리적인 오류나 오타가 없는지
- 반복적인 작업을 하다 누락한 부분이 있진 않은지
- 이전 PR에서 지적된 실수를 다시 한번 반복하고 있진 않는지
- 사용이 권장되지 않는(deprecated) 구식 기능을 사용하고 있는지
- 코드의 시간 복잡도를 낮출 수 있는지
- 성능상 최적화 가능한 부분이 더 남아있지는 않은지
물론 리뷰어가 더 좋은 코드를 제안할 수도 있고, 그것을 적용하기만 해도 됩니다. 하지만 적어도 이 코드가 내 역량과 지식으로 작성할 수 있는 최선의 코드인가 를 스스로에게 질문하자는 것이죠. 본인이 살펴봤을 때에도 더 개선할 점이 보이는 코드를 굳이 PR로 올림으로써 공격 포인트를 넘겨줄 필요는 없으니까요.
PR 생성 페이지 하단을 보면 커밋 목록과 코드 변경 사항이 나오는데, 난 여기서 최종 확인을 다시 해 본다
이를 방지하기 위해서는 PR을 올리기 전 내가 작성한 코드에서 약점이 없는지 전체적으로 다시 한번 훑어보는 과정이 필요합니다. 저 같은 경우는 깃허브의 PR 생성 페이지와 Github Desktop 앱을 주로 이용하고 있는데, 코드 변경 사항 추적이 가능한 도구들은 많으니 취향껏 선택하시면 될 것 같습니다.
두 번째 방법은 리뷰어가 미리 궁금해할 수 있는 부분까지 고려해 설명을 남김으로써 공격의 기회조차 주지 않는 것입니다.
우리가 코드를 작성하다 보면 무의식적으로 많은 선택을 하게 되는데 이러한 선택들이 공격 포인트가 되기도 합니다. 리뷰어는 이러한 선택들의 근거가 무엇인지를 궁금해할 수 있기 때문에, 코드를 작성할 때는 선택에 대한 근거를 어느 정도 기억해 두는 것이 좋습니다.
- 변수나 함수에 왜 그러한 네이밍을 사용했는지
- 외부 프로젝트를 참고할 때, 어떤 것을 우선적으로 참고했는지
- 참고한 레퍼런스가 공신력이 있는지
- 선택한 라이브러리가 다른 라이브러리와 비교했을 때 어떤 장점이 있는지
- 내가 지금 수정하고 있는 코드에 대해서 기존에 논의된 히스토리가 있는지
- 만약 도움이 필요하다면, 지금까지 어떤 방법으로 디버깅을 시도했는지
이러한 선택의 근거는 PR 본문과 커밋 메시지, 그리고 필요에 따라 적절한 주석을 통해 남겨둡니다. 글로만 설명하기 어렵다면 스크린샷, 영상, 다이어그램을 쓸 수도 있구요.
한편으로는 자기가 만든 PR에 스스로 코멘트를 달아서, 도움이 필요하거나 추가 설명이 필요한 부분을 다른 사람들이 쉽게 볼 수 있도록 강조하는 방법도 있습니다.
반대로 내가 리뷰어가 된다면, 상대방이 미처 고려하지 못한 약점을 찾아 공략하는 것이 필요합니다. 위에서 설명한 것과 정확히 반대로 하면 되겠네요.
- 누락한 로직이나 오타, 오류가 있는지
- 기존 코드보다 더 나은 네이밍, 로직을 제안할 수 있는지
- 참고한 레퍼런스가 믿을 수 있는지
- 리뷰이가 선택에 대해 충분한 근거를 남기지 않은 부분이 있는지
그런데 리뷰어의 지식이 부족해서 리뷰이의 코드 리뷰를 하기 어려운 경우도 있습니다. 이런 경우에는 어떻게 해야 할까요?
펜싱에 비유해 다시 생각해 봅시다. 나보다 상대방의 기량이 압도적일 수도 있죠. 근데 기껏 경기장까지 올라왔는데, 상대방에게 공격 한번 못 해보고 경기가 끝나면 좀 억울하지 않을까요? 유효타는 못 먹이더라도, 일단 쥐고 있는 칼을 휘둘러는 봐야죠.
이런 경우라면 저는 리뷰어가 리뷰이의 코드를 이해하기 위해 어떤 노력을 했는지 자세하게 알려주는 것이 좋다고 생각합니다. “해당 부분의 코드가 이해가 안 되어서 찾아봤는데, 저희 프로젝트 내에서 이러이러한 용도로 쓰고 있군요”, “이 라이브러리의 공식 문서를 찾아봤는데 이 속성은 이러이러한 것들을 다루는 데 쓰는 것이군요” 처럼요.
노력을 했음에도 불구하고 이해가 가지 않는다면, 이해가 가지 않는 부분에 직접 질문을 남기는 것도 좋은 방법이라고 생각합니다. 대부분은 잘 설명해 주시겠지만, 사실 리뷰이도 무의식적으로 작성한 코드일 수 있거든요. 그러다 보면 의도치 않게 공격에 성공할 수도 있습니다.
리뷰이와 리뷰어의 실력 차이가 많이 난다고 해도 각자의 자리에서 서로 최선을 다하자
요약하자면 저는 내 코드에서 언급될 수 있는 리뷰 포인트는 최대한 줄이고, 상대방 코드에서의 리뷰 포인트는 최대한 찾아내는 것을 경쟁처럼 생각했습니다. 물론 이건 저 혼자의 망상(…) 이긴 하지만요.
상대방을 존중하고 예의를 지킨다
스포츠에서는 치열한 공방이 벌어지다 보면 선수들끼리 자기도 모르게 감정이 격화되기도 합니다. 그리고 이는 코드 리뷰에서도 마찬가지입니다.
따라서 리뷰어는 코드의 문제점을 찾아냄과 동시에 친절하고 예의를 갖추며 텐션을 높이기 위해 의도적으로 노력해야 한다고 생각합니다.
물론 지적이라는 행위 자체가 달가운 것이 아니긴 합니다만… 코드 리뷰는 보통 텍스트로 의견을 전달하므로 리뷰어의 감정이나 의도가 불분명하게 드러나기 때문에 더욱 신경을 써야 합니다. 즉, 똑같은 내용을 전달하더라도 오프라인으로 만나 얼굴을 보며 하는 대화보다 텍스트로만 전달되는 코드 리뷰는 더욱 냉소적이고 공격적으로 받아들여질 수 있습니다.
그렇다면 리뷰어의 공격 태도는 어떠해야 할까요?
펜싱 얘기로 다시 돌아가봅시다. 펜싱에서 점수를 얻기 위해서는 상대방의 몸을 얼마나 세게 찌르는 것이 중요한 게 아닙니다. 얼마나 정확하게 약점을 타격하는지가 더 중요하죠.
이것을 코드 리뷰에서도 적용해 보자면, 리뷰어는 리뷰이의 코드를 지적할 때 최소한의 힘만으로 약점만 정확하게 타격하는 훈련이 필요하다고 생각합니다. 똑같은 표현을 하더라도 상대방이 기분 나쁘지 않게 받아들일 수 있도록 표현에 쿠션감(?)을 주는 것이죠.
그래서 저는 코드 리뷰를 달 때만큼은 특히 어조를 쾌활하게 유지하려고 합니다. 그리고 상대방이 잘 한 부분에 대해서는 칭찬을 남기는 것도 잊지 않구요. 즉 짚어야 할 부분은 정확하게 짚되, 활기차고 긍정적인 태도로 제 의견을 전달하는 것을 목표로 하고 있습니다. 뭐 실제로는 무표정일 수도 있겠지만, 텍스트로는 활기찬 척(?) 하는 건 괜찮다고 생각합니다.
한편으로는 리뷰이 역시 다가올 리뷰에 대해서 상처받지 않을 각오가 필요하다고 생각합니다. 펜싱 선수들이 보호 장비를 착용하고 경기장에 오르는 것처럼요.
상대방이 나를 불쾌하게 할 의도로 공격하지 않는다는 것을 알고 있어도 공격이 너무 아프게 들어온다면 감정이 상할 수 있죠. 하지만 펜싱 경기 내에서 상대방에게 최선을 다해 공격하는 행위가 상대방을 싫어하기 때문이 아닌 것을 우리 모두가 알고 있습니다.
그렇기 때문에, 코드 리뷰에서도 코드와 나를 분리하여 생각하는 것이 중요합니다. 지적에 대해서는 열린 마음으로 받아들이고, 상대방의 의도를 이해하려고 노력해야 합니다. 그리고 이런 행동이 나를 향한 인격적인 공격이 아니라는 것을 상기해야 합니다.
물론 이것이 쉽지 않은 걸 알고 있습니다. 저도 사람이다 보니 가끔씩 날아오는 날카로운 코멘트에 상처를 받을 때가 있긴 하지만, 그래도 이런 점을 염두에 두면서 코드 리뷰에 참여하려고 노력하고 있습니다.
만약 본인 성격이 개차반이라서 친절하게 남기기가 어렵다면 ChatGPT의 도움을 받아보자
하지만 그럼에도 불구하고 리뷰어와 리뷰이의 의견 충돌이 지속될 수도 있죠. 이럴 조짐이 보이거나 대화가 너무 길어진다면, 저는 보통 오프라인에서 만나서 대화하는 것을 추천합니다. 서로 얼굴을 보고 대화하는 것이 텍스트로만 전달되는 피드백보다 더 친절하게 느껴지고 존중을 표현하기 쉽기 때문이죠.
정해진 규칙 내에서 경쟁한다
펜싱 경기는 공격 방법과 범위 따라 종류가 구분되며, 규칙도 달라집니다. 그리고 경기에 참여하는 선수들은 규칙을 준수하고 존중해야 합니다.
코드 리뷰에서 이는 코딩 컨벤션, 또는 팀 문화 와 같습니다. 이러한 규칙은 코드의 일관성을 유지하고 애매한 상황에서 판단의 기준이 되기 때문에, 팀원이 합의하여 정하고 누구나 접근 가능한 곳에 문서로 정리해 두는 것이 필요합니다.
가령 분기가 여러 개인 경우의 메서드를 작성할 때, if
문이나 switch
문을 쓸 수도 있지만 객체의 프로퍼티로 분기를 만들 수도 있습니다. 셋 다 맞는 방법이지만 이런 사소한 것으로 인해 코드 리뷰가 오랫동안 질질 끌린다면 그것은 소모적인 논쟁입니다.
따라서 이렇게 정답이 없는 논쟁이 매 리뷰마다 발생하지 않기 위해서는, 팀원 간의 합의된 규칙을 레퍼런스로 참조하여 대화를 진행하는 것이 좋습니다. 이렇게 남겨진 규칙들이 상세하게 정리될수록, 리뷰 과정에서 생기는 소모적인 의견 충돌을 줄일 수 있습니다.
팀원의 합의하여 정한 내용이라는 것은 신규 입사자에게 있어서도 중요한 내용입니다. 신규 입사자의 경우는 규칙에 익숙해지기까지 시간이 걸리는데요, 규칙에 관련된 실수를 할 때마다 컨벤션 문서 링크가 포함된 코멘트를 남겨준다면 신규 입사자의 빠른 적응에도 도움이 되기 때문입니다.
한편 각 회사나 프로젝트마다 문화가 다를 수도 있는데요, 추천할 만한 코드 리뷰 문화로는 뱅크샐러드에서 제안한 P5룰을 예시로 들 수 있을 것 같습니다. 사실 이전 회사에서도 팀원들과 합의 하에 리뷰의 필수 반영 여부를 이모지로 표시하는 방식을 사용했었는데요, 개인적으로 적용 경험이 꽤 좋았던 기억이 나네요.
다만 이런 규칙은 절대적인 것이 아니므로, 구성원들 간의 합의를 통해 언제나 변경이나 추가가 가능하다는 점도 명심해야 합니다. 구성원들도 규칙을 준수하면서 불편하다는 생각이 들면, 구성원들과의 논의를 적극적으로 고려해 봐야 합니다.
개인의 객관적 역량을 인지한다
펜싱 선수들은 각자의 강점을 최대한 발휘하는 방법을 연구합니다. 어떤 선수는 빠른 순발력을 무기로 삼을 수도 있고, 어떤 선수는 신체적 우위를 활용할 수도 있습니다. 초조한 상황에서 긴장하지 않는 침착함도 무기가 될 수 있죠.
코드 리뷰에서도 리뷰어들은 개인이 강점을 살리면서 기여할 수 있는 부분을 고민해야 합니다. 꼼꼼하게 코드를 살펴보는 것이 무기일 수도 있고, 큰 그림을 볼 줄 아는 능력이 무기일 수도 있죠. 넓고 얕은 기술적 지식을 리뷰에 활용할 수도 있고, 특정 기술에 대한 깊은 이해를 리뷰에 활용할 수도 있습니다. 코드를 실행시키지 않고도 상황 판단을 빠르게 하는 능력을 갖출 수도 있죠.
내가 어떤 강점을 갖고 있으며, 팀에 어떻게 기여할 수 있는지를 찾아내는 것은 쉽지 않습니다. 하지만 반복적으로 코드 리뷰를 하다보면 팀에서 내가 상대적으로 어떤 성향이 뛰어난지를 인지할 수 있습니다. 이러한 성향 차이를 인지하고 그 사실을 팀원들과 공유한다면 코드 리뷰를 더욱 효과적으로 수행할 수 있겠죠?
이와 더불어 각자의 역량에 따라 리뷰 역할을 다르게 분배할 수도 있습니다. 예를 들어, 개발 경험이 많은 리뷰어는 코드 설계나 알고리즘 등 전반적인 코드 구조에 대한 피드백을 제공할 수 있고, 개발 경험이 적은 리뷰어는 문법 오류나 코딩 규칙 준수 등의 세부적인 부분을 체크하는 방식으로 기여 방식을 나누어볼 수 있습니다. 이러한 역할과 역량에 근거하여 자신의 강점을 최대한 발휘할 수 있는 리뷰 환경을 조성하는 것이 좋습니다.
팀워크를 통해 성장한다
펜싱은 개인 스포츠이기도 하지만 팀 스포츠이기도 합니다. 예를 들어, 팀 경기에서 팀원 중 한 명이 약점을 보인다면 다른 팀원들이 그 부분을 보완하여 팀 전체의 성과를 높일 수 있죠. 또한 팀원들이 서로의 경기를 관찰하여 각자가 놓치고 있는 부분을 찾아내어 전체적인 성과를 높일 수 있습니다. 덕분에 펜싱 팀은 각 개인 기량의 한계를 넘어서서 더 높은 성과를 이끌어 낼 수 있습니다.
코드 리뷰에서도 마찬가지입니다. 리뷰어와 리뷰이는 코드 리뷰를 통해 전체적인 코드 품질을 높이는 것뿐만 아니라 팀원들이 서로의 코드를 이해하고 협력할 수 있는 관계로 이어주는 매개체가 됩니다. 그 덕분에 각자 작성한 코드의 호환성이 높아지며, 팀 전체의 생산성도 높일 수 있죠. 따라서 코드 리뷰에서도 팀워크와 신뢰는 매우 중요한 요소 중 하나입니다.
그렇기 때문에, 저는 신규 입사자라면 코드 리뷰를 통해 신뢰 관계를 빠르게 구축하는 것이 매우 중요하다고 생각합니다. 협업 경험이 충분한 사람들끼리는 신뢰가 많이 누적되어 있기 때문에 전반적인 리뷰의 난이도도 완만하지만, 서로 잘 모르는 상태에서 주고받는 리뷰는 의심의 눈초리에 좀 더 가깝기 때문입니다. 이 사람이 실력은 있는데 적응에 시간이 필요한 사람인지, 아니면 진짜로 기술적 지식이 모자란데 운빨로 들어온 사람인지 모르기 때문입니다.
그래서 저는 새 조직에 합류한 후 몇 달 동안은 상대방이 ‘아니, 이렇게까지 자세하게 설명해주다니?!” 라고 생각할 정도로 오버스러운 코드 리뷰를 달곤 합니다. 서로가 기술적으로 신뢰할 수 있는 상태로 만들기 위해서는 신규 입사자가 본인의 역량을 증명하는 것뿐만 아니라 조직 문화에도 빠르게 적응하기 위해 노력하고 있다는 것을 티낼 필요가 있다고 생각해요.
때문에 조직 적응기에서의 코드 리뷰가 유독 힘들고 어렵게 느껴질 순 있는데요, 나의 열정을 코드 리뷰에 집중하면서 기술적 신뢰 관계를 쌓는 것을 단기적인 목표로 삼아보세요.
요약
결국 위의 내용들을 요약하면 코드 리뷰에서 추구하는 가치가 스포츠맨십과 유사하다는 것을 알 수 있습니다.
- 최선: (스포츠 선수와 개발자는) 각자 맡은 바에 따라 최선을 다합니다.
- 상호존중: (스포츠 선수와 개발자는) 소통과 협업 과정에서 각자의 의견을 존중하고 상대방을 배려하는 태도가 필요합니다.
- 공정: (스포츠 선수와 개발자는) 합의된 규칙 내에서 행동하며, 필요에 따라 규칙을 개선할 수 있습니다.
- 자기 성찰: (스포츠 선수와 개발자는) 자신의 역량을 객관적으로 판단하고 팀에 어떻게 기여할 수 있는지를 고민합니다.
- 팀워크: (스포츠 선수와 개발자는) 신뢰 관계를 구축하고 서로의 모자란 부분을 채워주며 팀의 성과를 높이는 데 기여합니다.
마무리
치열하게 코드 리뷰로 의견을 주고받았다 해도, 끝난 후에는 같이 커피 마시면서 잡담하는 게 팀원 아닐까?
이렇게 저는 코드 리뷰를 긍정적인 경쟁으로 생각하니, 언젠가부터 남에게 보여주었을 때 부끄럽지 않은 코드를 작성하기 위해 노력하고 있는 제 모습을 볼 수 있었습니다. 그리고 다른 사람의 코드를 좀 더 열심히 리뷰를 할 동기 부여도 받을 수 있었구요.
이러한 경험을 바탕으로, 지금은 팀 내에서 ‘아, 이 분이 어프루브를 해주었다면 신뢰할 만하다’ 라고 생각될 정도로 깊은 신뢰를 쌓는 것이 목표이긴 한데… 아직 갈 길이 멀어 보이네요. 😂
앞으로도 코드 리뷰를 통해 더 많은 것을 배우고, 더 나은 코드를 작성할 수 있도록 꾸준한 멘탈 관리를 실천해야겠습니다.