[번역] 좋은 코드 리뷰를 수행하는 방법

2026. 3. 10. 14:04·Game Programming
728x90
반응형

 

 

원문 링크

How to do a good code review

https://asawicki.info/articles/code_review_en.php

 

좋은 코드 리뷰를 수행하는 방법

영어 | 폴란드어 이 글은 원래 폴란드어로 Programista 잡지 112호(2024년 3월/4월)에 게재되었습니다. 좋은 코드 리뷰를 수행하는 것은 숙달할 가치가 있는 기술입니다. 이 글에서는 이 기술의 장점과 단점에 대해 논의하겠습니다.

asawicki.info

 

Gemini를 사용하여 번역하였습니다,

 

이 기사는 원래  Programista 잡지 112호(2024년 3월/4월)에 게재되었습니다.

좋은 코드 리뷰를 수행하는 것은 습득할 가치가 있는 기술입니다. 이 글에서는 이 프로세스의 장점과 단점이 무엇이며, 어떤 프로젝트에서 이를 적용하는 것이 좋은지 논의하겠습니다. 코드 리뷰를 수행할 때 어떤 접근 방식을 취해야 하는지, 어떻게 하는 것이 가장 효과적인지, 코드의 어떤 측면에 집중해야 하는지, 그리고 마지막으로 코드에 대한 우리의 의견을 어떤 형태로 작성해야 프로젝트에 도움이 되고, 이 전체 과정이 팀원들 간의 생산적인 소통의 기회가 되며 갈등의 원인이 되지 않을지에 대해 고민해 보겠습니다.

첫 코드 리뷰를 맡게 되었는데 어떻게 시작해야 할지 모르시나요? 다른 사람의 코드를 검토할 때 어떤 점을 주의해야 할까요? 코멘트는 어떤 형식으로 작성해야 할까요? 아니면 여러분이 작성한 코드가 다른 사람들의 리뷰를 받게 될 텐데, 무엇을 기대해야 하고 어떻게 반응해야 할지 모르시나요? 그렇다면 이 글이 여러분을 위한 것입니다! 하지만 이미 경험이 풍부한 개발자라 하더라도, 여기 제시된 조언들 중에는 동의할 수도 있고 동의하지 않을 수도 있지만, 분명히 생각할 거리를 제공할 것입니다.

여기서 말하는 것은 물론 소프트웨어 개발 과정에서 한 개발자가 다른 개발자의 코드를 검토하고 자신의 의견을 제시하며, 모든 것이 괜찮다고 판단되면 승인하는 절차입니다. 폴란드어로 예를 들어 "코드 검토"라고 표현할 수도 있지만, 저는 널리 사용되는 영어 용어인 "code review"를 사용하겠습니다.

이 관행은 조직과 팀마다 다양한 형태를 취할 수 있습니다. 옆자리 동료가 비공식적으로 불러서 화면에 표시된 코드를 함께 보고 의견을 나누는 것일 수도 있습니다. 반면에, 버전 관리 시스템(예: GitHub의 'pull request' 또는 Perforce Swarm) 내에서 특수 도구를 사용하는 완전히 공식화된 프로세스일 수도 있으며, 검토자가 승인해야만 병합(merge) 또는 제출(submit)이 가능하도록 잠금이 해제됩니다.

여기서는 코드 리뷰를 특정 조직, 특정 팀, 특정 프로젝트 내에서 진행되는 프로세스로 논의할 것입니다. 그러나 동일한 내용이 오픈 소스 프로젝트 관리에도 적용될 수 있습니다  오픈 소스 프로젝트 운영에도 동일하게 적용될 수 있습니다. 예를 들어 GitHub에서 다양한 사용자들이 "이슈(issues)"와 "풀 리퀘스트(pull requests)"를 통해 제기하는 의견들도 공개적으로 접근 가능한 해당 코드의 일종의 코드 리뷰 역할을 합니다.

코드 리뷰는 언제, 왜 해야 할까요?

코드 리뷰 관행을 특정 프로젝트에 도입할 가치가 있는지 여부는 프로젝트의 특성을 고려하고 이 관행의 장단점을 파악한 후 개별적으로 결정해야 합니다.   장점 중 가장 먼저 떠오르는 것은 코드 품질 향상입니다. 새로 작성되거나 수정된 코드 조각마다 추가적인 검토를 거치면 다른 관점에서 평가할 기회가 생기므로, 리포지토리에 반영되기 전에 잠재적인 오류를 발견하고 보고할 수 있습니다. 이는 논리적 오류, 잘못 처리된 "경계 사례"(예: 입력 데이터가 비어 있을 때), 메모리 누수, 성능 문제 또는 심지어 보안 취약점일 수 있습니다.

코드 리뷰 수행에는 다른, 덜 명백한 장점들도 존재합니다. 이 관행을 도입하면 모든 코드 조각을 최소 두 명 이상의 사람이 보고 어느 정도는 알게 됩니다. 이는 각 엔지니어를 담당하는 주제의 '사일로'에 가두기보다는, 모든 팀에서 바람직한 지식의 확산으로 이어집니다. 덕분에 향후 필요 시 다른 누군가가 해당 코드 작업을 더 쉽게 재개할 수 있을 것입니다. 즉, 소위 '버스 팩터(bus factor)'가 증가합니다. 마지막으로, 팀 동료가 컴파일러뿐만 아니라 우리의 코드를 읽을 것이라는 인식 자체만으로도, 단순히 올바르게 작동할 뿐만 아니라 잘 설계되고 가독성 있는 코드를 작성하기 위해 더 큰 주의를 기울이도록 동기부여할 수 있습니다.

