How we built a Ruby library that saves 50% in testing time (새 탭에서 열림)
소프트웨어 프로젝트의 규모가 커짐에 따라 발생하는 길고 불안정한 CI 파이프라인은 개발 생산성을 저해하는 주요 원인입니다. 데이터독(Datadog)은 코드 변경 사항과 관련된 테스트만 선택적으로 실행하는 '테스트 영향 분석(Test Impact Analysis)' 기술을 통해 이 문제를 해결하고자 했으며, 성능 오버헤드를 최소화한 Ruby용 Intelligent Test Runner를 구축했습니다. 이를 위해 기존 도구들의 한계를 넘어 Ruby VM 인터프리터 이벤트를 직접 활용하는 C 익스텐션을 개발함으로써 테스트 시간을 절반으로 단축하는 성과를 거두었습니다.
테스트 영향 분석의 개념과 필요성
- CI 파이프라인의 병렬 실행은 속도를 높일 수 있지만, 클라우드 컴퓨팅 비용이 증가하고 관련 없는 코드의 결함으로 인한 테스트 실패(Flaky tests) 문제를 해결하지 못합니다.
- 테스트 영향 분석은 각 테스트와 해당 테스트가 실행하는 소스 파일 간의 매핑 정보를 동적으로 생성하여 관리합니다.
- Git 커밋에서 변경된 파일과 특정 테스트가 의존하는 파일 목록이 겹칠 때만 해당 테스트를 실행하고, 관련이 없는 경우 건너뜁니다.
- 이 시스템은 정확성(필요한 테스트를 거르지 않음), 성능(매 커밋마다 실행 가능할 정도로 낮은 오버헤드), 투명성(사용자 코드 수정 없음)이라는 세 가지 핵심 요구사항을 충족해야 합니다.
기존 Ruby 솔루션의 한계
- 내장 Coverage 모듈: Ruby 3.1에서 추가된 테스트별 커버리지 수집 기능은
SimpleCov와 같은 기존 커버리지 도구와 호환되지 않으며, 성능 오버헤드가 약 300%에 달해 테스트 속도가 4배나 느려지는 단점이 있습니다. - TracePoint API: VM 이벤트를 구독하는
TracePoint방식은 사용이 간편하고 기존 도구와 충돌하지 않지만, 여전히 200~400% 수준의 높은 성능 저하를 유발하여 실제 개발 환경에 적용하기 어렵습니다.
Ruby VM 이벤트를 활용한 맞춤형 C 익스텐션
- 성능 최적화를 위해 Ruby 소스 코드의
coverage.c와thread.c를 분석하여, C 언어 수준에서 직접 인터프리터 이벤트를 가로채는 방식을 채택했습니다. - Ruby의 C API인
rb_add_event_hook2를 사용하여RUBY_EVENT_LINE이벤트를 등록함으로써, 코드가 실행되는 시점에 즉각적으로 파일 정보를 수집하도록 설계했습니다. dd_cov_update_line_coverage와 같은 콜백 함수 내에서 실행 중인 파일이 프로젝트 루트 내에 있는지 확인하는 필터링 로직을 구현하여 데이터 수집의 효율성을 높였습니다.- 이 접근 방식은 Ruby 인터프리터 내부 메커니즘을 직접 활용함으로써 성능 오버헤드를 획기적으로 낮추고, 대규모 테스트 수트에서도 무리 없이 작동합니다.
규모가 큰 Ruby 프로젝트에서 테스트 속도 정체와 CI 비용 증가 문제를 겪고 있다면, 전체 테스트를 매번 실행하는 대신 테스트 영향 분석 도구를 도입하여 파이프라인의 효율성을 극대화할 것을 권장합니다. 특히 성능이 중요한 환경이라면 Ruby 내장 도구에만 의존하기보다 VM 이벤트를 직접 제어하는 방식이 유효한 해결책이 될 수 있습니다.