코드 리뷰하는 법
원문은 Matthias Endler님이 에 게재했습니다. 이 블로그 구독하기
나는 꽤 오래전부터 다른 사람들의 코드를 리뷰해 왔다. 정확히 말하면 20년이 넘었다. 요즘은 업무 시간의 50~70%를 어떤 형태로든 코드 리뷰에 사용한다. 시스템 설계와 함께, 그것이 내가 돈을 받고 하는 일이다.
시간이 지나면서 코드를 효과적으로 리뷰하는 방법에 대해 한두 가지 알게 되었다. 지금은 처음 시작했을 때와는 다른 부분에 집중한다.
큰 그림을 생각하라
나쁜 리뷰는 시야가 좁다. 유지보수성과 확장성 대신 문법, 스타일, 사소한 문제에만 집중한다.
좋은 리뷰는 변경 사항 자체뿐 아니라 그 변경이 어떤 문제를 해결하는지, 앞으로 어떤 문제가 생길 수 있는지, 그리고 그 변경이 시스템의 전체 설계에 어떻게 들어맞는지도 함께 살핀다.
나는 바뀌지 않은 코드를 살펴보는 것을 좋아한다. 거기에 진짜 이야기가 숨어 있는 경우가 많기 때문이다.
예를 들어, 코드베이스나 문서의 관련 부분을 업데이트하는 것을 잊는 경우가 많다. 이는 버그나 혼란, 호환성을 깨뜨리는 변경, 혹은 보안 문제로 이어질 수 있다.
철저하게 살펴보고 새로 추가된 코드가 호출되는 모든 곳을 확인하라. 제대로 업데이트되었는가? 테스트는 여전히 올바른 대상을 검증하고 있는가? 변경은 적절한 위치에 이루어졌는가?
코드 리뷰할 때 스스로에게 던지는 질문들을 정리한 치트 시트다.
- 이 코드는 시스템의 나머지 부분과 어떻게 어우러지는가?
- 코드베이스의 다른 부분과는 어떻게 상호작용하는가?
- 전체 아키텍처에는 어떤 영향을 미치는가?
- 앞으로 예정된 작업에 영향을 미치는가?
이런 질문들은 변경 자체보다 시스템 설계와 더 관련이 있다. 큰 그림을 놓치지 마라. 나쁜 변경을 받아들이면 시스템은 쉽게 부서진다.
코드는 고립되어 작성되지 않는다. 더 경험 많은 개발자의 역할은 운영상의 마찰을 줄이고 프로젝트의 리스크를 관리하는 것이다. 문서, 테스트, 데이터 타입은 코드 자체만큼이나 중요하다.
코드가 발전함에 따라 더 나은 추상화가 없을지 항상 주시하라.
네이밍이 전부다
나는 코드를 리뷰할 때 좋은 이름을 고민하는 데 상당한 시간을 쓴다.
이름 짓기는 어렵다. 그래서 제대로 하는 것이 그토록 중요하다. 종종 코드 리뷰에서 가장 중요한 부분이기도 하다.
또한 가장 주관적인 부분이기도 해서, 사소한 트집과 중요한 네이밍 결정을 구분하기 어려워 지루하게 느껴지기도 한다.
이름은 개념을 압축하고 코드에서 “구성 요소” 역할을 한다. 나쁜 이름은 더 깊은 곳에 있는 문제를 암시하는 코드 스멜이다. 이해에 필요한 인지 부담을 한 단계 이상, 많게는 수 배까지 늘린다.
예를 들어, 게임에서 플레이어의 스탯을 나타내는 struct가 있다고 하자.
struct Player {
username: String,
score: i32,
level: i32,
}다음과 같은 코드를 자주 본다.
// Bad: using temporary/arbitrary names creates confusion
fn update_player_stats(player: Player, bonus_points: i32, level_up: bool) -> Player {
let usr = player.username.trim().to_lowercase();
let updated_score = player.score + bonus_points;
let l = if level_up { player.level + 1 } else { player.level };
let l2 = if l > 100 { 100 } else { l };
Player {
username: usr,
score: updated_score,
level: l2,
}
}이 코드는 읽고 이해하기 어렵다. usr, updated_score, l2는 무엇인가? 의도가 명확하게 드러나지 않는다. 이는 인지 부담을 쌓아 로직을 따라가기 어렵게 만든다.
그래서 나는 다소 까다롭게 느껴지더라도 항상 변수에 가장 적합한 이름을 고민한다.
// Good: meaningful names that describe the transformation at each step
fn update_player_stats(player: Player, bonus_points: i32, level_up: bool) -> Player {
// Each variable name describes what the value represents
let username = player.username.trim().to_lowercase();
let score = player.score + bonus_points;
// Use shadowed variables to clarify intent
let level = if level_up { player.level + 1 } else { player.level };
let level = if level > 100 { 100 } else { level };
// If done correctly, the final variable names
// often match the struct's field names
Player {
username,
score,
level,
}
}값이 사용되는 곳에서 멀리 떨어진 곳에 선언되어 있고, 많은 개발자가 문제 도메인에 대한 공통된 이해를 공유해야 하는 큰 코드베이스에서는 좋은 이름이 더욱 중요해진다.
“아니오”라고 말하기를 두려워하지 마라
나는 수시로 변경을 거절해야 하는데, 그게 절대 쉽지 않다. 어쨌든 누군가 많은 노력을 들였고 자신의 작업이 받아들여지길 바라기 때문이다.
결정을 포장하거나 무작정 좋게 보이려 하지 마라. 객관적으로 이유를 설명하고 더 나은 대안을 제시하라. 그 자체에 매달리지 말고 다음 단계를 고민하라.
나중에 문제를 일으킬 올바르지 않은 것을 받아들이는 것보다 거절하는 편이 낫다. 한번 선례를 만들면 앞으로 그 변경을 거절하기는 더욱 어려워진다.
그것이 리뷰 과정의 존재 이유다. 코드가 반드시 받아들여진다는 보장은 없다.
오픈소스에서는 많은 사람들이 기준에 미치지 못하는 코드를 기여한다. “아니오”라고 말해줄 누군가가 필요하고, 이는 매우 인기가 없는 역할이다(오픈소스 메인테이너에게 물어보라). 하지만 훌륭한 프로젝트에는 게이트키퍼가 필요하다. 그렇지 않으면 수준 이하의 코드가 쌓이고 결국 유지보수할 수 없는 프로젝트가 되기 때문이다.
때로는 사람들이 “일단 머지하고 나중에 고치자”고 말한다. 나는 그것이 미끄러운 경사라고 생각한다. 기술 부채와 추가 작업으로 이어질 수 있다. 소신을 지키는 것은 어렵지만 중요하다. 뭔가 잘못되었다고 느끼면 목소리를 내라.
어려워질 때는 당신이 거절하는 것은 사람이 아니라 코드라는 것을 기억하라. 그들의 노력에 감사하고, 그들이 더 나아지도록 돕고 싶다는 점을 상기시켜 주라.
리뷰에서 무엇에 집중해야 할지 직감이 생기더라도, 여전히 사실로 뒷받침해야 한다. 같은 이유로 계속 “아니오”라고 말하고 있다면, 팀을 위한 스타일 가이드나 가이드라인을 작성하는 것을 고려해 보라.
정중하되 단호하라. 결국 코드일 뿐이다.
코드 리뷰는 커뮤니케이션이다
코드 리뷰는 단지 코드에 대한 것만이 아니다. 사람도 중요하다. 동료들과 좋은 관계를 쌓는 것이 중요하다.
나는 가능하면 처음 몇 번의 리뷰는 페어 프로그래밍 세션으로 함께 진행하려고 한다.
이렇게 하면 서로의 커뮤니케이션 스타일을 배울 수 있다. 이런 방식으로 신뢰를 쌓고 서로를 알아가는 것이 효과적이다. 이후에 소통이 원활하지 않거나 오해가 생겼다고 느끼면 그 과정을 다시 반복해야 한다.
여러 차례에 걸쳐 리뷰하라
“이 PR 좀 빨리 봐줄 수 있을까요? 오늘 머지하고 싶어요.” 코드 리뷰가 한 번에 끝나는 일이라는 기대가 종종 있다. 하지만 실제로는 그렇지 않다. 코드 리뷰는 반복적인 과정이다. 코드를 제대로 다듬기 위해서는 여러 차례의 반복이 필요하다는 것을 당연하게 여겨야 한다.
나는 첫 번째 단계에서는 큰 그림과 전체적인 설계에 집중한다. 그 단계가 끝나면 세부 사항으로 들어간다.
목표는 가능한 한 빨리 머지하는 것이 아니라, 품질이 높은 코드를 받아들이는 것이어야 한다. 그렇지 않다면 코드 리뷰를 하는 의미가 무엇이겠는가? 이는 중요한 사고방식의 전환이다.
리뷰는 결함을 지적하는 것에 만 국한되지 않는다. 팀 내에서 코드에 대한 공통된 이해를 만드는 과정이기도 하다. 나는 종종 다른 사람의 코드를 리뷰하면서 더 나은 코드를 작성하는 법을 가장 많이 배운다. 뛰어난 엔지니어들로부터 내 코드에 대해 훌륭한 피드백을 받기도 했다.
이는 개발자로서 성장하는 데 도움이 되는 값진 “아하 모먼트”다. 전문가들이 귀한 시간을 들여 내 코드를 리뷰해 주었고, 나는 그로부터 많은 것을 배웠다. 모든 사람이 커리어에서 한 번쯤은 그런 경험을 해봐야 한다고 생각한다.
무례하게 굴지 마라
가끔은 작성자와 의견이 달라질 때가 있다. 존중하고 건설적인 태도를 유지하는 것이 중요하다. 인신공격이나 깔보는 듯한 말투는 피하라. “이건 틀렸습니다”라고 말하지 마라. 대신 “나라면 이렇게 하겠습니다”라고 말하라. 상대가 주저한다면, 그들의 생각을 이해하기 위해 몇 가지 질문을 던져 보라.
- “이렇게 하면 기존 워크플로가 망가지지 않을까요?”
- “어떤 대안들을 고려해 보셨나요?”
- “이 함수를 빈 배열로 호출하면 어떻게 되나요?”
- “이 값을 설정하지 않으면 사용자에게 어떤 오류 메시지가 표시되나요?”
이러한 “소크라테스식 질문”1은 작성자가 자신의 결정을 돌아보게 하고 더 나은 설계로 이어질 수 있다.
사람들은 당신의 피드백을 받는 것을 즐거워해야 한다. 그렇지 않다면 자신의 리뷰 스타일을 되돌아보라. 자신이 받아도 기분 좋을 만한 코멘트만 남겨라.
가끔은 “이 부분 좋네요”나 “훌륭한 아이디어입니다” 같은 긍정적인 코멘트를 남기기도 한다. 작성자의 동기를 유지하고 그들의 작업에 감사하고 있음을 보여주는 것은 큰 힘이 된다.
가능하면 코드를 직접 실행해 보라
코드를 너무 오래 들여다보면 미묘한 부분을 놓치기 쉽다. 직접 만져볼 수 있는 로컬 복사본이 있으면 큰 도움이 된다.
가능하면 코드와 테스트, 린터를 직접 실행해 본다. 브랜치를 체크아웃해서 이리저리 만져보고, 일부러 망가뜨려 보며 어떻게 동작하는지 이해하려는 과정 자체가 내 리뷰 과정의 일부다.
UI 변경이나 오류 메시지 같은 사용자 대면 변경은 코드를 직접 실행해 보고 망가뜨려 보려 할 때 훨씬 쉽게 발견할 수 있다.
그 뒤에는 변경 사항을 되돌리고, 필요하다면 발견한 점을 코멘트로 남긴다. 이런 접근을 통해 더 깊은 이해에 이를 수 있다.
가능한 일정을 솔직하게 밝혀라
코드 리뷰는 종종 개발 과정에서 병목이 된다. 완전히 자동화할 수 없고 코드를 보고 피드백을 줘야 하는 사람이 개입되어 있기 때문이다.
하지만 동료가 코드를 리뷰해주기를 기다리는 상황은 좌절감을 줄 수 있다. 그런 사람이 되지 않도록 하라.
때로는 코드를 리뷰할 시간이 없을 수도 있고, 그건 괜찮다. 합리적인 시간 안에 리뷰할 수 없다면 작성자에게 알려주라.
나도 아직 노력 중이지만, 내 일정에 대해 더 능동적으로 알리고 명확한 기대치를 설정하려고 애쓴다.
배움을 멈추지 마라
코드 리뷰는 내가 새로운 것을 배우는 가장 좋아하는 방법이다. 새로운 기술과 패턴, 새로운 라이브러리를 배우고, 무엇보다 다른 사람들이 문제에 어떻게 접근하는지를 배운다.
나는 리뷰할 때마다 한 가지 새로운 것을 배우려고 노력한다. 그것이 팀 전체가 개선되고 성장하는 데 도움이 된다면 헛된 시간이 아니다.
사소한 것에 집착하지 마라
포매터가 존재하는 데는 이유가 있다. 공백과 형식은 도구에 맡겨라. 정말 중요한 문제에 에너지를 아껴 두라.
로직, 설계, 유지보수성, 정확성에 집중하라. 코드 품질에 영향을 주지 않는 주관적인 취향은 피하라.
스스로에게 물어보라. 이게 기능에 영향을 미치는가, 혹은 미래의 개발자를 혼란스럽게 할 것인가? 그렇지 않다면 그냥 넘어가라.
‘어떻게’보다 ‘왜’에 집중하라
코드를 리뷰할 때는 변경의 배경이 되는 이유에 집중하라. 이유 없이 결함만 지적하는 것보다 훨씬 성공할 가능성이 높다.
다음 두 개의 코드 리뷰 코멘트를 비교해 보자. 첫 번째는 도움이 되지 않고 일축하는 식이다.