물론 코드 리뷰 수행의 단점도 언급할 수 있습니다. 첫 번째이자 가장 명백한 것은 개발자들이 이에 할애해야 하는 소중한 시간입니다. 다른 사람의 코드를 검토하고 코멘트하는 데 소요되는 모든 작업 시간은 자신의 코드를 작성하거나 디버깅하는 데 할애하지 못하는 시간입니다. 개발자의 자원과 시간을 관리하는 입장에서 보면 이는 시간 낭비로 보일 수 있으며, 최소한 작업 생산성을 저하시키는 요인으로 여겨질 수 있습니다. 자신의 작업에서 벗어나 다른 프로그램 부분에 주의를 집중해야 하는 필요성도 무시할 수 없으며, 이는 정신적으로 부담스러울 수 있습니다.

코드 리뷰를 프로세스에 포함시키는 것에 반대하는 사람들이 자주 제기하는 주장은 코드 내 오류는 오히려 잘 작성되고 정기적으로 실행되는 테스트(단위 테스트, 통합 테스트 등)를 통해 발견되어야 하며, 또는 QA 부서의 수동 프로그램 테스트, 그리고 정적 코드 분석과 같은 다른 자동화 도구로 발견되어야 한다는 주장입니다. 물론 이는 사실입니다. 마찬가지로, 코드를 읽는 사람이 머릿속으로 테스트할 수 있는 가능한 경우의 수는 좋은 테스트가 확인할 수 있는 경우의 수만큼 많지 않다는 것도 사실입니다.

그럼에도 불구하고 하나가 다른 하나를 배제하지는 않습니다. 오히려 자동 테스트와 코드 리뷰는 서로를 훌륭하게 보완한다고 말할 수 있습니다. 리뷰어는 테스트로 커버되지 않는 특정 사례를 발견할 수 있습니다. 게다가 테스트는 코드의 구조, 가독성, 변수 및 함수 이름의 적절성, 주석, 첨부된 문서 등 향후 코드 유지보수에 핵심이 될 수 있는 중요한 측면들을 전혀 검증하지 않습니다.

코드 리뷰의 또 다른 잠재적 단점은 프로세스 지연입니다. 코드 내 모든 변경 사항을 승인해야 하는 필요성, 자동화된 테스트를 통과해야 하는 필요성은 가장 사소한 변경 사항조차 작성 후 최소 하루 이상이 지나야 저장소에 반영되도록 할 수 있습니다. 이러한 상황은 프로젝트의 성격과 코드 반복 속도에 따라 수용 가능할 수 있습니다. 리뷰 프로세스의 효율성은 물론 이 프로세스의 조직 방식에도 영향을 받습니다. 다른 팀원이 변경 사항을 승인하기만 하면 되는 경우, 모든 것이 한 팀 리더가 모든 리뷰를 승인해야 하는 경우보다 더 빨리 진행될 수 있습니다. 특히 해당 리더가 매우 바쁘거나 휴가를 떠난 경우에는 더욱 그렇습니다.

이 부분을 요약하자면,   코드 리뷰를 할 가치가 있는지는 프로젝트의 성격에 따라 달라집니다. 프로토타입, 내부 사용을 위한 도구 또는 임시 해결책을 작성하는 경우라면, 코드 품질이 최고 수준일 필요는 없기 때문에 이를 수행하지 않는 것이 더 나을 수 있습니다. 이 경우 코드 생성 및 수정 속도와 전체 프로세스의 민첩성이 더 중요합니다.

반면, 프로젝트가 고객에게 제공되는 시스템의 개발 및 유지보수와 관련된 것이라면, 아마도 우리 회사의 주요 제품이거나 다른 소프트웨어(예: 컴파일러, 운영체제)가 작동하는 기반 플랫폼일 수 있습니다. 이 경우 코드 품질은 최우선 과제여야 합니다. 그러나 복잡한 프로세스가 이를 강제하지 않더라도, 최소한의 수준에서라도 항상 이 품질을 관리할 가치가 있습니다. 결국 우리는 "임시방편이 가장 오래가는 법"이라는 것을 알고 있습니다. 이 장의 요약을 표 1에서 확인할 수 있습니다.

꼭 그렇지는 않다

덜 중요한 프로젝트, 예를 들어 보조 도구 중요한 프로젝트, 예를 들어 우리 회사의 주요 제품
시간이 중요합니다 – 빠른 반복 품질이 중요합니다 – 오류는 최소화해야 합니다
임시 프로젝트, 예: 프로토타입 장기 프로젝트 – 현재 존재하거나 장기간 유지될 예정입니다.
소수 사용자 그룹을 위한 프로젝트, 예를 들어 내부 사용을 위한 다양한 사용자층을 대상으로 한 프로젝트, 예를 들어 인터넷에 공개적으로 제공되는 프로젝트
안전성과 신뢰성은 중요하지 않습니다. 예를 들어, 로컬에서 실행되는 싱글 플레이어 게임. 안전성과 신뢰성은 핵심입니다. 예를 들어, 네트워크 서버, 다른 소프트웨어를 위한 플랫폼 등이 있습니다.

표 1. 해당 프로젝트에서 코드 리뷰를 수행할 가치가 있는가?

어떻게 접근해야 할까?

이 글에서는 특정 코드 예시나 프로그래밍 언어의 구조에 대해 다루지 않을 것입니다. 어떤 언어로 프로그래밍하든 상관없이 이 글이 도움이 될 수 있습니다. 대신 리뷰를 수행하는 일반적인 접근법에 대해 살펴보겠습니다. 하지만 먼저 기본부터 시작해 보겠습니다…

