소프트웨어 프로젝트가 성장함에 따라 CI 파이프라인의 속도 저하와 불안정성은 흔한 문제가 됩니다. 전체 테스트 스위트를 실행하는 데 많은 시간이 소요되고, 변경 사항과 무관한 테스트 실패로 인해 개발 생산성이 저하됩니다. 이러한 문제를 해결하기 위한 접근 방식 중 하나가 테스트 영향 분석(Test Impact Analysis, TIA)입니다. TIA는 코드베이스 내 각 테스트와 해당 테스트 실행 중 사용되는 소스 파일 간의 매핑을 동적으로 생성하여, 최근 코드 변경 사항과 관련된 테스트만 선별적으로 실행하는 방식입니다. Datadog은 이러한 아이디어를 기반으로 Ruby 애플리케이션을 위한 Intelligent Test Runner 제품을 개발했으며, 이 글은 그 핵심 구성 요소인 테스트 영향 분석 라이브러리를 구축하는 과정에서 마주한 도전 과제와 해결책, 그리고 기술적 세부 사항을 다룹니다.
Datadog 팀은 Ruby용 테스트 영향 분석 라이브러리 개발을 위해 여러 접근 방식을 시도했습니다. 초기에는 Ruby의 내장 Coverage 모듈을 활용하려 했으나, 기존 코드 커버리지 도구와의 비호환성 및 최대 300%에 달하는 심각한 성능 오버헤드 문제에 직면했습니다. 다음으로 시도한 TracePoint API는 사용 편의성과 데이터 수집 측면에서는 개선되었지만, 여전히 약 200%의 높은 성능 오버헤드를 보였습니다. 이러한 한계를 극복하기 위해 Datadog은 Ruby 인터프리터의 내부 동작을 깊이 파고들어 C 확장을 활용하는 자체 솔루션 개발을 결정했습니다.
C 확장을 통해 RUBY_EVENT_LINE 이벤트를 직접 후킹하는 방식은 초기 POC 단계에서 약 60-80%의 오버헤드를 보이며 가장 유망한 결과를 나타냈습니다. 성능 최적화를 위해 rb_sourcefile
에서 반환되는 C 문자열을 Ruby 문자열로 변환하는 오버헤드를 줄이기 위해 rb_profile_frames
및 rb_profile_frame_path
를 사용하여 파일명 문자열에 직접 접근하는 방식을 적용했습니다. 또한, 동일 파일 내 연속적인 라인 이벤트 발생 시 불필요한 반복 작업을 피하고자 rb_sourcefile
이 반환하는 파일명 포인터를 캐싱하여 포인터 비교로 빠르게 동일 파일 여부를 판단하는 최적화를 수행했습니다. 이로써 추가적인 5-10%의 성능 개선을 달성했습니다.
하지만 라인 커버리지 기반 TIA는 ‘코드 없는 클래스(code-less classes)’의 영향을 포착하지 못하는 중요한 한계가 있었습니다. 예를 들어, 로직이 대부분 상속이나 외부 라이브러리(Active Record 등)에서 제공되는 클래스의 경우, 해당 클래스 파일 자체에서는 RUBY_EVENT_LINE
이벤트가 발생하지 않아 테스트 영향 분석에서 누락될 수 있었습니다. 이 문제를 해결하기 위해 Datadog Continuous Profiler에서 영감을 받아, RUBY_INTERNAL_EVENT_NEWOBJ 이벤트를 활용하여 테스트 실행 중 인스턴스화되는 객체의 클래스를 추적하는 방식을 도입했습니다. 이를 통해 Module.const_source_location
메서드를 사용하여 객체가 정의된 소스 파일을 식별함으로써 ‘코드 없는 클래스’의 영향까지 분석 범위에 포함시켰습니다. 내부 트레이스포인트에서 Ruby API 호출이 금지되는 제약 때문에 C 구현 해시를 사용하는 등 조심스러운 접근이 필요했습니다.
개발된 라이브러리는 외부 서비스 호출이나 데이터 파일 변경과 같은 프로세스 외부의 영향을 직접 추적하지 못하는 등의 일부 제한 사항이 있으나, Datadog Intelligent Test Runner에서는 추적 파일 정의나 테스트 건너뛰기 방지 설정 등을 통해 이러한 한계를 보완할 수 있도록 지원합니다. 최종적으로 이 도구는 중앙값 25%의 성능 오버헤드로 기존 솔루션 대비 5-10배 우수한 성능을 보이며, 모든 커밋에서 실행될 만큼 충분히 효율적입니다. 이를 통해 항상 최신 상태의 테스트 영향 맵을 유지하며 정확하고 결정적인 테스트 선별 실행을 가능하게 합니다.
Datadog이 Ruby를 위해 구축한 테스트 영향 분석 라이브러리는 성능 저하와 불안정성 문제를 겪는 대규모 Ruby 프로젝트의 CI 파이프라인 효율성을 크게 개선하는 강력한 도구입니다. Ruby의 내부 메커니즘에 대한 깊이 있는 이해와 C 확장을 활용한 최적화를 통해 기존 방식의 한계를 극복하고, '코드 없는 클래스' 문제까지 해결하며 정밀하고 효율적인 테스트 영향 분석을 구현했습니다. 이 라이브러리는 Datadog Intelligent Test Runner의 핵심 기술로서 고객들에게 더 빠르고 안정적인 테스트 경험을 제공하고 있습니다. 향후에는 파일별 정확한 라인 커버리지 데이터 제공 등 기능 확장을 계획하고 있으며, 테스트 영향 맵을 활용한 자동화된 근본 원인 분석 등 더 다양한 활용 가능성을 탐색하고 있습니다.