이런 상황을 한번 상상해 보세요. 월요일 아침, 몇 달 만에 가장 깔끔하게 작성한 코드가 담긴 pull request를 열었습니다. 오후가 되자 댓글 하나 때문에 앞으로의 배포가 두려워집니다. 피드백이 틀렸기 때문이 아닙니다 — 틀리지 않았어요 — 그것이 전달된 방식 때문입니다. "이건 불필요하게 복잡합니다. 왜 이렇게 하셨나요?" 일곱 단어. 실행 가능한 안내는 전혀 없습니다. 그리고 어쩐지 그 한 주 내내 쓴맛이 남습니다.
코드 리뷰는 모든 엔지니어링 팀에서 가장 높은 레버리지를 가진 의식입니다. 잘 수행되면 더 좋은 소프트웨어를 배포하고, 엔지니어를 더 빠르게 성장시키며, 신뢰의 문화를 조용히 다져 줍니다. 잘못 수행되면 사람을 지치게 만들고, 배포를 늦추며, 뛰어난 엔지니어들이 매번 pull request마다 자신을 변호해야 한다는 느낌이 들지 않는 팀으로 떠나게 만듭니다. 이 가이드는 제대로 수행하는 방법에 관한 것입니다 — 구체적인 표현, 리뷰어 체크리스트, 리뷰를 조용히 독성으로 만드는 습관들, 그리고 댓글을 받는 입장일 때 어떻게 해야 하는지.
코드 리뷰는 버그 찾기가 아닌 문화입니다
코드 리뷰가 무엇을 위한 것인지에 대한 오해가 많습니다. 기술적인 목표 — 프로덕션에 도달하기 전에 버그 찾기 — 는 실제적이고 가치 있습니다. 하지만 그것은 이야기의 일부일 뿐입니다.
여러분이 남기는 모든 댓글은 무언가를 가르칩니다. 작성자에게 코드베이스에 대해, 트레이드오프에 대해, 팀이 중요하게 여기는 기준에 대해 가르칩니다. 수백 번의 리뷰에 걸쳐, 여러분은 팀의 집단 기억이 명시적으로 드러나는 존재입니다. 새로운 엔지니어는 여러분의 댓글을 읽으며 여기서 "좋은" 것이 무엇인지 배웁니다. 주니어 엔지니어는 리뷰어가 지속적으로 묻는 질문을 내면화하며 시니어가 됩니다. 시니어는 자신의 직관 뒤에 있는 "이유"를 설명하면서 예리함을 유지합니다.
리뷰는 또한 보이지 않게 규범을 설정합니다. 친절하고 구체적이며 호기심 어린 댓글을 지속적으로 남기는 팀은 불완전한 것을 배포하고 그로부터 배우는 것이 심리적으로 안전한 곳이 됩니다. 직설적이고 무시하며 모호한 댓글을 남기는 팀은 사람들이 비판을 피하려고 조용히 과도하게 엔지니어링하고, PR 열기를 미루며, 질문을 멈추는 곳이 됩니다.
엔지니어들이 pull request 열기를 두려워하면, 리뷰 횟수를 줄이기 위해 더 크고 큰 변경 세트에 작업을 모아 둡니다. 큰 PR은 제대로 리뷰하기가 더 어려워서 리뷰 품질이 떨어지고, 피드백은 더 가혹해지며, 악순환이 깊어집니다. 해결책은 덜 엄격해지는 것이 아닙니다 — 엄격함과 함께 더 많은 친절함입니다.
이것이 코드 리뷰가 부드럽거나 날이 없어야 한다는 의미는 아닙니다. 가장 효과적인 리뷰어는 깊이 솔직합니다. 문제를 명확히 지적합니다. 진정으로 중요한 것들은 원칙을 지킵니다. 하지만 작성자가 판사를 맞닥뜨린 것이 아니라 협력자를 얻은 것처럼 느끼도록 하는 방식으로 합니다.
실제로 무엇을 리뷰해야 하는가 — 그리고 무엇을 내버려 둬야 하는가
가장 흔한 리뷰 실수 중 하나는 모든 것을 동등한 비중으로 리뷰하는 것입니다. 끝에 쉼표가 없다고 PR을 막는 리뷰어는 SQL 인젝션을 지적하는 리뷰어와 동일한 거부권을 갖습니다. 그 비대칭성은 신뢰를 빠르게 잠식합니다. 먼저 무엇이 진정으로 중요한지 스스로 명확히 하는 것에서 시작하세요:
- 정확성: 이 코드는 해야 할 일을 하고 있습니까? 엣지 케이스가 처리됩니까? 테스트가 커버하지 않는 방식으로 프로덕션에서 실패할 수 있습니까?
- 설계: 이 변경은 기존 아키텍처에 자연스럽게 맞습니까? 불필요한 결합을 도입합니까? 동일한 문제를 해결하는 더 간단한 접근법이 있습니까?
- 가독성: 이것을 작성하지 않은 팀원이 여섯 달 후에 이해할 수 있습니까? 이름이 명확합니까? 흐름이 따라가기 쉽습니까?
- 테스트: 테스트가 의미 있습니까? 해피 패스, 엣지 케이스, 실패 모드를 커버합니까? 테스트 실패가 실제로 유용한 정보를 알려 줍니까?
- 보안: 사용자 입력이 검증됩니까? 데이터 유출, 권한 상승, 또는 인젝션이 발생할 수 있습니까? (그렇다면 차단 요소로 취급하세요.)
리뷰 에너지를 쓰지 말아야 할 것들:
- 린터나 포매터가 자동으로 처리하는 포맷 및 스타일. CI가 잡는다면 여러분이 할 필요가 없습니다. 사람 리뷰 슬롯은 비쌉니다 — 기계가 처리하는 것에 쓰지 마세요.
- 팀 기준이 아닌 개인 취향. "나라면 다르게 이름 붙였을 텐데"는 리뷰 댓글이 아닙니다. "이 이름은 도메인 나머지 부분의 유비쿼터스 언어와 일치하지 않습니다"는 때로는 그럴 수 있습니다.
- PR 댓글 스레드에서의 아키텍처 토론. 방향에 대한 근본적인 이견이 있다면, 그것은 설계 대화지 코드 리뷰가 아닙니다. 다음 PR이 시작되기 전에 별도로 협력적으로 진행하세요.
댓글을 작성하기 전에 물어보세요: "작성자가 이 변경을 정확히 한다면, 코드가 의미 있게 더 좋아질까?" 답이 "조금" 또는 "아마도"라면, 그것이 상대방과 여러분의 시간을 쓸 가치가 있는지 생각해 보세요. 답이 "그렇다, 그리고 이유는"이라면, 쓰세요 — 하지만 친절하게 쓰세요.
친절하게 — 그러면서도 솔직하게 — 댓글 표현하는 방법
코드 리뷰에서 가장 큰 레버는 단어 선택입니다. 동일한 우려가 두 가지 다른 방식으로 전달되면, 읽는 사람에게 완전히 다른 반응을 만들어 냅니다. 실용적인 도구 모음입니다:
- 판결 대신 질문을 하세요. "왜 여기서 X 대신 Y를 선택하셨나요?"는 대화를 초대합니다. "Y를 쓰셨어야 했어요"는 대화를 닫습니다. 질문은 여러분이 갖지 못했던 맥락을 드러낼 수 있습니다 — 그렇지 않더라도, 작성자는 비난받는 느낌 없이 같은 결론에 도달합니다.
- 무엇뿐 아니라 이유를 설명하세요. "이 로직을 서비스로 이동할 수 있을까요?"는 "이 로직을 서비스로 이동할 수 있을까요? 컨트롤러에 두면 독립적으로 테스트하기가 어려워지고, 크론 잡이 동일한 동작이 필요할 경우 중복해야 할 것입니다."보다 약합니다. 이유는 가르치고; 무엇은 그저 지시합니다.
- 비판만이 아닌 제안을 하세요. 문제를 발견하면, 대신 무엇을 할 것인지 보여 주세요 — 또는 최소한 그 모양을. "이것이 맞는지 모르겠지만, 이런 식으로…"는 "이건 맞지 않는 것 같아요"보다 훨씬 유용합니다.
- 좋은 코드는 명시적으로 칭찬하세요. "이 오류 처리가 정말 깔끔합니다 — 이 패턴을 가져갈게요"는 타이핑하는 데 10초가 걸리고 비용이 없습니다. 작성자의 자신감을 굳히고, 패턴을 팀 표준으로 강화하며, 비판적인 댓글이 왔을 때 더 잘 받아들여지게 합니다.
- 솔직할 때 "우리"와 "우리의"를 사용하세요. "우리의 관례는 이것을 레포지토리 근처에 두는 것입니다"는 "잘못된 곳에 두셨어요"보다 덜 정확하지 않으면서 더 부드럽습니다.
가혹한 것과 친절한 것: 같은 요점, 두 가지 방식
| 가혹한 것 (하지만 기술적으로는 맞음) | 친절한 것 — 그러면서도 솔직한 |
|---|---|
| "이건 틀렸어요. null 케이스를 처리해야 해요." | "user가 null이면 예외가 발생할 것입니다 — 여기에 가드를 추가하거나 호출자가 null이 아님을 보장한다고 문서화할 수 있을까요?" |
| "왜 이렇게 하셨나요? 불필요하게 복잡합니다." | "이 부분을 따라가기가 어렵습니다 — 이것을 더 간단하게 표현하는 방법이 있을까요? 맥락을 놓치고 있을 수도 있으니, 이야기 나눠봐도 좋을 것 같아요." |
| "이 함수가 너무 많은 일을 합니다. 쪼개세요." | "이 함수가 유효성 검사와 영속성을 모두 처리하고 있습니다 — 각 책임을 나누면 각각을 독립적으로 테스트하기가 더 쉬워질 것 같습니다. 어떻게 생각하세요?" |
| "이건 분명히 테스트하지 않으셨군요." | "빈 입력 케이스에 대한 테스트를 못 봤습니다 — 의도적인 것인가요, 아니면 후속 티켓을 열까요?" |
"여기는 let이 아니라 const를 쓰세요." |
"nit: 다시 할당되지 않으므로 여기서 const — 의도를 더 명확히 합니다." |
| "이건 보안 구멍입니다." | "blocking: 이 입력은 사용자 제공이며 쿼리에 바로 들어갑니다 — 인젝션 위험이 있습니다. 머지 전에 파라미터화할 수 있을까요?" |
| "잘못된 추상화입니다." | "이 추상화가 올바른 방향으로 끌고 가는지 궁금합니다 — 다음 기능을 더 어렵게 만들 것 같습니다. 빠른 싱크 해볼까요?" |
"친절한" 열이 무엇이 아닌지 주목하세요: 부드럽거나, 모호하거나, 솔직하지 않은 것이 아닙니다. 보안 문제는 여전히 차단 요소로 지적됩니다. null 케이스는 여전히 수정이 필요합니다. 함수는 여전히 분리가 필요합니다. 친절함이란 여기서: 구체적이고, 설명되며, 판사가 판결을 내리는 것이 아닌 한 사람이 다른 사람에게 말하는 방식으로 전달됩니다.
사소한 지적, 제안, 차단 요소 — 라벨을 붙이세요
리뷰 문화에 가장 실용적으로 할 수 있는 일 중 하나는 모든 댓글의 심각도에 라벨을 붙이는 것입니다. 라벨이 없으면, 작성자는 각 댓글이 "머지가 차단됩니다"를 의미하는지 "그냥 생각"인지 추측해야 합니다. 그 추측은 에너지를 소모하고 종종 잘못된 답을 만들어 냅니다.
많은 팀이 사용하는 간단한 관례 (Conventional Comments로 대중화됨):
- nit: 사소한 스타일이나 취향 포인트 — 수정하거나 하지 않거나, 작성자가 결정합니다. "nit: 여기 쉼표가 파일 나머지와 일치합니다."
- suggestion: 코드를 개선할 수 있지만 차단 요소는 아닌 것. "suggestion: 헬퍼로 추출할 수 있습니다 — 이번 PR에는 필요하지 않지만."
- blocking: 이것이 해결될 때까지 PR이 머지되어서는 안 됩니다. 이것은 정확성 버그, 보안 문제, 그리고 팀 기준의 명백한 위반에만 사용하세요.
- question: 진심으로 물어보는 것이지, 변경이 필요하다는 암시가 아닙니다. "question: 이것이 백그라운드 워커에서도 실행되나요, 아니면 웹 프로세스에서만 실행되나요?"
- praise: 명시적이고 진심 어린 긍정적 피드백. 중요합니다. 건너뛰지 마세요.
모든 차단 문제가 해결되면, 댓글과 함께 승인하세요. 이것은 중요한 습관입니다. 이 의미는: "나머지 사소한 것들은 당신이 처리할 것이라 믿습니다; 나에게서 또 한 번의 라운드가 필요하지 않습니다."라는 것입니다. 동료의 차단을 해제하고, 신뢰를 표시하며, 리뷰 루프가 병목이 되는 것을 방지합니다. 그 대안 — 모든 사소한 포인트가 해결될 때까지 승인을 보류하는 것 — 은 리뷰 문화의 느린 독소 중 하나입니다.
모든 차단 항목이 해결되면 승인하고 작성자가 나머지를 결정하도록 하세요. PR을 사소한 것들로 인질로 잡는 것은 사람들에게 리뷰가 협력이 아닌 장애물이라고 가르칩니다. 비차단 포인트에 정말로 신경 쓴다면, 명시적으로 말하세요 — "이것에 신경 쓰지만 당신의 결정입니다" — 작성자가 완전한 정보를 갖도록.
작성자로서: 피드백을 개인적으로 받아들이지 않고 받는 방법
리뷰를 받는 것은 그 자체로 기술이며, 대부분의 엔지니어링 문화 글은 리뷰어에만 집중합니다. 하지만 작성자의 행동도 리뷰 문화를 그만큼 형성합니다.
기본적으로 좋은 의도를 가정하세요. 직설적인 댓글은 거의 항상 빠르게 쓴 바쁜 사람이지, 상처를 주려는 사람이 아닙니다. 댓글에서 어조를 읽기 전에, 중립적이거나 긍정적인 해석이 있는지 물어보세요. 대부분은 그렇습니다.
모든 댓글에 응답하세요. 동의하지 않더라도. 구현한 피드백에 ✅ 또는 "완료", 그리고 거부하는 것에 대한 설명은 루프를 닫고 리뷰어의 시간이 가치 있었음을 보여 줍니다. 침묵은 의도하지 않더라도 수동 공격적으로 읽힙니다.
진정으로 동의하지 않을 때는 명확하고 차분하게 반박하세요. "우려를 이해하지만, 이 결정을 내린 이유가 있습니다: [이유]. 여전히 강하게 느끼신다면 기꺼이 논의하겠습니다." 이것은 모든 결정을 반사적으로 방어하는 것과는 다릅니다. 목표는 진짜 대화를 나누는 것이지, 이기는 것이 아닙니다. 때로는 리뷰어가 맞습니다. 때로는 여러분이 맞습니다. 때로는 옳은 답이 "팀에 가져가 봅시다"입니다.
PR 설명에서 자신의 코드를 과도하게 설명하지 마세요. 코드가 모든 결정을 정당화하기 위해 긴 텍스트 벽이 필요하다면, 그것은 코드, 이름, 또는 인라인 댓글을 개선해야 한다는 신호입니다 — 더 긴 PR 설명을 쓰는 것이 아닙니다. 가장 좋은 PR은 맥락과 의도에 대한 좋은 설명과 함께 자명합니다.
리뷰 속도와 PR 크기 — 엄청난 영향을 가진 두 가지 레버
코드 리뷰의 품질은 리뷰어의 기술과 무관한 두 가지 요소로 강하게 예측됩니다: 얼마나 빨리 리뷰하는가와 PR이 얼마나 큰가입니다.
신속하게 리뷰하세요. 리뷰를 기다리는 pull request는 다음으로 나아가기를 기다리는 사람입니다. 리뷰가 며칠씩 걸릴 때, 작업이 쌓입니다 — 엔지니어는 생산적이기 위해 다음 작업을 열고, 컨텍스트 전환이 곱절로 늘어나며, 리뷰가 돌아올 때쯤 작성자는 무슨 생각을 했는지 잊어버립니다. 좋은 경험 법칙: 태그된 후 몇 시간 내에 PR을 확인하고 ("오늘 끝날 때까지 할게요"라도), 가능하면 영업일 하루 내에 리뷰를 완료하세요.
작은 PR은 훨씬 더 좋은 리뷰를 받습니다. 이것은 잘 문서화되어 있으며 실제로도 명백합니다. 100줄짜리 PR은 모든 줄에 세심한 주의를 받습니다. 1,000줄짜리 PR은 고무 도장이 찍히거나, 훑어보게 되거나, 너무 느리게 리뷰되어 갈등의 원인이 됩니다. PR을 작게 유지하는 규율 — "PR당 하나의 논리적 변경"이 괜찮은 경험 법칙입니다 — 은 다른 어떤 리뷰 위생 개선보다 더 많은 것을 돌려줍니다. 또한 각 PR을 작성하기도 더 쉽게 만드는데, 왜냐하면 하나의 변경이 무엇을 의미하는지 명확하게 생각해야 하기 때문입니다.
| PR 크기 (변경된 줄 수) | 일반적인 리뷰 품질 | 리뷰 시간 |
|---|---|---|
| < 200줄 | 높음 — 리뷰어가 작업 메모리에 담을 수 있음 | 15–45분 |
| 200–500줄 | 중간 — 미묘한 문제에서 피로가 시작됨 | 45–90분 |
| 500–1,000줄 | 감소 — 리뷰어가 훑어보거나 세션을 분리함 | 몇 시간에서 하루 |
| > 1,000줄 | 대부분 형식적 — 중요한 문제가 정기적으로 놓침 | 며칠 (또는 완전히 못 함) |
기능이 진짜로 수천 줄이 필요하다면, 스택된 PR을 고려하세요: 각각 독자적으로 리뷰 가능한, 서로 위에 쌓이는 일련의 작고 독립적인 변경들. 더 많은 PR을 여는 오버헤드는 거의 항상 그만한 가치가 있습니다.
팀 크기에 따른 리뷰 문화의 차이
코드 리뷰에 대한 올바른 접근 방식은 팀이 성장하면서 상당히 달라집니다. 세 명의 엔지니어에게 효과적인 것이 서른 명에서는 종종 무너지고, 기업 규모의 팀은 완전히 다른 도구가 필요합니다.
솔로 또는 초기 스타트업 (1–5명). 이 규모에서는 리뷰가 전혀 없을 수도 있는데, 이것은 위험 부담에 따라 때로는 괜찮고 때로는 치명적입니다. 리뷰를 할 때, 관계는 보통 직설적인 피드백이 잘 전달될 만큼 충분히 강합니다 — 하지만 이것은 또한 누군가 이름 붙이기 전에 나쁜 습관이 고착되는 단계이기도 합니다. 댓글 심각도에 라벨을 붙이는 습관을 일찍 확립하세요; 비용이 없고 나중에 매우 귀중해집니다.
소규모 성장 팀 (5–20명). 이 단계에서 리뷰 문화가 만들어집니다. 팀은 "우리 모두 서로 알아" 약어가 희미해지기 시작할 만큼 충분히 크지만, 몇몇 영향력 있는 목소리가 여전히 규범을 설정할 수 있을 만큼 충분히 작습니다. 친절하고 구체적이며 라벨이 붙은 리뷰를 모델로 보여 주는 시니어 엔지니어 한 명이 몇 달 안에 팀 전체의 문화를 바꿀 것입니다. 이것은 또한 팀 리뷰 가이드 — 한 페이지라도 — 가 성과를 낼 때입니다: 차단 요소가 무엇인지, 사소한 것이 무엇인지, 리뷰가 얼마나 걸려야 하는지.
중간 규모 팀 (20–100명). 리뷰는 이제 서로 거의 모를 수 있는 스쿼드에서 일어납니다. 소규모 팀에서 자연스럽게 일어나는 신뢰 구축 작업은 의도적으로 이루어져야 합니다. 규범이 공유되지 않으면 크로스 팀 리뷰가 주요 마찰 원인이 됩니다. 코드 오너, 리뷰 순환, 경량 리뷰 체크리스트가 도움이 됩니다. 엔지니어링 회고에서 리뷰 품질을 주제로 삼는 것도 마찬가지입니다 — "빠르게 배포했나"뿐만 아니라 "잘 리뷰했나"도.
대규모 또는 기업 팀 (100명 이상). 이 규모에서 리뷰는 품질 기능만큼이나 거버넌스 및 컴플라이언스 기능입니다. 도구가 엄청나게 중요합니다: 자동화된 검사, 필수 리뷰어, 리뷰 SLA, 리뷰 사이클 타임 지표. 사람 리뷰 슬롯은 소중하고 오직 사람만 할 수 있는 것 — 설계 판단, 도메인 지식, 크로스 팀 영향 — 에 예약되어야 합니다. 린터나 정적 분석기가 잡을 수 있는 것은 PR이 열리기 전에 잡혀야 하며, 댓글 스레드에서가 아닙니다.
핵심 요약
- 코드 리뷰는 버그 찾기보다 문화가 먼저입니다. 모든 댓글은 가르치고, 댓글 패턴은 수개월에 걸쳐 심리적 안전감을 구축하거나 침식합니다.
- 중요한 것에 리뷰 에너지를 집중하세요: 정확성, 설계, 가독성, 테스트, 보안. 포맷은 린터에게 맡기세요.
- Kind + Specific이 목표입니다. 이유를 설명하고, 판결 대신 질문을 하며, 좋은 코드는 명시적으로 칭찬하세요.
- 댓글에 라벨을 붙이세요: nit / suggestion / blocking / question / praise. 모호함을 없애고 작성자의 시간을 존중합니다.
- 차단 요소가 해결되면 댓글과 함께 승인하세요. PR을 사소한 것들로 인질 잡지 마세요.
- 작성자로서: 좋은 의도를 가정하고, 모든 댓글에 응답하며, 동의하지 않을 때 차분하게 반박하고, PR 설명에서 과도하게 설명하지 마세요.
- 작은 PR, 빠른 리뷰. 200줄 미만이 최고의 주의를 받습니다. 스택된 PR은 대형 기능을 처리합니다.
- 리뷰 규범은 의도적이어야 합니다 — 특히 팀이 10–20명을 넘어 성장할 때. 적어 두고, 회고에서 다시 검토하세요.
이것이 공감됐다면, 이 시리즈의 다음 글은 코드를 리뷰하는 방법에서 더 넓어져 매일 엔지니어로서 어떻게 나타나는지까지 다룹니다: Kind Engineering.