본문으로 건너뛰기
Community툴 리뷰

Claude Code로 레거시 마이그레이션 PR 40개를 자동으로 돌린 회고

윤기태

@coder_yuki

무엇을 어떻게 돌렸나

6년 된 Node 백엔드, 파일 약 600개. 세 마이그레이션을 동시에 걸었습니다. moment→dayjs, winston 로거→pino, CommonJS require→ESM. 거대 PR 하나 대신 Claude Code에 "한 모듈만 바꾸고 테스트가 통과하면 PR을 열어라"를 반복시켰습니다. 43개를 열어 38개를 머지하고 5개를 폐기했습니다. 직접 했으면 3주 잡던 작업을 실 리뷰 시간 나흘로 줄였습니다.

맡길 수 있던 것과 없던 것

자동으로 굴러간 38개 중 31개는 두 유형이었습니다. 첫째는 기계적 치환입니다. moment().format()dayjs().format()으로 바꾸는 1:1 대응은 diff가 좁고 의미가 안 바뀝니다. 둘째는 테스트가 계약을 고정한 모듈입니다. 유닛 테스트가 초록이면 믿고 머지했습니다.

롤백하거나 수정한 7개는 전부 사람이 봤어야 하는 셋이었습니다.

  • 암묵 계약: moment는 관대하게 파싱하지만 dayjs는 플러그인 없이는 엄격합니다. dayjs('2024-01-05 09:00')의 타임존 해석이 갈려 정산 배치가 9시간 밀렸습니다. 테스트엔 고정 문자열만 있어 안 잡혔습니다.
  • 부수효과: winston은 info(msg, meta), pino는 info(obj, msg)로 인자 순서가 반대입니다. 로그 구조가 조용히 뒤집혀도 테스트는 통과합니다. 배포 후 대시보드가 비어서야 알았습니다.
  • 마이그 순서: ESM 전환에서 barrel index.ts가 순환 참조를 만들어, A를 먼저 바꾸면 B가 런타임에서만 터졌습니다. 정적 빌드는 초록이었습니다.

안전하게 굴린 게이트 세 개

  1. 작은 단위: PR당 파일 하나에서 한 폴더까지로 범위를 묶었습니다.
  2. 테스트 선통과: CI가 초록이 아니면 PR 자체를 안 엽니다.
  3. diff 상한: PR당 ±400줄, 넘으면 쪼개게 지시했습니다. 리뷰어 피로가 사고를 만듭니다.

when-NOT: 테스트 없는 코드베이스

위 31개를 믿은 근거는 전부 "테스트 초록"입니다. 커버리지가 없으면 그 신호가 거짓이 되고, 로거 인자 순서 같은 부수효과는 사람 눈에도 잘 안 보입니다. 커버리지가 40% 아래면 자동 PR보다 characterization test부터 깔아야 합니다. 안 그러면 40개의 초록 PR이 40개의 잠복 버그가 됩니다.

이 글에 대한 Q&A

이 글에 질문하기

이 글에서 궁금한 점이 있다면 먼저 질문을 남겨보세요.

댓글

첫 댓글을 남겨보세요.