코드 리뷰를 수행할 때도 프로그래밍할 때와 마찬가지로   좋은 프로그래밍 관행이 적용됩니다. 여러분은 이미 그중 상당수를 알고 계실 것입니다. 어느 정도 공식화되었든 아니든, 관련 과정을 수강했든, 컴퓨터 공학을 전공했든, 아니면 독학으로 실전 경험을 쌓았든 상관없이 말이죠. 여기서 말하는 것은 특정 언어와 라이브러리에서 제공되는 구조를 올바르고 효율적이며 간단하게 사용하는 모든 원칙을 의미합니다. 코드를 작성할 때 항상 염두에 두어야 할 사항들은 타인의 코드를 검토할 때도 고려할 가치가 있습니다.

물론 해당 조직, 팀 또는 프로젝트에서 정한 규칙도 적용됩니다. "코딩 표준"과 같은 문서가 작성되어 변수 명명 방식(CamelCase 또는 snake_case?)이나 코드 내 오류 처리 방식(예외를 던지거나 숫자 오류 코드를 반환하는가?)을 규정하고 있다면, 코드 리뷰 시 이러한 규칙 준수 여부를 확인하는 것이 좋습니다. 이러한 문서는 많은 모호함을 해소하고 기준점이 될 수 있으므로 마련하는 것이 좋습니다. 그러나 공식적인 표준 문서가 없더라도, 오래 운영된 팀이라면 반드시 존재하는 암묵적인 규칙(소위 "부족 지식")이 있을 것이며, 이를 발견하고 적응하는 것이 중요합니다.

마지막으로, 코드 리뷰를 진행할 때는  예의가 필요합니다. 결국 리뷰에서의 코멘트는 사람과 사람 사이의 소통입니다. 컴파일러나 ChatGPT에게 쓰는 것이 아니라 살아있는 사람에게 쓰는 것입니다. 리뷰에 코멘트를 작성하는 주제에 대해서는 나중에 더 자세히 다루겠지만, 지금 당장 강조할 점은 (예전에 표현되던 대로) "네티켓", 즉 인터넷에서 지켜져야 할 예의와 품위의 원칙이 적용된다는 것입니다. 사실 이는 언제 어디서나 지켜져야 할 원칙입니다. 코드 리뷰의 경우 특히 "피드백", 즉 의견 교환의 기술을 주고받는 데 익숙해지는 것이 도움이 될 수 있습니다. 이 주제에 대해 더 알아보는 것이 좋습니다.

어떤 대규모 프로젝트에서는 모든 코드 변경 사항이 전체 코드를 관리하는 한 명의 리드 개발자의 검토를 거쳐야 한다는 규칙이 적용되었습니다. 그를 '위대한 벤'이라 부르자. 그는 수년 전 이 프로젝트의 초석을 다졌고, 이제 유지보수가 새 팀에 넘어가도 여전히 모든 것이 자신의 원래 비전에 부합하도록 감시한다. 그는 코드 자체에서 명백한 것들조차도 장황한 주석으로 설명하도록 요구한다. 그는 프로그래밍 언어에서 스마트 포인터나 다른 현대적인 메커니즘 사용을 금지한다. 모든 것은 그가 원하는 대로 명명되어야 한다. 세부 사항에 대한 논의나 개인적인 의견의 여지는 없다. 이 팀의 개발자들이 그와 이 프로젝트에 대해 어떻게 생각하는지 상상하기 어렵지 않다.

위 이야기는 완전히 허구이며, 실제 인물이나 프로젝트와의 유사성은 우연의 일치입니다. 그러나 아무도 그런 프로젝트에 참여하고 싶어하지 않을 것입니다. 특히 우리가 다른 사람의 코드를 리뷰할 때, 그런 '위대한 벤'이 되고 싶지 않습니다. 따라서 기초부터 시작하여 코드 리뷰를 할 때 어떤 마음가짐이 좋을지 고민해 볼 필요가 있습니다.

가장 먼저 그리고 가장 중요한 원칙으로, 어느 쪽이든 리뷰에 참여할 때   자신의 자아를 버리는 것. 이는 동양의 어떤 구루나 LSD를 너무 많이 복용한 히피의 영적 지혜처럼 들릴 수 있지만, 실제로는 매우 간단한 것을 의미합니다: 자신의 코드에 지나치게 집착하지 말고, 그에 대한 비판을 개인적으로 받아들이지 말라는 것입니다. 이렇게 말할 수 있습니다: "기억하세요, 당신의 코드는 당신 자신이 아닙니다!"

우리가 작성한 코드는 그 자체를 위해 존재하는 것이 아니라 무언가를 위해 존재합니다. 경험 많은 프로그래머는 수백 줄의 새 코드를 추가하는 것보다 한 줄의 핵심 코드를 수정하는 것이 프로젝트에 더 가치 있을 때가 많다는 것을 압니다. 수천 줄의 불필요해진 코드를 제거하는 것은 더 가치 있을 뿐만 아니라 만족스럽기도 합니다. 결국 코드가 짧을수록 아직 발견되지 않은 오류가 숨어 있을 수 있는 구석이 적어집니다. 따라서 우리가 추가한 코드 줄에 지나치게 집착할 필요는 없습니다.

여기서   책임에 대한 의문이 제기됩니다. 우리가 작성한 코드에 집착하거나 맹목적으로 방어해서는 안 된다면, 아예 '우리 코드'라고 부르지 말고 모든 코드를 공동의 것으로 취급해야 하는 것일까요? 저는 어느 한쪽으로 지나치게 치우치는 것도 문제라고 생각합니다. 모든 코드 줄을 우리 자신이 작성한 것이 아니라 공동의 것으로 간주한다면, 그 코드의 품질, 오류, 가독성, 유지보수에 대한 모든 책임을 회피할 수 있습니다. 즉, 공산주의 시대에 모든 것이 '공동의', "국가 소유", 즉 "아무도 소유하지 않은" 것이었기에, 이는 또한 성실한 작업을 방해했습니다.