두 번째는 대안을 제시하고 문서 링크를 첨부하며, 왜 그 변경이 나중에 문제를 일으킬 수 있는지 설명한다.

둘 중 어떤 코멘트를 받고 싶은가?
이것이 더 많은 시간과 노력을 필요로 한다는 것을 안다. 하지만 그만한 가치가 있다! 대부분의 경우 작성자는 고마워할 것이고 앞으로 같은 실수를 반복하지 않을 것이다. 도움이 되는 리뷰는 시간이 지날수록 복리 효과를 낸다.
바보 같은 질문을 두려워하지 마라
추측하는 것보다 물어보는 것이 낫다. 이해가 안 되는 부분이 있다면 작성자에게 설명을 요청하라. 아마 당신만 이해하지 못한 것이 아닐 것이다.
작성자는 종종 자신의 이유를 기꺼이 설명해 줄 것이다. 이를 통해 코드와 시스템 전체에 대한 이해가 깊어질 수 있다. 또한 작성자가 다른 관점에서 사물을 바라보는 데 도움이 될 수도 있다. 어쩌면 자신의 가정이 틀렸다는 것을 깨닫거나, 시스템이 스스로를 설명하지 못한다는 것을 알게 될 수도 있다. 어쩌면 문서가 빠져 있는 것일지도 모른다.
자신의 리뷰 스타일에 대해 피드백을 요청하라
가끔은 작성자에게 당신의 피드백 자체에 대한 피드백을 요청해 보라.
- 너무 가혹했는지/사소한 것에 집착했는지/느렸는지/대충 했는지?
- 올바른 부분을 지적했는지?
- 당신의 피드백이 도움이 되었는지?
- 개선할 점에 대한 제안이 있는지?
말하자면, 그들에게 당신의 리뷰 과정을 리뷰해 달라고 요청하는 셈이다, 하하.
코드 리뷰하는 법을 배우는 것은 꾸준한 연습과 다듬음이 필요한 기술이다. 자신만의 스타일을 찾는 데 행운을 빈다.
그 용어를 알려준 Lucca에게 고마움을 전합니다! ↩
글을 무작위로 읽기
댓글
로그인하고 댓글 남기기