코드 리뷰의 주된 목적은 유지보수하기 어려운 코드를 찾는 것
(mathstodon.xyz)- 코드 리뷰는 버그를 잡아내거나 무결성을 보장하는 절차보다, 나중에 유지보수하기 어려운 코드를 미리 드러내는 과정에 가까움
- 리뷰어가 코드를 읽어도 이해하기 어렵다면, 같은 문제를 미래의 유지보수자도 겪을 가능성이 높음
- 수정은 원 작성자가 맥락을 기억하고 있는 지금 하는 편이 낫고, 코드 검사만으로 버그를 안정적으로 찾겠다는 기대는 현실적이지 않음
- “버그를 찾아라”보다 “이해해 보고, 이해 안 되는 부분을 표시하라”가 리뷰어에게 더 실행 가능한 과제임
- 좋은 리뷰는 모든 것을 완벽히 증명하는 일이 아니라, 이해되지 않는 지점에 메모를 남기고 개선을 요구하는 데서 시작함
코드 리뷰의 초점 바꾸기
- 코드 리뷰의 핵심 목적은 리뷰어가 버그를 찾는 것이 아니며, 코드에 버그가 없다고 보증하는 것도 아님
- 코드만 훑어 일반적으로 버그를 찾아낼 수 있다는 기대는 실무적으로 약함
- 그래서 리뷰의 중심은 “맞는 코드인가”보다 “다른 사람이 나중에 읽고 고칠 수 있는가”에 놓임
이해하기 어려운 코드는 유지보수 위험 신호
- 리뷰어는 코드가 무엇을 하고, 어떻게 동작하는지 이해하려고 읽음
- 이해되지 않는 부분은 미래의 유지보수자가 막힐 가능성이 있는 위험 신호가 됨
- 이런 코드는 원 작성자가 아직 맥락을 기억하고 있을 때 바로 고치는 편이 낫음
버그 찾기보다 실행 가능한 리뷰 과제
- “이 코드에서 버그를 찾아보라”는 요청은 성공 여부를 판단하기 어려운 작업임
- 버그를 몇 개 찾아도 더 숨어 있는 버그를 놓쳤을 수 있어, 리뷰어 입장에서는 실패만 명확해지기 쉬움
- 반대로 “이 코드를 이해해 보고, 이해할 수 없으면 지적하라”는 요청은 기준이 더 분명함
- 모든 것을 완벽히 이해할 필요는 없음
- 이해하지 못한 부분을 기록하면 됨
- 전체를 이해하려고 시도하고, 막힌 지점에 메모를 남기면 리뷰의 역할을 수행한 것임
실무에서의 리뷰 기준
- 리뷰어가 이해하지 못한 코드는 그 자체로 수정 대상이 될 수 있음
- 리뷰 코멘트는 버그 보고뿐 아니라 설명 부족, 구조 문제, 읽기 어려운 흐름을 드러내는 역할을 함
- 이 기준에서는 코드의 정당성을 증명하는 일보다, 이후 팀원이 읽고 다룰 수 있는 상태로 만드는 일이 중요함
버그 발견은 부수 효과
- 코드 리뷰가 버그를 전혀 찾지 못한다는 뜻은 아님
- 버그는 리뷰 중 발견될 수 있지만, 모든 버그나 대부분의 버그를 찾는 방법으로 기대하기는 어려움
- 더 현실적인 성공 조건은 이해 가능성을 점검하고, 유지보수하기 어려운 부분을 원 작성자와 함께 바로 개선하는 것임
댓글과 토론
Hacker News 의견들
-
코드 리뷰에는 단일한 목적만 있는 게 아님. 유지보수하기 어려운 코드를 찾는 것도 중요하지만 유일한 목적도, 어쩌면 가장 중요한 목적도 아닐 수 있음
개발자나 AI가 이상한 방향으로 가더라도 악성 코드 병합을 어렵게 하는 안전장치가 되고, 문제에 너무 가까이 있지 않은 사람이 더 나은 방법이나 놓친 문제를 볼 수 있음
시스템의 다른 부분을 더 잘 아는 사람이 상호작용 문제를 잡아낼 수도 있고, 최소 한 명은 해당 코드에 익숙해지게 만들며, 작성자와 리뷰어 모두에게 학습 기회가 됨
특히 경력 차이가 있을 때 중요해서, 새 직원을 멘토링할 때 내 모든 PR에 리뷰어로 추가해 내가 일하는 방식을 보게 하고, 그들의 PR도 리뷰해 방향을 잡아줌. 가끔은 나도 그들에게 배움
버그를 잡는 것도 맞지만 주된 메커니즘이어서는 안 되고, 자동화 테스트로 잡기 어려운 보안·성능 버그에는 특히 중요함- 오래된 근거 하나를 더 들면, 사람들은 자기 코드가 리뷰되고 그 코드로 제출자의 역량과 조직 적합성에 대한 장기 인상이 형성된다는 걸 알 때 코드를 다르게 작성함
- 3번과 비슷하게, 해당 하위 도메인에 더 익숙한 사람이 기존 코드와 맞지 않는 부분이나 문제가 될 만한 부분을 잡아줄 수 있음
- “단일 목적”을 코드를 이해하고 이해되지 않는 부분에 문제를 제기하라는 뜻으로 읽었음. 이해하고 나면 잘못됐거나 어리석거나 안전하지 않은 부분을 짚을 수 있다는 의미라면 납득됨
특히 모듈화와 분해에서 그렇고, 거대한 PR 전체를 이해하고 나면 머릿속에 모델이 생겨서 유지보수 가능할지, 언젠가 완전한 악몽이 될지, 아니면 그 중간인지 보이기 시작함
-
코드 리뷰에서 어쩌면 가장 중요한 부분은 지식 이전이라고 봄
우리 작은 팀은 급한 경우가 아니면 병합 전에 전체 팀이 PR에 승인 표시를 하고, 덕분에 팀원 모두가 현재 코드베이스 상태를 대략 알고 있음. 이전에 더 사일로화된 회사에서 겪었던 “내가 의존하던 시스템 전체가 사라졌다” 같은 기습을 피할 수 있음
또한 동작 방식에 대해 질문하고 이해를 키우는 장이 됨. 잘 돌아가는 팀이라면 모든 개발자가 직접 만지지 않는 부분까지 포함해 전체 시스템을 어느 정도 이해해야 함
또 중요한 기능은 조직 지식 점검임. 최근 테이블을 조금 바꿨는데, 동료가 내가 고려하지 않은 마이크로서비스가 그 테이블에 쓰고 있어서 깨질 거라고 알려줬음. 그 마이크로서비스가 존재하는지도, 그 테이블에 접근하는지도 몰랐지만, 그 점검 덕분에 더 큰 문제와 데이터 정리 상황을 막을 수 있었음- “작은 팀 전체가 병합 전 PR에 승인 표시”는 느리게 움직이는 작은 코드베이스에서는 좋아 보이지만, 큰 팀이나 빠른 코드베이스에 강제하면 코드를 대충 훑고 승인 버튼을 누르는 형식적 의식이 되기 쉬움
끝에는 모두 자기 일이 바쁘고 중요한 PR을 막는 사람이 되고 싶지 않아 그냥 승인만 누르면서, 실제로는 아무도 코드를 리뷰하지 않는 상태가 됐음 - 팀 규모가 얼마나 되는지 궁금함. 아마 엔지니어 다섯 명을 넘으면 그런 방식은 확장되지 않을 것 같음
“내가 의존하던 시스템 전체가 사라졌다” 같은 문제는 그 시스템에 의존하는 사람이 그 자리에 없어도 잡을 수 있는 자동화 테스트가 매우 중요하다고 봄
모든 것에 대한 공유 소유권도 강하게 지지함. 사람들이 코드베이스의 특정 부분, 특히 본인이 만든 컴포넌트를 사실상 소유하게 되는 건 자연스럽지만, 사일로와 낮은 버스 팩터로 이어짐. 한 사람이 한 시스템을 소유하고, 그 시스템이 또 다른 한 컴포넌트에 의존하는 구조가 되어서는 안 됨 - 동료가 리뷰에 없었다면 그 깨지는 변경이 프로덕션으로 나가는 걸 무엇이 막았을지 궁금함. 코드 리뷰가 중요하다면 테스트는 어디에 놓이는가
- 어차피 바로 병합할 코드라도 PR을 만들고 다른 개발자를 태그할 때가 있음. 무엇이 왜 병합됐는지 보기 쉬운 경로를 제공해서 사람들이 코드베이스 안의 내용을 놓치지 않게 하려는 목적임
- 사소하지 않은 변경이나 정리 작업에는 항상 두 번째 시선이 좋음. 하지만 “모두가 모든 것을 읽는다”는 방식은 큰 N으로 확장할 수 없음
읽을 것이 너무 많아지면 아무도 따라갈 수 없기 때문에, 위임하고 문서를 만들고 개요 세션을 여는 것임
- “작은 팀 전체가 병합 전 PR에 승인 표시”는 느리게 움직이는 작은 코드베이스에서는 좋아 보이지만, 큰 팀이나 빠른 코드베이스에 강제하면 코드를 대충 훑고 승인 버튼을 누르는 형식적 의식이 되기 쉬움
-
코드 리뷰는 작성자가 소유하던 코드가 팀이나 프로젝트의 소유로 넘어가는 관문이라고 보는 게 가장 좋다고 늘 생각해왔음
내가 리뷰하는 코드는 당신의 코드가 아니라 곧 우리의 코드가 될 코드임. 당연히 유지보수성은 그 안에서 큰 요소임- 정말 부럽고 사치스러운 환경임
우리 팀은 AI를 쓰기 시작해서, 나는 단순한 방식으로 바꿨음. 코멘트는 남기지 않고 “이게 미친 수준인가, 아니면 통과 가능한가”만 이진으로 승인 판단함
내 시간과 정신 건강을 아끼는 중임
- 정말 부럽고 사치스러운 환경임
-
이렇게 하면 리뷰어와 작성자가 더 게을러질 뿐임
코드 리뷰의 목적은 다면적임. 유지보수하기 어려운가, 버그가 있을 수 있는가, 더 단순하고 깔끔하게 할 수 있는가, 프로젝트 코드 스타일에 맞는가, 다른 사람도 코드를 이해하게 하는가, 주니어 팀원을 온보딩하는가, 설계 결정을 sanity check하는가 모두 해당됨
이런 가벼운 글은 대체로 게으른 코드 리뷰어가 스스로를 정당화하는 데 더 가까움- 리뷰에서 봐야 할 체크리스트가 따로 있음
이슈나 PR 설명대로 기능적으로 목표를 달성하는가, 남은 디버그 출력이나 비공개 API 키 같은 불필요한 코드가 있는가, 메모리 누수·처리되지 않은 엣지 케이스·보안 결함·낡은 API 호출 같은 명백한 결함이 있는가를 봐야 함
더 이해하기 쉽게 만들 수 있는지, 추상화를 추가하거나 제거할지, 변수·메서드 이름이 나은지, 함수형 스타일을 더 쓰거나 덜 쓰는 게 좋은지도 봐야 함
코드베이스나 스타일 가이드와 일관적인지, 리스트 대신 해시 집합을 쓰거나 지연 평가를 적용하는 등 명백한 성능 개선이 있는지, 테스트가 충분한지도 확인해야 함
이해할 수 없는 코드라면 통과하면 안 된다는 주장에도 완전히 동의하진 않음. 어떤 코드는 그냥 이해하기 정말 어렵고, 목표는 기능적으로 올바르면서 가능한 한 이해하기 쉽게 만드는 것임 - 업계는 “작성자를 탓하기”에서 “프로세스와 팀을 탓하기”로 넘어가려고 열심히 노력해왔음
그런데 이 글은 그냥 미끼에 가깝고, “사람들은 저녁 식사가 음식을 먹는 것이라고 생각하지만 사실 먹는 게 아니라 가족과 친구와 연결되는 것이다”라고 말하는 것과 비슷함. HN에서 잘 먹히는 특정한 종류의 허술한 환원주의 논리임 - AI 때문에 코드를 작성하고 배포하는 속도가 빨라진 지금은 강조점이 리뷰로 옮겨가야 함. 코드가 실제로 제대로 실행되는지, 우리의 모든 가정이 맞는지, 의도치 않은 부작용은 없는지 확인해야 함
리뷰와 디버깅이 코드 작성·생산보다 훨씬 더 시간이 많이 든다고 느꼈고, 그냥 “작동하길 기도하기”는 결코 좋게 끝나지 않음
- 리뷰에서 봐야 할 체크리스트가 따로 있음
-
“코드를 살펴봐서는 일반적으로 버그를 찾을 수 없다”는 말은 전혀 맞지 않음. 추상화 수준마다 충분히 찾을 수 있고, 그런 걸 코드 냄새라고 부름
닫히지 않은 파일 디스크립터, await하지 않은 코루틴, 오류를 기록하지 않고 어떤 값으로 되돌리는 거대한 try/catch 블록, 잘못된 타입 캐스팅 등이 모두 해당됨
일반 원칙으로, 타입 검사기·컴파일러·런타임을 단지 통과시켜야 할 단계로 보면 안 됨. 이 단계들과 함께 일하고, 그것들이 가치 있는 도구임을 인정해야 하며, 거슬러 일하면 안 됨- 무슨 말을 하는지 모르겠음. 실행하지 않고 코드 리뷰만으로 버그를 잡아본 적도 있고, 반대로 내 코드에서 다른 사람이 그렇게 해준 적도 있으며, 다른 사람들 리뷰에서도 그런 장면을 봤음
“일반적으로”를 어떻게든 기술적으로 참이 되게 정의할 수는 있겠지만, 그러면 별 의미가 없어짐
- 무슨 말을 하는지 모르겠음. 실행하지 않고 코드 리뷰만으로 버그를 잡아본 적도 있고, 반대로 내 코드에서 다른 사람이 그렇게 해준 적도 있으며, 다른 사람들 리뷰에서도 그런 장면을 봤음
-
코드 리뷰에 대해 넓은 주장을 하려면 어떤 종류의 코드 리뷰를 말하는지 정의하는 게 중요함
지금은 GitHub식 비동기 PR 리뷰와 인라인 코멘트가 표준이지만, 리뷰가 그것뿐인 건 아님. 예전에는 대면 리뷰가 학위논문 심사나 학회 발표에 가까운 프로세스도 있었음
코드 리뷰가 유용한 품질 실천이라는 문헌, 사실 유용한 몇 안 되는 품질 실천이라는 문헌은 대체로 지금보다 훨씬 구조화된 리뷰 프로세스에서 나온 것임
개인적으로 LLM 이전의 GitHub식 PR 리뷰는 프로세스가 괜찮다고 느끼게 하거나 거버넌스 체크박스를 채우기 위한 것이었고, LLM 시대에는 비용 대비 효과가 훨씬 나빠져 사라질 것 같음- 동기식 리뷰는 지금도 가능함. 초창기 매니저 중 한 명은 “표준” 코드 리뷰가 한 번 넘게 오가면, 거의 항상 직접 만나거나 한 명이라도 원격이면 Zoom으로 정리한 뒤 합의 내용을 코멘트로 남기는 편이 낫다고 가르쳐줬음
억지 기술 비유를 들자면, 비동기 텍스트 커뮤니케이션은 성공적으로 인코딩할 수 있는 정보 면에서 말보다 손실이 크고 처리량도 낮음. 그래서 많은 정보를 교환해야 할 때는 동기화 비용을 치를 가치가 있음 - 첫 직장 중 하나에서는 변경 패키지를 출력해서 리뷰하고 서명해야 했음. 최종본을 파일 캐비닛에 보관하는 담당자도 있었음
전통적인 공학에 더 가까웠고, 모두가 소프트웨어를 더 영구적인 것으로 생각해야 했음
- 동기식 리뷰는 지금도 가능함. 초창기 매니저 중 한 명은 “표준” 코드 리뷰가 한 번 넘게 오가면, 거의 항상 직접 만나거나 한 명이라도 원격이면 Zoom으로 정리한 뒤 합의 내용을 코멘트로 남기는 편이 낫다고 가르쳐줬음
-
유지보수성을 보장하는 것이 코드 리뷰의 이점 중 하나인 건 맞지만, 그것이 유일한 목적이라고 말하는 건 꽤 과감한 주장임
코드 리뷰는 팀이 코드 변경을 파악하고 전체 코드베이스에 대한 공동 책임을 나누게 해주는 도구이기도 함 -
코드 리뷰는 단일한 것이 아님. 지식 공유, 책임 세탁, 코드 품질, 규제 준수 등 여러 이유가 있고, 늘 그렇듯 어떤 목적을 갖는지는 사용 맥락에 따라 달라짐
- 동료 리뷰의 이유를 대부분의 사람이 이해하지 못한다고 말하는 건 꽤 무지해 보임. 단일 목적만 있다고 믿는 것 자체가 다른 팀이나 사람들과 일해본 경험이 부족하다는 신호처럼 보임
-
작성자가 수학자라면 “코드를 살펴봐서는 일반적으로 버그를 찾을 수 없다”는 말은 버그를 찾는 게 완전히 불가능하다는 뜻이 아닐 것임
모든 버그를 찾거나 특정 버그를 찾는 것이 가능하지 않다는 뜻에 가까움- 대학 수학 강의 경험에 비춰보면, 수학자들이 다른 인간에게 소통을 정말 못할 때가 많음. 그래서 본인이 한 말과 거의 모두가 읽는 방식이 다르다고 생각하는 이유는 설명됨
- 그 의미라면 맞음
유지보수성 논점과 연결해 덧붙이면, 코드를 가능한 한 단순하게 만들어서 리뷰로 디버깅 가능할 확률을 높이는 것도 리뷰의 목표임. 절대적인 의미에서 버그를 막지는 못하지만, 확률은 끌어올림 - 수학자인 작성자가 자기 자연어 한정사의 의미를 이해하지 못한 듯함. “코드를 살펴봐서는 일반적으로 버그를 찾을 수 없다”는 “코드를 살펴봐서는 일반적으로 어떤 버그도 찾을 수 없다”는 뜻이지, “모든 버그를 찾을 수 없다”는 뜻이 아님
첫 해석은 관련은 있지만 틀렸고, 두 번째 해석은 참이지만 관련이 없음
아마 작성자는 “주어진 버그를 코드를 살펴봐서 일반적으로 찾을 수 없다”, 즉 “모든 버그 B에 대해 B를 찾을 수 있는 것은 아니다”라고 말하려 한 것 같지만, 이것도 참이면서 핵심과는 거리가 있음
-
PR 제안을 자주 거절하는 사람과, 제안을 받아들이는 사람을 함께 일해봤음
제안을 받아들이는 사람은 어느 정도 소유권을 나와 공유하려는 건지 생각하게 됨. 둘 다 코드를 유지보수하고 이해하며 같은 방향을 보고 있다는 느낌이 듦
반대로 PR 제안을 거절하는 사람의 PR에는 참여 의지가 줄어듦. 어차피 거절될 거라면 왜 시간을 들여 꼼꼼히 리뷰하겠나- 우리 팀은 코멘트 앞에 대체로
thought,change,nit,fix,chat같은 접두어를 붙임
예를 들어thought는 “나중에 foo가 더 흔해질 수도 있으니 그때 리팩터링하자”,change는 “이건 새는 추상화라 bar처럼 모델링했으면 한다”,nit는 “이름이 조금 직관적이지 않으니 Baz나 Boo를 고려하자”,fix는 “이 단위 테스트가 잘못된 필드를 검증한다”,chat은 “앞으로 이 범주 해법의 모양을 정할 큰 결정이니 먼저 팀과 논의하자” 같은 식임
어떤 접두어는 수정 전까지 PR을 멈추게 하고, 어떤 것은 받아들이거나 말거나인 코멘트라는 뜻임. 작성자에게 무엇이 “같은 이해에 도달해야 하는 것”이고 무엇이 “선호 표현” 또는 “관찰”인지 명확해짐
단,nit를 남겼는데 상대가 동의하지 않고 무시해도 기분 나빠하지 말아야 함. 강하게 느꼈다면 그건nit가 아니었어야 함 - 중요하다고 생각한다면 차단성 제안을 남기고 대화를 강제해야 함.
- 우리 팀은 코멘트 앞에 대체로