제 생각에는, 이 두 극단 사이의 균형을 찾기 위해 코드 리뷰를 예술가처럼 접근하기보다는 엔지니어나 기계공처럼 접근하는 것이 좋습니다. 자신의 코드를 '내면의 영감'이 지시한 작품으로 여기고, 이제 아무것도 바꿔서는 안 되며 모든 것이 정확히 그대로 유지되어야 다른 사람들이 감탄할 수 있다고 생각하는 것은 좋지 않습니다. 이런 태도로는 코드에 대한 모든 의견이 개인적인 공격으로 받아들여질 수 있습니다.

기계공의 관점에서 접근한다면, 코드 변경을 정비소에서 자동차를 수리하는 것과 같다고 생각할 수 있습니다. 그 자동차는 더럽고 낡았으며 심지어 녹슬었을 수도 있지만, 우리는 그 안에서 하나의 시스템을 수리했고 지금 작동하는 방식에 만족합니다. 우리는 이 수리에 서명하며, 신중하게 그리고 좋은 관행에 따라 수행했다는 책임을 집니다. 아마도 몇 가지 타협을 해야 했고, 테이프와 '트라이프'로 무언가를 고정해야 했을 수도 있지만, 우리는 정확히 무엇을, 어떻게, 왜 그렇게 했는지 알고 있습니다. 결국 중요한 것은 차량이 정상적으로 운행되고 고객이 만족하는 것입니다.

특정 코드 부분에 대한 책임이라는 주제와 관련하여,   누가 코드 리뷰를 해야 하는가? 여기에 대한 단 하나의 규칙은 없습니다. 이 결정은 특정 프로젝트와 팀의 특성에 따라 달라질 수도 있고, 개발자들 간의 비공식적 소통 과정에서 자연스럽게 생겨날 수도 있습니다. 가장 경험이 많고 최고 직위를 가진 한 명 또는 몇 명에게 모든 리뷰를 맡기는 것도 하나의 방법입니다. 그러나 여기서 위험한 점은, 위에서 언급한 '위대한 벤'처럼 권위를 가진 한 사람이 자신의 경직되거나 구식 관점을 강요함으로써 프로젝트에 해를 끼칠 수 있다는 것입니다. 다른 옵션은 각 모듈, 파일 또는 디렉터리가 해당 코드 조각을 작성하고 가장 잘 알고 관리하는 '소유자'를 두는 것입니다.

역설적이게도, 리뷰를 팀의 다양한 구성원들, 특히 "주니어"들에게 맡기는 것도 한 가지 해결책이 될 수 있습니다. 경력이 짧은 이들은 우리 프로젝트를 아직 잘 알지 못하거나 프로그래밍 경험이 많지 않더라도, 새로운 시각으로 코드를 바라보며 토론에 신선함을 불어넣고, 질문을 통해 흥미로운 논의를 이끌어낼 수 있습니다. 또한 이러한 리뷰를 진행하며 스스로 많은 것을 배울 수 있을 것입니다.

코드 리뷰를 어떻게 수행하나요?

일반적인 접근 방식을 논의했으니 이제 구체적인 내용으로 넘어가 보겠습니다. 누군가의 코드 리뷰를 수행해야 합니다. 어떻게 시작해야 할까요? 어디서부터 시작해야 할까요? 이 글에서는 특정 도구나 프로그래밍 언어에 초점을 맞추지 않지만, 코드를 검토하고 추가된 줄, 변경된 줄, 삭제된 줄과 같은 변경 사항을 명확히 표시해 주는 편리한 도구가 있다고 가정합니다.

코드에 도입된 변경 사항은 다양한 관점에서 검토할 수 있습니다 – 보다 일반적인 수준에서 또는 세부 사항에 집중하여 살펴볼 수 있습니다. 이는 그림 1에 설명되어 있습니다.  일반적인 수준 에서는 어떤 파일, 클래스, 아마도 전체 디렉터리와 모듈이 추가되었는지 살펴봅니다. 우리는 그 구조를 이해하려고 노력합니다 – 각 요소의 논리적 의미와 그들 사이의 연관성을요. 이는 우리가 작업하게 되는 새로운 코드를 배울 때와 유사합니다. 유일한 차이점은 코드 리뷰에서는 새로 추가된 기능이나 클래스(검토 중인 코드의 작성자가 추가한 것)와 코드에서 변경되지 않은 부분으로 명확히 구분된다는 점입니다. 후자의 경우 변경 사항만 비교하는 뷰에서는 보이지 않을 수도 있지만, 전체 아키텍처를 완전히 이해하기 위해 때로는 이를 참조해야 합니다.

 

그림 1. 코드를 볼 수 있는 다양한 수준

우리가 이 모든 그림이 이미 "머릿속에 들어오지 않는다"고 느낄 때, 때로는   클래스 다이어그램을 그려보는 것 종이에 UML 표기법이나 다른 어떤 표기법, 아마도 우리만의 표기법으로. 이는 클래스 간의 연관성—상속 관계, 포함 관계 및 기타 관계—를 시각화하고 이해하는 데 도움이 됩니다. 코드의 전반적인 구조를 이해하는 또 다른 접근법은 코드를 컴파일하고 디버거에서 실행하여 제어 흐름을 단계별로 추적하고, 어떤 함수가 어떤 다른 함수를 호출하는지, 어떤 조건에서 호출되는지 등을 이해하는 것입니다.

