개념
리뷰는 도구가 아니라 테스트 레벨 하나다
레슨 1~4는 도구가 숫자를 만드는 과정이었다. 마지막 레슨은 사람이고, 이 자리를 "문화"나 "매너"로 두면 아무것도 관리되지 않는다.
코드 리뷰는 실행 없이 결함을 검출하는 정적 테스트다. 테스트라고 부르면 질문이 따라붙는다 — 무엇을 검출 대상으로 삼는가(체크리스트), 검출한 것을 어떻게 기록하는가(결함 유형 분류), 검출력이 올라가는가(지표). 이 레슨은 그 셋을 코드 리뷰에 붙이는 일이다.
리뷰 기법 자체 — 체크리스트 기반 읽기·퍼스펙티브 기반 읽기(PBR)의 정의와 절차 — 는 s2-m58-l02가 요구사항·설계 문서 를 대상으로 이미 다뤘으니 반복하지 않는다. 리뷰 유형과 테스트웨어 리뷰 기준은 s2-m43-l02가 자리다. 여기 대상은 프로덕션 코드 리뷰의 운영 이다.
동적 테스트가 구조적으로 잡기 어려운 것
리뷰가 값을 내는 이유는 "사람이 꼼꼼해서"가 아니다. 동적 테스트에 원리적 사각지대가 있어서 다. 커버리지 90%·뮤테이션 점수 80%인 코드에도 다음이 남는다.
| 결함 유형 | 왜 실행으로 안 잡히나 | 리뷰에서는 어떻게 보이나 |
|---|---|---|
| 경계 누락 | 개발자가 놓친 케이스는 테스트에도 없다 | if (amount > limit) 에 "같을 때는?"을 물으면 드러난다 |
| 오류 처리 부재 | 정상 경로만 실행되면 초록색이다 | catch 가 삼키는지, 재시도 상한이 있는지 보인다 |
| 동시성 가정 | 단일 스레드 테스트는 레이스를 만들지 않는다 | "요청 간 공유되는데 HashMap 인가?"는 읽으면 보인다 |
| 자원 해제 누락 | 짧은 테스트에서는 릭이 증상을 안 낸다 | finally·defer 없는 획득 지점은 눈에 띈다 |
| 요구사항 오해 | 잘못된 기대값을 잘못된 코드가 만족한다 | 도메인 아는 사람이 "계산 기준이 틀렸다"를 짚는다 |
핵심은 첫 줄과 마지막 줄이다. 테스트와 코드를 같은 사람이 같은 이해로 만들면 그 오해는 검증되지 않는다. 리뷰는 다른 머리로 이해 자체를 검사한다.
범용 체크리스트는 왜 실패하는가
인터넷에서 가져온 "코드 리뷰 체크리스트 50항목"은 거의 예외 없이 죽는다. ① 길면 아무도 안 본다 — 40항목을 PR마다 돌리는 팀은 없고, 실제로 쓰이는 길이는 7~12항목이다. ② 우리 결함과 무관하다 — "변수명이 의미를 담는가"는 틀리지 않지만, 우리 장애가 타임존과 외부 API 타임아웃이었다면 체크리스트는 그 둘을 물어야 한다. ③ 도구가 이미 보는 것을 또 본다 — 포맷·미사용 변수·널 가능성은 린터·타입 체커가 잡는다(레슨 4).
그래서 체크리스트의 첫 작업은 추가가 아니라 삭제 다. 도구가 보는 것을 빼고, 남은 자리에 사람만 판정할 수 있는 질문을 넣는다.
우리 결함 이력에서 체크리스트를 뽑는 절차
체크리스트는 창작물이 아니라 데이터의 요약 이다. 다섯 단계로 만든다.
1단계 — 모집단. 최근 6개월의 운영 장애 + 리뷰 이후에 발견된 결함. 리뷰에서 이미 잡힌 것은 뺀다. 원하는 것은 리뷰를 빠져나간 결함 이다.
2단계 — 유형 집계. ODC·IEEE 1044를 참고해 8~12개로 줄인다. 20개를 넘으면 집계가 안 되고, 5개 미만이면 질문으로 바꿀 만큼 구체적이지 않다.
3단계 — 상위 유형만. 파레토를 그리면 보통 상위 34개가 전체의 6070%를 만든다.
4단계 — 유형을 질문으로 바꾼다. 이 변환이 핵심이다. 유형 이름은 체크리스트가 될 수 없고, 리뷰어가 코드를 보며 예/아니오로 답할 형태 여야 한다.
| 집계된 결함 유형 | 건수 | 체크리스트 질문으로 변환 |
|---|---|---|
| 경계값 오류(off-by-one, 등호 누락) | 14 | 비교 연산자마다 "경계에서 같을 때" 동작이 명시돼 있는가 |
| 외부 호출 타임아웃·재시도 누락 | 11 | 네트워크 호출에 타임아웃·재시도 상한이 있는가. 멱등한가 |
| 시간·타임존 처리 | 9 | 날짜 경계 계산에 타임존이 명시됐는가. 서버 로컬 시간을 쓰는가 |
| 예외 삼킴·오류 정보 유실 | 8 | catch 가 원인을 보존하고 상위에 신호를 주는가 |
| 자원 미해제 | 5 | 커넥션·스트림·락이 실패 경로에서도 해제되는가 |
5단계 — 만료. 분기마다 검토해 최근 두 분기 동안 그 질문으로 잡힌 결함이 0건이면 항목을 내린다. 이유는 둘뿐이다 — 팀 습관이 됐거나 도구가 대신 잡게 됐거나. 상한을 12개로 못 박으면 새 항목이 낡은 항목을 밀어낸다.
역할별 분담 — 같은 코드를 네 사람이 다르게 본다
한 PR을 네 사람이 같은 눈으로 읽으면 세 사람 몫이 낭비된다. 퍼스펙티브를 나눈다는 아이디어는 PBR과 같지만, 코드 리뷰에서는 역할마다 접근 가능한 정보와 판정 권한이 다르다.
| 역할 | 무엇을 보는가 | 전형적인 질문 |
|---|---|---|
| 작성자 | 셀프 리뷰. 자기 diff를 남처럼 읽고 위험 지점을 PR 설명에 적는다 | 이 변경의 위험은 어디인가. 어디를 봐 달라고 해야 하나 |
| 동료 개발자 | 정확성·설계·유지보수성. 코드 전체를 읽는 유일한 역할 | 이 추상화가 맞나. 중복인가. 동시 접근에 안전한가 |
| 테스터 / QA | 검증 가능성·경계·오류 처리·관측 가능성·영향 범위 | 이 경계는 테스트되나. 실패하면 어떻게 아나. 회귀 위험은 |
| 도메인 전문가 | 규칙의 정합성. 코드 문법은 안 봐도 된다 | 이 정산 기준이 계약서와 같은가. 이 예외는 존재하나 |
이 넷 앞에 자동 검사(포맷·린트·타입·SAST·커버리지)가 한 겹 더 있다. 운영 규칙 하나: 자동 검사가 빨간 PR은 사람이 읽지 않는다. 기계가 잡을 것을 사람이 먼저 읽으면 가장 비싼 자원을 낭비한다.
나쁜 코멘트와 좋은 코멘트
같은 결함을 지적하는 코멘트도 형태에 따라 결함으로 기록되거나 감정으로 소비된다.
✗ "이 부분 좀 이상한데요?" → 무엇이 어떻게 이상한지 없다
✗ "LGTM 👍" (400줄 결제 로직) → 무엇을 확인했는지 없다
✗ "변수명을 camelCase로" → 린터 룰의 자리다
✓ "amount == limit 일 때 통과인지 거절인지 어느 쪽인가요? 정책
문서는 '한도 이하 허용'인데 여기는 초과 비교입니다. 의도라면
경계 케이스 테스트로 고정해 두죠."
→ 결함 후보 + 근거(문서) + 재발 방지(테스트) 한 세트
✓ "[필수] 이 호출에 타임아웃이 없습니다. 상대가 멈추면 워커 풀이
고갈됩니다(ISSUE-3102와 같은 형태)." → 영향 + 이력 + 심각도
✓ "[질문] 이 캐시가 요청 간 공유되나요? 그렇다면 쓰기 경로에
동기화가 필요합니다." → 단정하지 않고 확인한다[필수] · [제안] · [질문] 세 접두어 만으로 병합 대기가 줄어드는 팀이 많다. 작성자가 "무엇을 고쳐야 병합되는가"를 즉시 알기 때문이다.
리뷰에서 나온 것을 결함으로 기록한다
리뷰 코멘트는 대개 PR과 함께 묻힌다. 병합되면 아무도 다시 보지 않으니 리뷰가 무엇을 잡았는지 데이터가 없고, 그러면 체크리스트를 데이터로 만들 수 없다. [필수] 코멘트에만 라벨 하나를 붙이면 된다.
boundary 경계·등호·off-by-one consistency 부분 실패 후 상태 불일치
error-handling 예외 삼킴·오류 전파 누락 security 권한·입력 검증·비밀값 노출
concurrency 공유 상태·락·원자성 가정 testability 검증 불가·관측 불가
resource 해제 누락·누수 domain-rule 도메인 규칙 오해분기마다 집계하면 셋이 나온다. ① 상위 유형 — 다음 체크리스트의 재료. ② 유형별 검출 단계 — 리뷰에서도 잡히고 운영에서도 터지는 유형은 질문이 모호하다는 신호다. ③ 유형이 몰린 모듈 — 한 유형이 한 모듈에 집중되면 리팩터링이 답이다.
이게 이 레슨의 순환이다. 결함 이력 → 체크리스트 → 리뷰 → 분류된 결함 → 갱신된 체크리스트. 두세 바퀴 돌면 체크리스트가 우리 팀의 약점 지도가 된다.
리뷰 지표 — 무엇을 세고 무엇을 세면 안 되는가
리뷰 측정은 세기 쉬운 것을 세다가 망한다.
| 세도 되는 것 | 왜 |
|---|---|
| 유형별 유출 결함 수(리뷰 이후 단계) | 리뷰의 목적 자체를 본다 |
| 리뷰 커버리지 — 리뷰를 거친 변경의 비율 | 우회 경로(핫픽스 직접 푸시)를 드러낸다 |
| 첫 리뷰까지의 대기 시간 | 병목인지 본다. 개인 평가가 아닌 흐름 지표다 |
| PR 크기 분포 | 큰 PR이 리뷰 형식화의 가장 큰 원인이다 |
| 체크리스트 항목별 검출 건수 | 어떤 항목이 일하는지 본다. 만료 근거 |
| 목표로 삼으면 안 되는 것 | 무슨 일이 벌어지나 |
|---|---|
| 리뷰어당 코멘트 수 | 오타·취향 지적이 쏟아지고 경계 질문은 그대로다 |
| 리뷰 속도(시간당 PR 수) | LGTM 이 늘어난다. 지표는 좋아지고 검출력은 0이 된다 |
| 개인별 결함 지적 순위·승인율 | 작성자는 PR을 쪼개 숨기고, 리뷰어는 쉬운 것만 찾는다 |
원칙 한 줄: 리뷰 지표는 흐름과 결과에 붙이고 사람에게 붙이지 않는다. 개인에게 붙는 순간 지표는 측정 대상이 아니라 게임 대상이 되고, 게임하기 가장 쉬운 변수가 하필 코멘트 수와 속도다.
QA가 코드를 다 읽지 않고도 기여하는 법
여기가 이 레슨의 실용적 핵심이다. QA가 코드 리뷰에서 빠지는 이유는 거의 언제나 같다 — "코드를 개발자만큼 못 읽으니 낄 자리가 없다." 틀린 전제다. 코드 전체를 읽는 역할은 동료 개발자 몫이고, QA의 네 개입 지점은 전체 읽기를 요구하지 않는다.
① 테스트 코드를 리뷰한다. 테스트 코드는 QA의 전문 영역이고 볼 것도 정해져 있다 — 어설션이 실제 결과를 검증하는가(assertNotNull 만 있으면 뮤턴트가 다 살아남는다, 레슨 3), 이름이 조건과 기대를 담는가, 경계 케이스가 있는가, 공유 상태·순서 의존·sleep 이 있는가, 실패 메시지가 원인을 말하는가. diff의 테스트 파일만 봐도 된다.
② 관측 가능성을 요구한다. 릴리스 후 "무슨 일이 있었는지 알 수 없는" 상태는 리뷰에서 막을 수 있는 결함이다.
- 이 실패 경로에 로그가 있습니까. 식별자(주문 ID·사용자 ID)가 담깁니까
- 상관 ID(correlation ID)가 하위 서비스까지 전달됩니까
- 이 분기 중 어느 쪽으로 갔는지 운영에서 구분할 수 있습니까
- 이 재시도가 몇 번 일어났는지 세는 지표가 있습니까
- 로그에 비밀값·개인정보가 들어가지 않습니까관측 가능성은 테스트 가능성의 운영판이다. 못 보는 것은 검증할 수 없고, 리뷰가 그것을 요구할 마지막 시점이다.
③ 경계 조건을 질문한다. 코드 전체를 이해하지 못해도 비교 연산자와 조건식은 찾을 수 있다. >·>=·!=·&&·||, 숫자 리터럴, 시간 계산, 컬렉션 인덱스. 각각에 "경계에서 어떻게 되나", "빈 값·0·음수·최댓값이면", "타임존이 다르면"을 묻는다. 대답이 코드에 없으면 결함 후보이고, 있으면 그게 테스트 케이스다.
④ 변경 영향 범위를 확인한다. diff가 건드린 함수가 어디서 호출되는가 는 IDE의 호출자 찾기나 grep 으로 몇 분이면 나온다. 이것만으로 회귀 범위를 정하고 "A·B·C 화면에 영향이 있는데 B의 회귀 케이스가 없다"를 남길 수 있다.
정리하면 QA의 리뷰 산출물은 코드 수정 요구가 아니라 세 목록 이다 — 답을 못 얻은 경계 질문(=결함 후보), 추가할 테스트 케이스, 회귀 범위. 코드 전체를 읽지 않아도 만들 수 있고, 리뷰 질문이 그대로 테스트 케이스가 되는 것 이 QA 참여의 가장 큰 배당이다.
실무에서 왜 필요한가
리뷰는 대부분의 조직에서 이미 강제돼 있다. 브랜치 보호 규칙에 승인 1건이 걸려 있고 모든 PR이 그 관문을 지난다. 그런데 그 관문이 무엇을 잡고 있는지 아는 팀은 드물다.
그래서 두 실패가 반복된다. 형식화 — 승인율은 100%인데 유출 결함 유형이 6개월째 그대로인 상태. 과부하 — 리뷰가 병목이 되어 PR이 3일씩 대기하다 팀이 승인 요건을 없애는 상태. 체크리스트도 분류도 지표도 없으면 둘 다 감지할 수 없다.
QA에게는 이 빈자리가 기회다. 리뷰를 계측 가능한 테스트 활동으로 만드는 역할은 코드를 가장 잘 읽는 사람이 아니라 결함 데이터를 가장 잘 읽는 사람에게 있다.
채용시장에서의 위치
국내 공고에서는 "코드 리뷰 문화 정착", "결함 분석 및 재발 방지"로 표현되고 시니어 QA·QA 리드 요건에 자주 들어간다. 약한 답은 "코드 리뷰에 참여했습니다"이고, 강한 답은 순환을 설명한다 — "운영 장애 6개월치를 8개 유형으로 집계해 상위 4개를 9항목 체크리스트로 만들고, 리뷰 코멘트에 유형 라벨을 붙여 분기마다 갱신했다. 타임존 유출 결함이 9건에서 1건으로 줄어 항목 2개를 만료시켰다." ISTQB CTAL-TTA에서도 정적 테스트와 리뷰 체크리스트가 정면 주제다.