대규모 Rails 테스트 스위트 최적화 전략
Doctor Lib은 초기 5,000개였던 테스트가 현재 84,000개로 증가하면서 CI 파이프라인이 40-45분 소요되는 병목 현상을 겪었습니다. 이를 해결하기 위해 다음과 같은 다각적인 접근 방식을 취했습니다.
- 성능 병목 식별:
- 데이터베이스 리셋: 각 테스트마다 10개에 달하는 데이터베이스를 리셋하는 과정이 전체 테스트 시간의 약 30%를 차지했습니다.
- 팩토리(Factories): 데이터베이스와의 상호작용 및 복잡한 객체 생성 로직으로 인해 팩토리에서만 테스트 시간의 50%를 소모했습니다.
- 누적된 코드(Bloat): 12년 된 모놀리스에 오랜 기간 추가된 작은 기능들이 누적되어 성능 저하를 야기했습니다.
- Rails 기본 설정으로의 회귀:
- 트랜잭션 테스트: 각 테스트 시작 시 트랜잭션을 시작하고 종료 시 롤백하는 방식을 도입하여 데이터베이스 리셋 시간을 크게 단축했습니다. 이는 기존의 테이블 truncate 방식보다 훨씬 빠릅니다.
- 픽스처(Fixtures) 활용: 팩토리 대신 픽스처 사용을 권장하고, Shopify의
fixture_factory와 같은 도구를 활용하여 픽스처의 유연성을 확보했습니다.
- 결과: 이러한 노력으로 한 엔진의 테스트 시간을 7분에서 1분 미만으로 줄이는 데 성공했으며, 현재 코드베이스의 90%가 새로운 프레임워크로 마이그레이션되었습니다.
Packwerk 모듈화의 현실과 데이터베이스 확장성
-
Packwerk 도입 배경: 팀별 도메인 분리 및 테스트 성능 향상을 목표로
Packwerk를 도입하여 Rails 엔진 기반의 모듈화를 시도했습니다. -
한계점: 제로 종속성 패키지 달성의 어려움, 정적 분석의 한계, 높은 투자 비용 대비 제한적인 효과 등 현실적인 어려움을 겪었습니다.
Packwerk는 여전히 유용하지만, 완벽한 격리나 테스트 성능 면에서 기대만큼의 효과는 없었습니다. -
데이터베이스 스케일링: AWS Aurora PostgreSQL의 최대 인스턴스 한계에 도달하여 10개의 라이터와 각 라이터당 최대 15개의 리더를 운영 중입니다. 읽기 쿼리를 자동으로 리더로 분산하고, 관련 테이블 그룹을 새 라이터로 마이그레이션하는 샤딩 전략을 통해 확장성을 확보하고 있습니다. 데이터 마이그레이션 시에는
safe_pg_migrations와 같은 도구를 사용하여 다단계 프로세스를 거쳐 안전하게 변경합니다.
개발자 경험 및 Rails 업그레이드
-
개발자 도구: Go로 작성된 CLI 도구
DCTL을 통해 개발 환경 설정, 스테이징 데이터베이스 연결 등을 자동화하여 온보딩 경험을 개선했습니다. -
Rails 업그레이드: 초기에는 개인이 담당했으나 현재는 전담 팀이 업그레이드를 수행합니다. 변경 사항을 깊이 이해하고,
bundle open을 통해 Rails 소스 코드를 직접 분석하며,dual boot방식을 사용하여 프로덕션에 영향을 주지 않으면서 새로운 Rails 버전으로 전환하는 과정을 거칩니다. -
플래키 테스트 관리: 20,000개 이상의 E2E 테스트에서 발생하는 플래키 테스트 문제를 해결하기 위해 테스트에 “밀리터리 스코어”를 부여하고, CI에서 두 번 실패 시 자동으로 스킵하고 버그 티켓을 생성합니다. 특히
Capybara::Lockstep을 도입하여 Capybara와 React 프론트엔드 간의 동기화 문제를 해결하여 플래키 테스트의 70-75%를 줄였습니다. -
기능 스위치(Feature Switches): 새로운 기능 도입, 기존 기능 제거, 쿼리 변경 등 모든 코드 변경 사항에 기능 스위치를 활용하여 안전한 배포 및 롤백을 가능하게 합니다. DataDog과 Sentry를 연동한 자동 롤백 시스템 구축도 모색 중입니다.