반면, 코드 변경 사항은  세부 사항 관점에서, 즉 줄 단위로 코드를 읽으면서 검토할 수 있습니다. 몇 줄만 변경되는 리뷰의 경우 당연히 이 관점만으로 살펴보게 됩니다. 각 줄을 읽으면서 우리는 마음속으로 여러 가지를 확인할 수 있습니다. 특정 산술 표현식이나 논리 표현식이 올바른가? 참조하는 포인터나 참조가 이 위치에서 절대 빈 상태가 되어 프로그램이 "크래시"하지는 않을까? 변수 이름이 코딩 표준에 따라 명명되었으며 그 이름이 용도를 반영하는가?

이 두 가지 측면 모두 중요하며 서로 보완적입니다. 리뷰에서 제기된 의견은 코드의 전반적인 구조와 특정 명령어 모두에 관한 것일 수 있습니다. 전반적인 구조만 분석하면 특정 명령어의 많은 오류를 놓칠 수 있습니다. 반면 코드를 줄 단위로 검토할 때는 전체적인 함수 및 클래스 구성의 부적절한 조직을 간과할 수 있습니다. 그러나 두 측면을 동시에 고려하는 것은 어렵습니다.

따라서 코드에서 더 복잡한 변경 사항을 검토할 때는  여러 번에 걸쳐 진행하는 것이 좋습니다. 먼저 전체를 빠르게 훑어보며 – "스크롤"하면서 – 검토해야 할 코드의 양, 변경 사항이 적용된 프로젝트의 부분, 그리고 추가되거나 변경되거나 삭제된 주요 클래스 및 함수의 이름을 파악하려고 노력합니다. 이렇게 시작하면 코드를 처음부터 끝까지 꼼꼼히 살펴보는 대신, 어떤 부분에 우선적으로 더 집중해서 살펴볼지 더 잘 결정할 수 있습니다.

새로운 코드에 대한 지식은 점진적으로 쌓여갑니다. 특정 프로젝트와 기존 코드를 잘 알고 있더라도, 리뷰를 시작한 첫 순간부터 새로운 코드나 작성자의 의도를 알지 못한다는 점을 명심해야 합니다. 따라서  코멘트를 서둘러 달 필요는 없습니다. 처음에는 오류로 보일 수 있는 것이, 우리가 리뷰를 진행하며 제안된 변경 사항의 전체적인 그림을 더 잘 이해하게 되면 올바르고 의도된 것으로 드러날 수도 있습니다. 검토 중인 코드에 대한 의견은 따로 메모해 두었다가, 전체 코드를 검토하고 충분히 이해한 후에야 공식적으로 리뷰에 반영하는 것이 좋습니다. 그 사이 우리가 떠올린 많은 의견들은 변경되거나 잘못된 것으로 드러날 수 있습니다.

우리는 코드 줄 수가 프로젝트의 품질이나 프로그래머의 작업 효율성을 결정하는 지표가 아니라는 것을 알고 있습니다. 마찬가지로 리뷰에서 제기된 코멘트의 수는 그 자체로 목표가 되어서는 안 되며, 무엇이나 누군가를 평가하는 기준으로 삼아서는 안 됩니다. 리뷰어의 눈에는 한 코드 변경 사항이 완벽해 보이고 모든 품질 기준을 충족하며 수정할 필요가 없을 수도 있지만, 다른 변경 사항은 반대로 여러 부분에서 의문을 불러일으킬 수 있습니다. 농담 삼아 코드 품질의 척도는 리뷰 중에 나오는 "WTF 분당"의 수라고 말하기도 합니다. 그러나 이 수치는 양측 모두, 즉 코드 작성자와 검토자 모두에게 달려 있습니다.

또한 이런 말이 있습니다: "프로그래머에게 10줄의 코드 리뷰를 맡기면 10개의 코멘트를 달 것이다. 1000줄의 코드 리뷰를 맡기면 단지 LGTM(Looks Good To Me)만 쓸 것이다." 후자의 상황은 리뷰어가 새로운 코드 전체를 세밀하게 분석하지 않았음을 의미합니다. 하지만 작은 변경 사항은 검토하기가 더 쉽다는 점은 인정해야 합니다. 따라서 큰 작업과 대량의 새 코드는 여러 개의 작은 변경 사항으로 분할  단계별로 추가하고 검토하는 것이 좋습니다. 예를 들어 별도의 브랜치에서 작업한 후, 모든 새로운 기능이 완료된 시점에서만 메인 브랜치로 병합하는 방식이 가능합니다.

무엇에 주의해야 할까요?

코드를 검토할 때, 저자에게 보고할 수 있는 다양한 의견이 떠오릅니다.   모든 의견이 똑같이 중요하지는 않으며 상대방이 동의하지 않고 다른 의견을 가질 경우 이를 위해 싸울 가치가 없다는 점입니다. 달리 표현하자면, 이를 더 객관적인  (예: 프로그램 중단을 초래할 수 있는 논리적 오류)와  주관적인 것들(예: 특정 변수를 어떻게 명명하는 것이 가장 좋은지)로 나눌 수도 있습니다. 이 상황은 그림 2에 설명되어 있습니다.

 

그림 2. 코드에 대한 가능한 주석 유형을 중요도 순으로 분류한 것

그러나 이 구분은 엄격하지 않으며, 우리는 결코 100% 확신해서는 안 됩니다. 우리에게 명백한 오류로 보일 수 있는 것이 실제로는 그렇지 않을 수도 있습니다. 왜냐하면 저자가 해당 지표나 참조가 특정 위치에서 다른 코드 조각에 의해 null이 되지 않도록 보장했기 때문인데, 우리는 그 부분을 간과했을 수 있습니다. 반면, 변수 명명 문제는 제안된 이름이 불분명하거나 심지어 혼란스러울 경우 중요할 수 있습니다.

