코드리뷰의 중요성
코드리뷰란, 한 명 또는 여러 명의 개발자가 본인이 만들지 않은 코드의 내용을 점검(examining)하고, 피드백을 주는 과정을 말합니다. 여기에서 피드백이란 오타, 버그 가능 성, 개발 표준 등에 대한 의견이 될 수도 있고, 좋은 코드에 대한 긍정적인 피드백이 될 수도 있습니다. 뒤에서 자세하게 설명하겠지만, 코드리뷰의 핵심은 단순히 코딩 스타일을 일관되 게 유지하거나, 예상되는 문제를 일찍 파악하는 데에 그치지 않고 코드에 대한 책임이 그 코드를 만든 사람 혼자에게 있지 않고 우리 모두에게 있다는 문화를 만드는 데에 있습니다.
이번 글에서는 코드리뷰가 실제로 왜 중요한지 알아보고 실제로 코드리뷰를 수행하는 방식들, 그리고 코드리뷰에서 중점적으로 확인해야 하는 내용들과 주의사항들을 순서대로 알아 보도록 하겠습니다.
코드리뷰는 왜 중요한가?
코드리뷰로 얻을 수 있는 가장 대표적인 장점으로는 ‘버그의 조기 발견’, ‘개발 표준(convention) 준수’, ‘중복 코드를 방지하고 모듈의 재사용성 증대’와 같은 것들이 있습니다. 본인은 쉽게 발견하지 못하는 실수를 다른 사람은 금방 발견하여 코드의 부작용(side effect)과 오류를 좀 더 일찍 조치할 수 있으며, 정해진 표준 준수를 통해서 많은 사람들의 개발 결과물이 일관된 스타일을 유지할 수 있도록 도와줍니다. 또한, 동일한 역할을 수행하는 중복 코드를 빨리 발견하고 이미 만들어진 코드를 재사용할 수 있도록 수정할 수 있습니다. “코드 컴플릿(Code Complete)”의 저자 스티브 맥코넬(Steve McConnell)은 책에 서 다음과 같은 실험결과를 통해 코드리뷰의 중요성을 강조합니다.
“소프트웨어를 유지보수하는 조직에서 코드 한 줄을 변경한다고 했을 때, 코드리뷰가 도입되기 전에는 그러한 변경의 55% 정도가 문제를 일으켰다. 그러나 리뷰 과정이 도입된 이후에는 그러한 변경의 2% 정도에서만 문제가 발생했다.”– by Steve McConnell (Code Complete)
코드 리뷰의 또 다른 장점으로는 다른 사람의 잘 만들어진 코드를 보면서 배울 기회를 얻는 것입니다. 같은 환경에서 개발을 진행하더라도 개인별로 해당 언어나 프레임워크에 대한 이해도와 경험은 크게 차이가 날 수 있습니다. 예를 들어, 프로그래밍 언어와 프레임워크가 추구하고자 하는 기본 철학을 이해하고 그에 맞는 방식을 유지하려고 노력하는 사람이 있으며, 기존에 다른 환경에서 개발하던 방식을 벗어나지 못하고 현재 환경의 장점을 활용하지 못하는 사람이 있습니다. 또한, 언어나 프레임워크가 기본적으로 제공하는 손쉬운 기능들을 잘 숙지하고 적절히 활용하는 사람이 있는가 하면, 이미 만들어져 있는 기능을 사용하지 못하고 직접 불필요한 기능을 추가하는 사람도 있습니다. 이러한 개인 간의 격차를 해소하는 가장 좋은 방법이 바로 코드리뷰이며 이를 통해 조금 더 좋은 방법을 제시해주고 이해 수준을 상향 평준화하는 것입니다. 즉, 코드리뷰는 단순히 버그를 사전에 발견하거나 문제점을 찾는 목적을 넘어서 전체적인 조직의 역량을 강화하는 중요한 역할을 합니다.
그럼에도 코드리뷰의 가장 중요한 점 한 가지를 뽑는다면 저는 ‘책임자를 추궁하지 않는 문화’의 정착이라고 말하고 싶습니다.
코드리뷰가 없고, 다른 사람이 어떤 부분을 어떻게 개발하고 있는지 모르는 상황에서는 특정한 문제가 발견했을 때 그 원인이 누구의 코드에 있는 지를 찾으려는 모습을 자주 확인할 수 있습니다. 코드리뷰 문화가 정착되면 특정 코드에 문제가 발생했을 때 누군가에게 책임을 묻거나 비난하는 문화를 없앨 수 있습니다. 즉, 배포된 코드에 문제가 있어서 서비스의 장애나 이슈가 발생한 경우 그 문제는 코드를 개발한 사람뿐 만 아니라, 해당 변경사항을 확인한 모든 사람이 연관되어 있기 때문에 그 책임이 누구에게 있는지를 찾기보다 왜 그 문제를 사전에 발견할 수 없었는지에 초점을 맞출 수 있게 됩니다. 다시 말해, 코드리뷰의 핵심은 ‘개발 결과물에 대한 책임이 그 코드를 만든 사람 개인에게 있지 않고, 우리 모두에게 있다는 문화를 정착하는 것’에 있습니다.
코드리뷰는 어떻게 하는가?
코드 리뷰를 실제로 수행하는 방식은 매우 다양하며 조직마다 조금씩 다를 수 있지만, 일반 적으로 ‘정형화되고 공식적인 코드리뷰(formal code review)’와 ‘자연스럽고 가벼운 코 드리뷰(lightweight code review)’ 두 가지 종류로 분류할 수 있습니다. 전자(formal code review)의 경우, 좀 더 전통적인 방식으로, 여러 명의 참석자가 정해진 절차에 의해서 코드의 상세한 부분을 하나하나 검토하는 방식입니다. 이 방식은 발생 가능한 문제를 조기에 발견할 가능성이 상당히 높지만, 수행하는 데에 드는 비용이 비싸고 빈번히 수행하기 어려우므로 빠르고 잦은 배포를 해야 하는 스타트업에는 적절하지 않은 방법일 수 있습니다. 물론, 서비스 런칭 직전 또는 대규모 배포 직전에 코드 인스펙션을 통해서 좀 더 높은 품질의 서비스를 제공할 수도 있습니다. 이 책에서는 주로 후자(lightweight code review)의 방식에 초점을 맞추어서 코드리뷰 기법을 설명하도록 하겠습니다.
가벼운 방식의 코드리뷰는 복잡한 절차나 부담감 없이 자연스럽게 코드리뷰를 수행하면서도 좋은 효과를 얻을 수 있는 방식입니다. 이 방식은 전통적인 구분(Over-the-shoulder, Email pass-around, Pair programming, Tool-assisted code review 등)에 따라 세부적으로 나누어지기도 하지만 이 책에서는 현실적으로 스타트업에 가장 적합한 두 가지 방식으로 나누어 새로운 분류 기준으로 설명합니다. 이 두 가지 방식은 반드시 한 가지를 선택해야 하는 것이 아니라 병행할 경우 더 좋은 효과를 얻을 수 있습니다.
온라인 코드리뷰
온라인 코드리뷰는 말 그대로 도구를 이용하여 온라인상에서 진행하는 방식의 코드리뷰입니다. 일반적으로 한 명의 코드를 리뷰하는 사람은 적게는 1명에서 많게는 5명 이상까지 다양하게 진행할 수 있습니다. 일반적으로 온라인 코드리뷰에 사용하는 도구들은 버전 관리 시스템, 이슈 트랙킹 시스템과 연동해서 해당 코드가 어떤 부분을 수정했는지, 어떤 이슈와 관련되어 있는지 쉽게 파악할 수 있도록 도와줍니다. 대표적인 코드리뷰 도구로는 Crucible, GitLab, Phabricator, Rhodecode 등이 있습니다. 만약 버전 관리 도구로 git을 사용하고 있다면 별도의 도구를 사용하지 않아도 github의 기본적인 pull request를 통해서 자연스럽게 온라인 코드리뷰를 진행할 수 있습니다.
일반적으로 온라인 코드리뷰는 코드의 작성자가 변경사항에 대한 코드리뷰를 요청하고, 리뷰어들은 해당 코드의 피드백을 작성하는 방식으로 진행됩니다. 만약, 코드 수정이 필요하다면 코드 작성자는 수정 사항들을 반영합니다. 이 과정이 완료되면 리뷰어들은 코드의 최종 확인을 완료합니다. 아래의 그림은 github을 이용하여 온라인에서 진행하는 코드리뷰의 예시입니다. 버전 관리 시스템의 특성에 따라 조금씩 다르지만 github의 경우 리뷰어가 해당 코드를 머지(merge)할 수 있는 권한이 있다면 최종 확인 후 코드를 머지하거나, 해당 코드가 최종적으로 확인되었음을 메시지로 표시합니다. 아래의 그림에서는 엄지손가락(thumbsup) 이모티콘을 이용해서 최종 확인 완료를 표시하였습니다.
코드리뷰를 진행할 때 도움을 받을 수 있는 한 가지 팁으로 반드시 지켜야만 하는 기준에 대한 체크리스트를 만들어 해당 내용이 통과될 때 코드를 수용(accept)하는 방식이 있을 수 있습니다. Github의 경우, ‘PULL_REQUEST_TEMPLATE’ 템플릿 파일을 이용하면 Pull Request의 가이드를 미리 작성할 수 있습니다. 이 가이드에 체크리스트를 미리 추가해두게 되면 개발자는 Pull Request를 보내면서 놓친 부분이 없는지 미리 점검하는 데에 이용할 수 도 있습니다.
팀리뷰
팀 리뷰는 온라인 리뷰와 반대로 팀 구성원들이 주기적으로 오프라인에서 진행하는 리뷰입니다. 팀 리뷰는 반드시 특정 코드에 대한 검토 형식으로 진행할 필요는 없습니다. 팀 리뷰 자체도 크게 보면 ‘자유롭고 가벼운 방식의 코들 리뷰’이기 때문에 다양한 주제를 가지고 진행할 수 있습니다. 예를 들어, 온라인 코드리뷰 과정에서 나왔던 내용을 기반으로 자유로운 토론을 진행할 수도 있고, 좋은 사례를 전체적으로 공유하는 시간으로 진행할 수도 있습니다. 또한, 자신이 궁금했던 점을 질문하거나 온라인 코드리뷰 과정에서 개선되었으면 하는 점을 제안할 수도 있습니다.
결론적으로, 팀 리뷰는 특정한 기준을 미리 정해두고 형식에 맞춘 회의가 되어서는 안 되고, 조직의 특성과 상황에 맞게 고유한 팀 리뷰 방식을 정해나가는 것이 좋습니다.
코드리뷰시 무엇을 확인해야 하는가?
앞에서 우리는 코드리뷰를 구체적으로 어떻게 수행하는지 알아보았습니다. 그렇다면 실제로 코드리뷰를 수행할 때 어떤 내용을 확인해야 하며, 어떠한 점들을 집중적으로 점검해야 하는지 알아보도록 하겠습니다.
기능의정상동작여부
기본적으로 모든 코드는 존재하는 목적을 가지고 있습니다. 다른 조건을 모두 만족하더라도 원하는 대로 동작하지 않는 코드는 잘못된 코드라고 할 수 있습니다. 코드리뷰의 시작과 끝은 언제나 기능이 원하는 대로 정상 동작하는지 확인하는 작업이 되어야 합니다.
버그의 조기 발견
코드 리뷰로 얻을 수 있는 장점 중 하나는 버그를 조기에 발견하여 불필요한 비용을 절감하는 것입니다. 같은 버그라고 해도 해당 버그를 코드리뷰 단계에서 발견하는 것과 테스트 단계에서 발견하는 것, 그리고 배포 이후에 발견하는 것은 순서대로 더 비싼 비용을 지불해야 합니다. 코드리뷰를 할 때는 버그가 발생할 소지가 없는지 점검해야 합니다.
가독성과 유지보수 편의성
코드의 가독성과 유지보수 편의성에 대한 견해는 같은 코드라고 해도 주관에 따라 조금씩 다를 수 있습니다. 그럼에도 이 내용을 주의 깊게 살펴야 하는 이유는 소프트웨어 개발의 전체 생명주기(life cycle)에서 유지보수가 차지하는 비중이 매우 크기 때문입니다. 또한, 스타트업의 경우 규모가 성장하면서 새로운 인력이 충원되거나 상황에 따라 퇴사자가 자주 발생 할 수도 있습니다. 물론, 가장 좋은 방법은 직원들이 비전과 목표를 공유하고 오랜기간동안 함께 하는 것이지만, 현실적으로 그렇지 못한 상황이 발생하더라도 다른 사람의 코드를 쉽게 이해하고 유지보수가 가능하도록 개발하는 것이 매우 중요합니다.
가독성과 유지보수 편의성은 자칫 잘못하면 주관적인 견해로 옳고 그름을 따지는 비생산적 논쟁으로 변질될 수 있으므로 가급적 기준을 정하고 해당 기준을 기반으로 검토하는 것이 좋습니다. 예를 들어, 들여쓰기(indent)의 크기나, 코드 한 줄의 최대 길이, 메소드 호출의 깊이(depth )등의 표준을 정해두면 좀 더 객관적인 기준으로 코드리뷰를 수행할 수 있습니다.
개발 표준(convention)의 준수 여부
앞에서 설명한 바와 같이 개발 표준(convention)은 가독성과 유지보수 편의성에 큰 영향을 미칩니다. 개발 표준을 잘 정리하고 지키려는 활동이 계속되면 많은 사람이 함께 개발하더라도 어느정도 일관된 개발 스타일을 유지할 수 있습니다. 그렇다고 해서 초기에 너무 세부적인 표준을 정하는 것은 표준을 위한 표준으로 전락하게 될 수도 있습니다. 될 수 있으면 최소한의 기본적인 표준을 정하고 시간이 지나면서 하나씩 기준을 추가해 나가는 것이 좋습 니다.
일반적으로 초기에 정해야 하는 기본적인 표준으로는 들여쓰기(indentation)의 크기, 코드 한 줄의 최대 길이, 파일과 변수의 명명규칙(naming) 등이 있고, 형상관리 도구를 사용 한다면 커밋 메시지에 대한 규칙도 추후에 변경사항을 추적할 때 용이하게 사용될 수 있습니다. 예를 들어, 해당 변경사항이 발생한 이유, 관련 히스토리 등을 커밋 메시지로 모두 적는 것이 어렵기 때문에 이슈 트래킹 시스템을 사용하고 있다면 해당 이슈의 ID를 커밋 메시지에 추가하는 것이 좋은 방법이 될수 있습니다.
테스트 코드의 작성 여부
테스트 코드를 작성하는 문화는 수많은 개발 조직에서 시도하지만 쉽게 정착하기 힘든 개발 문화 중 하나입니다. 형식적으로 작성된 테스트 코드가 아니라, 실제 잘 작성된 테스트 코드라면 코드의 품질을 높이는 데에 도움이 된다는 사실을 개발자라면 대부분 동의할 수 있을 것입니다. 이렇게 장점이 명확한 테스트 코드가 항상 누락되는 이유는 매우 다양합니다. 모든 개발자가 테스트 코드 작성을 당연시하고 습관적으로 수행하면 더 바랄 것이 없지만, 만약 그렇지 않다면 어느 정도 강제성을 통해 습관을 만들어나가는 노력이 필요합니다. 이런 상황에 적합한 것이 바로 코드 리뷰시 테스트 코드의 작성 여부를 확인하는 것입니다. 실제로 수많은 개발자가 동시에 개발을 진행하는 오픈소스 프로젝트들 대부분은 Pull Request 의 기본 조건으로 테스트 코드의 제출을 요구합니다.
사실, 테스트 코드의 효용성에 대해서는 다양한 의견들이 존재합니다. 만약 테스트 코드의 작성이 품질 향상에 도움이 된다고 확신하고 테스트 코드 작성을 활성화하고 싶다면 코드리뷰를 통해 테스트 코드 작성을 확인하는 것이 좋은 방법이 될수 있습니다.
재사용 가능한 모듈의 중복 개발
개발을 진행하다 보면, 자주 사용할 것 같은 기능들을 모듈화하여 재사용할 수 있도록 만드 는 경우가 많습니다. 그러나 정작 이렇게 만든 모듈을 공유하고 모두가 기억하도록 하는 것은 생각처럼 쉽지 않은 일입니다. 코드리뷰는 같은 기능을 하는 중복된 모듈의 개발을 막고, 코드의 재사용을 높이는 아주 좋은 방법입니다. 만약, 누군가가 재활용할 수 있는 기존 코드를 인지하지 못하고 스스로 중복된 코드를 만들었다면, 코드리뷰 과정에서 같은 기능을 하는 코드가 존재한다는 피드백을 받아 수정할 수 있습니다.
배울만한 점은 없는지
코드리뷰에 많은 사람이 오해하는 부분 중 하나는, 경력이 많거나 실력이 뛰어난 개발자가 후배 개발자의 코드를 검사한다고 생각하는 것입니다. 코드리뷰에서 코드의 작성자와 리뷰어는 누가 더 경력이 높거나 낮을 필요가 없습니다. 또한, 코드리뷰의 목적은 코드 작성자에 게 피드백을 주는 것도 있지만, 해당 코드를 보면서 ‘아, 이런 식으로 코드를 작성하는 것도 가능하구나?’, ‘아, 이렇게 쉬운 방법이 있었구나?’와 같은 학습효과도 함께 가지고 있습니다. 그렇기 때문에 코드를 리뷰할 때는 피드백을 주기 위한 시각과 좋은 점을 배우려는 시각, 이 두 가지 시각의 균형을 맞추며 진행하는 것이 좋습니다.
코드리뷰에서 주의해야 할 점들
처음 코드리뷰를 하다 보면 예기치 못한 논쟁이나 다툼이 발생하는 경우도 있습니다. 이것은 코드리뷰시 지켜야 하는 몇 가지 기본적인 주의사항들을 숙지하지 않아서 발생하게 됩니다. 코드를 작성한 사람은 물론, 코드리뷰를 수행하는 리뷰어들은 항상 다음과 같은 몇 가지 주의사항들을 숙지하며 코드리뷰를 수행하는 것이 좋습니다.
코드의 맥락(context)을 이해할 수 있는 설명을 추가하라
코드를 작성하는 사람은 코드리뷰를 받기 전에 해당 코드가 어떤 목적을 가지고 작성되었으며 왜 필요한지에 대한 맥락을 리뷰어가 이해할 수 있도록 설명을 적어두는 것이 좋습니다. 이러한 설명은 ‘로그인 시 발생하는 이메일 인증 오류에 대한 버그 수정입니다’와 같이 매우 간결할 수도 있고, 기존의 다른 이슈와 연관되어 긴 설명일 수도 있습니다. 물론, 이러한 설명을 소스코드의 주석으로 다는 경우도 있지만, 대부분의 버전 관리 시스템은 소스코드 변경의 이력을 쉽게 추적할 수 있기 때문에 주석보다는 코드리뷰 도구의 메시지 또는 코멘트를 이용하는 것이 좋습니다.
하나의 이슈(버그, 기능추가)당 하나의 코드리뷰
개발을 수행하다 보면 바쁘다는 이유로, 또는 수정사항이 너무 적다는 이유로 서로 다른 여러 개의 이슈를 동시에 처리하는 경우가 발생합니다. 이런 경우 어쩔 수 없이 코드리뷰도 동시에 수행되기 때문에 리뷰어는 독립된 하나의 이슈에 집중할 수 없고, 리뷰의 진행이 산만해지게 됩니다. 코드를 작성할 때에는 가급적 하나의 이슈에 대해서 하나의 코드리뷰가 수행될 수 있도록 하는 것이 좋습니다.
리뷰 받는 코드는 한 번에 500줄 이하
실제로 코드리뷰를 수행하다 보면 수천 줄의 수정사항을 확인해야 하는 경우가 있습니다. 한 번에 확인해야 하는 코드의 양이 너무 많은 경우 리뷰어는 상세한 리뷰를 진행하기 위해서 한 번에 너무 많은 시간을 투자해야만 합니다. 대부분 리뷰어는 코드의 양에 따라서 리뷰의 깊이를 조절하게 됩니다. 아래의 그림은 코드의 양(LOC: Line of Code)과 결함의 밀집도의 상관 관계를 나타내는 그림입니다. 그림에서도 볼 수 있듯이 한 번에 확인해야 하는 코드의 양이 많아지게 되면 발견되는 버그나 개선사항의 밀집도가 낮아져서 결과적으로 많은 부분을 놓치고 지나가게 됩니다. 이러한 이유로 많은 사람은 한 번에 리뷰 받는 코드의 양을 500줄 이하로 유지하라고 권장합니다.
주관적인 의견을 표현하는 방식
개발자는 누구나 각자의 개발 스타일을 가지고 있습니다. 개발 표준(convention)을 준수함으로써 어느 정도 일관된 스타일을 유지할 수는 있지만, 각자가 가진 스타일을 완전히 배제하는 것은 현실적으로 어렵습니다. 이러한 이유로, 코드리뷰를 진행하다 보면 각자의 견해 차이가 발생할 수 있습니다. 이때 중요한 것은 표현의 방식에 주의를 기울이는 것입니다. 기존에 자신이 일하던 방식이 정답이라는 생각을 버리고, “나의 의견은 이러한데 당신은 어떻게 생각하시나요?”와 같이 의견을 묻는 것이 좋습니다. 만약, 서로 다른 견해로 좀 더 많은 사람의 의견을 듣고 싶다면 비공식적인 팀 리뷰에 해당 내용을 제안하여 의견을 나눠보는 것도 도움이 됩니다.
리뷰를 너무 미루지 말자
한창 일이 바쁠 때 코드리뷰를 해야 하는 상황이 생기면 누구나 코드리뷰를 잠시 뒤로 미루게 됩니다. 그러나 이렇게 뒤로 미루는 것이 길어지게 되면 코드 작성자는 이어지는 작업에 불편함을 겪게 될 수도 있고, 시간이 지남에 따라 다른 코드와 충돌을 처리하면서 리뷰를 반복해야 하는 경우도 생길 수 있습니다. 이러한 문제를 해결하려면 코드리뷰를 중심 업무의 부수적인 작업으로 인식하지 말고, 코드리뷰에 집중할 수 있는 시간을 전체 일정에서 확보하는 것이 좋습니다.
이번 글에서 우리는 코드리뷰의 중요성과 코드리뷰를 구체적으로 실행하기 위한 방법들을 살펴보았습니다. 코드리뷰는 천천히, 그리고 꾸준히 만들어 나가야 하는 문화 중 하나입니다. 모든 문화가 그렇듯 코드리뷰를 이용한 협업의 개발 문화 역시 단기간에 강제로 정착시키기 보다 조금씩 천천히 습관이 길들도록 정착하는 것이 중요합니다.