3-7. 테스트와 코드 품질 25.12.28 ~ 25.12.30

속도전의 대가

10일 동안 미친 듯이 기능을 쌓아 올렸더니, 코드 품질이 걱정되기 시작했다. AI한테 빠르게 구현을 시키다 보면 동작은 하는데 테스트가 없고, 에러 핸들링이 부실하고, 중복 코드가 쌓인다.

12월 28일부터 30일까지는 기능 개발을 잠시 멈추고, 테스트 작성과 코드 품질 개선에 집중했다.

WebSocket 이벤트 자동 전송 버그

12월 28일에 잡은 버그 하나(PR #41). 클라이언트가 IndexedDB에 쌓아둔 CDP 이벤트를, WebSocket이 연결되면 자동으로 전송해야 하는데, 이게 제대로 안 되고 있었다.

문제는 WebSocket onopen 이벤트 타이밍이었다. IndexedDB에서 이벤트를 읽어오는 건 비동기인데, WebSocket 연결이 그 전에 성립되면 전송 타이밍을 놓치는 거였다. WebSocket 연결 상태를 확인하고, 연결이 되어 있으면 즉시 전송하고, 안 되어 있으면 연결될 때까지 큐에 보관하는 로직으로 수정했다.

작은 버그 같지만, 이게 안 되면 "DevTools 열기 전의 이벤트도 볼 수 있다"는 핵심 기능이 깨진다. 사소한 타이밍 이슈가 사용자 경험을 망치는 전형적인 케이스였다.

유닛 테스트 추가

12월 30일, 클라이언트 패키지에 유닛 테스트를 본격적으로 추가했다(PR #46).

테스트가 하나도 없던 건 아니고, 리플레이 쪽에 몇 개 있긴 했다(PR #24에서 추가). 하지만 CDP 도메인 구현체나 WebSocket 통신 로직에는 테스트가 전무했다.

추가한 테스트들:

  • Console 도메인: console.log, console.error 후킹이 CDP 이벤트를 제대로 생성하는지
  • Network 도메인: fetch/XHR 후킹이 요청/응답을 제대로 캡처하는지
  • DOM 도메인: getDocument, querySelector 같은 명령이 올바른 응답을 반환하는지
  • DOMStorage 도메인: localStorage/sessionStorage CRUD 동작 확인
  • WebSocket 클라이언트: 연결/재연결/메시지 전송 로직

테스트를 작성하면서 기존 코드의 문제점도 몇 개 발견했다. 에러 핸들링이 빠져 있거나, 타입이 맞지 않거나, 엣지 케이스를 고려하지 않은 부분들이 있었다. 테스트가 코드의 거울이라는 말이 맞다.

커버리지 PR 코멘트

테스트를 추가했으니 커버리지도 보고 싶었다. PR을 올리면 자동으로 커버리지 리포트가 코멘트로 달리는 스크립트를 만들었다(PR #47).

GitHub Actions에서 테스트를 돌리고, 커버리지 리포트를 생성해서, PR에 코멘트로 남기는 워크플로우다. 이전 커버리지와 비교해서 올라갔는지 내려갔는지도 보여준다.

솔직히 사이드 프로젝트에 이런 것까지 필요한가 싶기도 한데, 한 번 만들어놓으니까 PR을 올릴 때마다 "아 커버리지가 떨어졌네" 하고 바로 인지할 수 있어서 나쁘지 않았다. 나 혼자 하는 프로젝트라 리뷰어가 없으니, CI가 리뷰어 역할을 하는 셈이다.

코드 정리

테스트를 작성하면서 동시에 코드 정리도 했다.

  • 네트워크 응답 크기 표시 버그 수정(PR #32): 바이트 단위가 제대로 표시 안 되던 문제
  • 리플레이 타임아웃 에러 수정(PR #32): 긴 세션 재생 시 타임아웃 나던 문제
  • 코드 중복 제거와 리팩토링(PR #33): AI가 비슷한 코드를 여러 곳에 복붙한 흔적들 정리

AI로 빠르게 개발하면 이런 중복이 생기기 쉽다. AI는 기존 코드를 다 기억하고 있지 않으니까, 비슷한 유틸 함수를 다른 이름으로 여러 곳에 만들어놓기도 한다. 이걸 수동으로 찾아서 합치는 건 사람 몫이다.

10일간의 스프린트를 돌아보며

12월 20일부터 30일까지, 약 10일간의 집중 개발이 일단락됐다. 이 기간 동안 PR을 47개 머지했다.

기능적으로는 배민이 블로그에 쓴 것 대부분을 구현했고, 거기에 rrweb 세션 리플레이, PostMessage 트랜스포트, Tauri 데스크톱 앱, init() API, CSS 도메인까지 추가했다. 테스트와 커버리지 시스템도 갖췄다.

다만 이 시점에서 아직 빠진 게 있었다. React Native다. 지금까지 만든 건 전부 웹 환경이다. React Native 앱에서 CRD를 쓰려면 완전히 다른 접근이 필요했다. 그리고 그건 새해가 지나서야 시작됐다.

1줄 요약

10일 스프린트 후 테스트 작성과 코드 품질 개선에 집중했다. WebSocket 타이밍 버그 수정, 유닛 테스트 추가, 커버리지 PR 코멘트 자동화를 통해 코드 안정성을 확보했다.