일반적으로 코드 작성자에게는 어느 정도의 자유를 부여하고, 전체 코드의 구조나 개별 요소 명명법을 우리가 원하는 대로 강요하지 않는 것이 좋습니다. 그가 "자신을 표현"할 수 있도록 허용합시다. 결국 그는 코드의 작성자이고 우리는 단지 검토자일 뿐입니다. 프로젝트에 "코딩 표준"을 문서화하고, Clang Format과 같은 자동 포맷팅 도구를 사용하는 것도 좋습니다. 그러면 코드 내 사소한 부분들이 주관적인 평가에 맡겨지는 경우가 줄어듭니다.

그러나 항상 객관적으로 최선의 답이 없는 질문들이 등장할 것입니다. 예를 들어: "이 함수 이름이 여기서 최선의 선택인가?" 이때 메타 질문을 던져볼 필요가 있습니다: "이게 정말 중요한가?". 중요하지 않고 취향의 문제에 가까운 사항에 대한 의견은 물론 제시할 수 있지만, 오직 객관적이고 중요한 문제(예: 코드 내 오류)에 대해서만 논쟁하고 변경을 요구할 가치가 있습니다.

코드를 전반적으로 분석할 때 주목할 수 있는 예시적 측면 중 하나는 클래스 분할, 그 의미론적 중요성 및 클래스 간 관계입니다. 제안된 아키텍처가 해당 용도에 최적인지, 예를 들어 지나치게 복잡하지 않은지 고려해 볼 필요가 있습니다. 일부 개발자들은 고전적인 책 '4인방의 책'에 매료되어 코드를 최대한 일반화하고 향후 수정을 대비하기 위해 디자인 패턴을 적용할 수 있는 곳을 찾아다니곤 합니다. 그러나 그들은 종종 미래에 코드가 현재 예측할 수 없는 방식으로 변경될 가능성이 있으며, 코드가 복잡할수록 그 변경이 더 어려워질 수 있다는 점을 간과합니다.

중간 수준의 세부 사항으로 분석할 수 있는 것은  제안된 알고리즘의 성능을 분석할 수 있습니다. 성능 문제는 때로 도널드 크누스가 대중화한 "조기 최적화는 모든 악의 근원이다"라는 인용구로 무시되곤 합니다. 그러나 이 명언은 컴퓨터 과학 분야에서 가장 남용되고 오해받는 것 중 하나이며, 더 넓은 맥락에서 벗어나 인용된 것입니다. 저자가 의미한 것은 사소한 비효율성 개선이나 마이크로 최적화였는데, 이는 예를 들어 어셈블리어로 재작성하는 방식으로 코드를 덜 가독성 있게 만들고 유지보수를 어렵게 할 수 있습니다.

성능 최적화를 다룰 때 프로파일러를 먼저 사용해 성능을 측정하고, 시스템의 병목 현상이 발생하는 코드 부분을 파악하는 것이 중요합니다. 그러나 알고리즘과 데이터 구조를 설계할 때는 성능과 보안에 관한 모범 사례를 항상 염두에 두어야 합니다. 리뷰에서도 이러한 측면을 평가하는 것이 좋습니다. 결국 O(n²)과 같이 계산 복잡도가 낮은 알고리즘은 테스트 데이터에서는 잘 작동할 수 있지만, 데이터 크기가 커지면 알고리즘이 너무 비효율적이어서 사용자가 프로그램이 완전히 멈췄다고 보고할 수 있습니다(비록 캐시 메모리에 들어갈 만큼 작은 데이터에서는 이런 알고리즘이 때로는 더 빠를 수도 있지만).

가장 낮은 수준의 세부 사항에 집중하면, 코드에서 변수나 함수 이름의 적절성을 평가할 수 있으며, 또한  코멘트 를 평가할 수 있습니다. 많은 사람들이 코멘트는 전혀 필요하지 않다고 주장합니다. 코멘트 없이도 코드 자체가 가독성이 있어야 한다는 것이죠. 제 생각에는 너무 급진적인 접근이지만, 실제로 좋은 코멘트와 가독성 있는 코드는 서로 밀접하게 연관되어 있습니다.

리스트 1에는 나쁜 코멘트의 예시와 이를 개선하는 방법을 보여줍니다. 여기서 사용된 프로그래밍 언어는 C++입니다. 이러한 구체적인 예시 선택은 물론 논란의 여지가 있을 수 있지만, 일반적으로 가독성 있는 코드를 대체하는 주석은 나쁘다고 말할 수 있을 것입니다. 코드가 무엇을 하는지 명백히 드러나는데도 주석에서 이를 반복하는 것은 좋지 않습니다. 변수나 함수의 용도를 설명하는 주석을 달기보다는 적절한 이름을 부여하는 것이 좋습니다. 마지막으로, 함수 코드를 여러 부분으로 나누기 위해 ASCII 아트 스타일의 '선'을 주석으로 그리는 것보다는 코드를 별도의 함수로 분리하는 것이 좋습니다.

Listing 1. 나쁜 주석의 예시와 수정된 버전

return buffer_size; // Returns buffer size.
-->
return buffer_size;

// 7% is the percent of users to be selected for discount.
// Formula calculates number of users to receive discount.
AssignDiscount( GetTotalUserCount() * 7 / 100 );
-->
constexpr int percent_users_with_discount = 7;
int users_with_discount = GetTotalUserCount() * percent_users_with_discount / 100;
AssignDiscount( users_with_discount );

