배경
- 대상: 프론트엔드 저장소 1곳
- 구성: AI 코드리뷰 두 겹
- PR에 자동으로 달리는 Gemini 리뷰 봇
- 작업 중간에 명시적으로 태우는 code-review 패스
- 목표: “지적을 받는 것”이 아니라 지적사항을 실제 커밋으로 환류시키기
-
기간: 약 두 달
-
두 달 운영 결과 — 봇이 잘 잡는 클래스와 전혀 못 잡는 클래스가 뚜렷하게 갈림
- 커밋 메시지에
Co-Authored-By서명과 모델 세대를 남겨 두었다
— Sonnet 4.6 → Opus 4.8 → Opus 4.8 1M → Opus 5
봇이 잡은 것
- 실제 커밋으로 이어진 지적을 유형별로 정리
| 유형 | 지적 내용 |
|---|---|
| 관용구 위반 | 차트 option 객체를 매 렌더 재생성 (useMemo 누락) |
| 누락된 cleanup | 메모리 누수 3건 추가 발견 |
| 레이스 컨디션 | 민감도 분석 로딩 순서 |
| 가드 비대칭 | heatmap의 x축은 가드가 있는데 y축만 있음 |
| 중복 방어 |
escapeHtml이 이미 정규화하는데 바깥에 String() 래퍼 |
| 부작용 혼입 |
setGridRows 업데이터 함수 안에서 다른 setState 호출 |
| 도달 불가능한 분기 |
crumbOf의 구분선 처리 |
- 이 중 몇 개는 부연 필요
업데이터 안에 부작용이 섞여 있었다
- 형태:
setGridRows((prev) => { ... setDeleteIdList(...); return next; }) - 원칙: React 업데이터 함수는 순수해야 함
- 위반: 안에서 다른 상태를 갱신
-
결과: Strict Mode·동시성 렌더에서 업데이터 2회 호출 →
deleteIdList에 항목 중복 - 수정: 부작용을 이벤트 핸들러로 끌어올림
- 현재 스코프의
gridRows를 직접 참조해 계산 -
두 상태를 순차 갱신
- 상태: 버그 신고 이력 없음. 다만 조건이 맞으면 터질 자리
가드의 비대칭
- heatmap의
yCats[y]→ 존재 확인 가드 있음 -
MODULES[x]→ 가드 없음 -
봇 지적: “왜 한쪽만 있냐”
- 특징: 사람이 diff로 볼 때는 잘 안 보이나, 패턴 매칭에는 잘 걸림
상태 미러링
- 기존:
useState+useEffect로location.hash를activeId에 복사 - 문제: desync 창 발생 — hash는 바뀌었는데 state는 아직 안 바뀐 순간
- 조치: 렌더 시점에 hash에서 직접 파생 → 미러링과 effect 동시 제거
봇이 못 잡은 것
가장 큰 성능 문제는 봇이 하나도 못 잡았다.
- 사례: PDF 다운로드가 7초 걸리던 문제
- 코드만 보면 이상한 구석 없음 — react-pdf로 PDF를 만드는 평범한 코드
- 실제 병목: 한글 폰트의 텍스트 layout
-
발견 경로: chrome-devtools로 직접 계측, 20여 종의 조합 실험
- 성격: 정적 분석으로 도달 불가능한 결론
봇이 잘 잡는 것과 못 잡는 것
- 두 달 운영 후 정리된 경계
| 잘 잡는 클래스 | 못 잡는 클래스 |
|---|---|
| 관용구 위반 (useMemo·useCallback 누락) | 성능 병목 (실측이 필요한 것) |
| 누락된 cleanup (dispose·revoke·clearTimeout) | 도메인 정합성 (이 계산식이 업무적으로 맞는가) |
| exhaustive check·가드 대칭성 | 아키텍처 수준의 중복 (V1/V2 이중 스택 같은 것) |
| 도달 불가능한 분기 | 사용자에게 실제로 어떻게 보이는가 |
- 공통점 — 잘 잡는 건 파일 하나 안에서 판정 가능한 것
- 못 잡는 건 실행해봐야 알거나 도메인 지식이 필요한 것
남는 교훈
- AI 리뷰 봇 도입 효과 — 지적사항 수 증가
- 왼쪽 열의 성격: 사람 리뷰어가 꾸준히 잡기 어려운 종류 (지루하고, 놓쳐도 당장 티가 안 남)
- 기계가 이를 대신 보는 것은 실질적 이득
다만 봇을 붙였다고 리뷰가 끝났다고 착각하면 위험하다.
- 오른쪽 열 — 여전히 사람 몫
- 그중 성능 문제 — 계측 없이는 판정 불가
봇의 통과 여부를 “문제 없음”의 근거로 쓰지 않는 것 — 그게 두 달 동안 얻은 가장 실용적인 결론이다.