void RunProgram()
{
    ///////////////////////////////////////////////////////
    // Initialization
    …
    ///////////////////////////////////////////////////////
    // Calculations
    …
    ///////////////////////////////////////////////////////
    // Writing the results
    …
}
-->
void RunProgram()
{
    Initialize();
    Calculate();
    WriteResults();
}

그러나 주석은 코드만으로 표현하기 어려운 사항을 설명하는 데 유용할 수 있습니다. 예를 들어, 명확하지 않은 알고리즘 앞에 해당 알고리즘이 무엇을 하는지, 이름이 무엇인지, 어디서 가져왔는지 설명하는 주석이 좋은 주석입니다. 마찬가지로 주석은 특정 변수나 함수 매개변수에 대한 가정을 명시할 수 있습니다. 예를 들어, 특정 포인터가 null일 수 있는지, 그리고 그것이 무엇을 의미하는지(예: 해당 매개변수가 선택적일 때), 다른 특수 값(예: 반환된 인덱스 -1은 요소를 찾지 못했음을 의미함), 숫자 변수가 가질 수 있는 값의 범위(예: 0…100 범위여야 함) 또는 어떤 단위로 표현되는지(예: 미터, 밀리초, 퍼센트) 등을 명시할 수 있습니다.

별도의 범주로는 특정 함수, 클래스 또는 전체 라이브러리의 인터페이스를 문서화하는 주석이 있습니다. 여기서는 각 함수와 그 매개변수, 그리고 각 구조체와 그 필드를 설명하여 사용자가 내부 구현을 연구하지 않고도 이러한 요소들을 사용하는 방법을 주석에서 배울 수 있도록 해야 합니다. 이러한 주석들도 리뷰 과정에서 확인하고 문서의 일부로 간주해야 합니다. 해당 코드를 더 포괄적으로 설명하는 워드 문서나 컨플루언스 페이지와 함께 고려할 수 있습니다. 주석과 문서는 사실 동일할 수 있습니다. Doxygen이나 Sphinx 같은 도구를 사용하면 적절한 형식으로 작성된 주석에서 문서를 생성할 수 있기 때문입니다.

위에서 언급된 것은 코드 리뷰를 수행할 때 주목할 수 있는 선택된 예시적 측면들일 뿐입니다. 특히 특정 프로그래밍 언어에 집중하지 않고서는 그 모든 것을 설명하는 것은 불가능합니다. 따라서 훌륭한 코드 리뷰를 수행하는 것은 무엇보다도 실습을 통해 배울 수 있는 기술입니다.

어떻게 댓글을 작성하나요?

마지막으로, 검토 중인 코드에 대한 의견인 리뷰에 댓글을 어떤 형식으로 작성할지 생각해 보겠습니다. 앞서 언급했듯이, 무엇보다도  예의와 매너가 우선입니다. 한편으로는 당연해 보일 수 있습니다. 그러나 다른 한편으로는 쉽지 않을 수도 있습니다. 결국 리뷰 코멘트는 기사나 소셜 미디어 게시물 아래의 댓글, 기타 온라인 토론과 유사한 비동기적 소통 방식입니다. 그리고 우리는 알고 있듯이, 이런 공간에서는 친절하고 진지한 사람들도 때로는 최악의 무례한 사람으로 변할 수 있습니다.

리뷰에 댓글을 작성할 때는 특히 감정에 휩쓸리지 않도록 주의해야 합니다. 좋은 규칙은 상대방에게 직접 대면해서 말하지 않을 내용은 쓰지 않는 것입니다. 댓글을 보내기 전에 한 번 더 읽어보는 것이 좋습니다. 이렇게 하면 오타나 다른 문장 오류를 잡아낼 수 있을 뿐만 아니라, 내용에 대해 잠시 생각해볼 시간도 가질 수 있습니다. 또한 프로그래머로서 업무의 일환으로 리뷰를 작성할 때는 직업적 상황에 있으므로 전문적으로 행동하고 소통해야 합니다. 농담이나 주제와 무관한 토론은 회사 디스코드나 슬랙 채널에서 하는 것이 더 나을 수 있습니다.

우리는 이미 코드를 작성할 때 자신의 자아를 버리고 그에 대한 의견을 개인적으로 받아들이지 말아야 한다고 이야기했습니다. 이 원칙은 반대 방향으로도 적용됩니다: 다른 사람의 코드에 대한 의견을 제시할 때는,  코드 자체에 집중하는 것이 그 작성자에게 집중하는 것보다 낫습니다. 이러한 상황은 그림 3에 설명되어 있습니다. "당신은 이 코드를 이런 식으로 작성했으니 형편없는 프로그래머입니다." – 이는 매우 나쁜 코멘트의 예입니다. "이 코드는 최선의 방식으로 작성되지 않았습니다." – 이건 좀 더 나은 표현입니다. 더 나은 방법은 이렇게 쓰는 것입니다: "제 생각에는 이 코드가 최선의 방식으로 작성되지 않은 이유는 (...)입니다. (...) 이렇게 작성하는 게 더 나을까요?" 이 마지막 버전에는 몇 가지 좋은 관행이 담겨 있습니다. 이제 차례로 살펴보겠습니다.

 

그림 3. 코드에 집중하는 것이 저자에 집중하는 것보다 낫다

첫째, 리뷰를 작성할 때 가장 중요한 것은  겸손함입니다. 우리는 결코 100% 확신해서는 안 되며, 항상 우리가 틀릴 수도 있다고 가정해야 합니다. 따라서 "제 생각에는…", "제 의견으로는…", "제 생각에는…", 등과 같은 표현으로 시작하는 것이 좋습니다. 결국 우리는 여기서 자신의 의견을 표현하는 것입니다. 특히 주관적인 문제일 때(예: "제 생각에는 이 기능을 X 클래스에 넣는 것이 더 나을 것 같습니다")뿐만 아니라, 명백한 오류라고 생각될 때도 마찬가지입니다("제가 아는 한 이 기능은 그런 매개변수로는 제대로 작동하지 않을 것입니다").

둘째, "왜냐하면 (...)"라는 표현은 근거를 제시할 수 있는 부분입니다. 자신의 의견을 어떤  논거로 뒷받침하는 것이 좋습니다. 오류를 발견했다면, 결과가 잘못될 입력 데이터나 변수 값의 예를 제시하세요. 특정 함수 호출이 해당 라이브러리의 사양과 일치하지 않는다고 생각된다면, 그 함수의 올바른 사용법을 설명하는 문서의 주소를 붙여넣으세요. C 또는 C++ 언어와 그 표준 라이브러리의 경우, 예를 들어   cppreference.com의 특정 페이지 주소일 수 있습니다. 특정 코드가 프로그래밍에서 일반적으로 받아들여지는 좋은 관행에 부합하지 않는다고 생각된다면, 해당 언어 구문이 권장되지 않거나 권장되는 방식이 어떻게 보이는지에 대한 주장을 뒷받침하기 위해 인터넷에서 검색한 예시 페이지 주소를 붙여넣는 것도 유용할 수 있습니다.

셋째, 논의 중인 좋은 코멘트는 구체적인 변경 제안을 포함합니다: "이렇게 쓰는 게 더 나을까요: (…)?". 긍정적인 태도를 유지하며 단순히 문제를 지적하는 데 그치지 않고  가능한 해결책 이나 해결 방안을 제안하는 것이 좋습니다. 단순히 "변수 이름 i, j는 가독성이 떨어집니다"라고만 하는 대신, "group_index, element_index로 명명하는 것이 더 나을까요?"라고 덧붙이는 것이 좋습니다.

마지막으로, "이렇게 쓰는 게 더 나을까요: (…)?"라는 제안은 우연히도  질문 형식을 취하고 있습니다. 이러한 형식을 사용하는 것이 좋습니다. 왜냐하면 더 정중하게 들릴 뿐만 아니라 답변과 추가 논의를 유도하기 때문입니다. 만약 우리가 틀렸거나 무언가를 고려하지 않았고, 코드가 여전히 올바르거나 다른 이유로 작성자가 우리와 의견이 달라 변경을 원하지 않는다면, 그에게 이런 질문에 답하는 것이 자연스러울 것입니다. 예를 들어, "아니요, 제 코드에서는 (…) 이기 때문에 제 생각에는 이렇게 구현하는 것이 더 낫습니다."

리뷰에서 제기된 의견에 응답하는 코드 작성자의 역할로 돌아가서, 우리는 코드를 검토하는 사람과 동의하여 요청된 수정을 적용하거나 이미 적용했는지, 아니면 동의하지 않고 논쟁을 벌이고 싶은지(물론 자신의 의견을 뒷받침하는 근거를 제시하면서) 명확히 표시하는 것이 좋습니다. 팀 내 관행에 따라 "알겠습니다, 수락합니다. 수정하겠습니다"와 같은 공식적인 표현이나 심지어 "좋아요" 👍 이모티콘만으로도 충분할 수 있습니다. 의견에 대한 감사의 인사도 잊지 않는 것이 좋습니다.

요약

코드 리뷰를 할 가치가 있는지에 대한 질문에는 간단히 그리고 일반적으로 이렇게만 답할 수 있습니다: 상황에 따라 다릅니다. 그러나 특정 프로젝트에서 코드 리뷰를 프로세스의 일부로 포함시키기로 결정했거나 다른 누군가가 그렇게 결정했다면, 이 글에서 설명한 바와 같이 신중하게 수행하고 좋은 관행을 따르는 것이 좋습니다. 그러면 리뷰는 프로젝트에 도움이 될 것이며, 단순히 소중한 시간을 낭비하는 데 그치지 않을 것입니다.

코드 리뷰를 수행할 때, 이 과정이 사람들 사이의 갈등의 원인이 되지 않도록 주의해야 합니다. 오히려 공동의 목표를 위해 사람들을 하나로 모으는 계기가 되어야 합니다. 왜냐하면 코드 리뷰는 사람들과의 추가적인 소통 채널로도 볼 수 있기 때문입니다. 여기서 코드를 함께 검토하는 것이 그 명분이 됩니다.

Adam Sawicki
Luty 2024

728x90
반응형
'Game Programming' 카테고리의 다른 글
  • CEDEC 2024 관심가는 자료 링크 모음.
  • Direct3D 12: Long Way to Access Data
  • Data-Oriented Design
  • Newtonsoft json serialize enum as string
이민웅
이민웅
그저 그렇게 다시 시작해볼까?
  • 이민웅
    그저 그런 개발자
    이민웅
  • 전체
    오늘
    어제
    • 분류 전체보기 (113)
      • AI (2)
      • Game Programming (35)
      • ShaderStudy발표자료 (44)
      • Engine Development (29)
      • 언리얼 공부 (2)
  • 블로그 메뉴

    • 홈
    • 태그
    • 미디어로그
    • 위치로그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    사랑
    mobile
    길찾기 알고리즘
    CEDEC2021
    루리웹
    Apple
    한국어문신
    스티브잡스
    블로그이사
    게임개발자
  • 최근 댓글

  • 최근 글

  • 반응형
  • hELLO· Designed By정상우.v4.10.6
이민웅
[번역] 좋은 코드 리뷰를 수행하는 방법
상단으로

티스토리툴바