루비 프로젝트에서 의존성을 최신 상태로 유지하는 것은 단순한 권장 사항을 넘어 필수적인 요소입니다. 의존성 업데이트를 소홀히 할 경우, 다양한 문제에 직면할 수 있습니다. 첫째, 보안 취약점(CVE) 노출은 원격 코드 실행, 데이터 유출, SQL 인젝션, 크로스 사이트 스크립팅 등 심각한 보안 위협으로 이어질 수 있으며, 이는 계약 위반, 벌금, 기업 평판 손상과 같은 비즈니스적 손실을 초래합니다. 둘째, 새로운 기능 요구사항 발생 시 최신 젬과의 비호환성 문제로 인해 기능 구현이 지연되거나 불가능해질 수 있습니다. 셋째, 오래된 의존성은 새로운 개발자가 프로젝트에 합류하거나 새로운 개발 머신을 설정할 때 컴파일 오류와 같은 환경 설정 문제를 야기하여 온보딩 시간을 늘립니다. 마지막으로, 운영체제(OS)의 수명 종료(End-of-Life)는 강제적인 시스템 업데이트를 요구하며, 이는 프로젝트의 기능 동결 및 장기간의 업데이트 작업을 초래할 수 있습니다.
반대로, 의존성을 정기적으로 업데이트하면 성능 최적화, 버그 수정, 그리고 Action Cable, Action Text와 같은 루비 온 레일즈(Ruby on Rails)의 새로운 강력한 기능들을 활용할 수 있어 애플리케이션의 품질과 개발 효율성을 높일 수 있습니다. 실제로 강연자는 레일즈 5에서 7로의 업데이트에 500시간, 심지어 GitHub는 레일즈 3에서 5로 업데이트하는 데 1년 반이 걸렸던 사례를 언급하며 의존성 방치의 대가를 강조합니다.
이러한 문제를 해결하기 위해 Infimum에서는 체계적인 의존성 업그레이드 문화를 구축했습니다. 주요 전략은 다음과 같습니다:
- 필수 전제조건: 높은 코드 커버리지(90-95% 이상)를 유지하여 업데이트 시 테스트를 통해 문제를 즉시 발견하고, 젬의 비공개(private) 또는 미문서화된(undocumented) API 사용을 제거하며, 재해 복구 계획을 수립합니다.
- 의존성 업그레이드: 업데이트를 작고 빈번한 단위로 나누어 적용하고, 보안 업데이트, 레일즈 업데이트, 루비 업데이트 순으로 우선순위를 부여하여 중요도가 높은 변경사항부터 처리합니다.
- 주요 업그레이드 계획: 메이저 버전 업그레이드는 다른 작업과 분리하여 진행하며, QA 팀에 충분한 정보를 제공하고 필요시 개발자가 직접 테스트를 지원합니다. Infimum의 Rails 업그레이드 핸드북과 같은 자료를 활용하는 것도 권장됩니다.
- 이해관계자 인식 개선: 고객과 같은 이해관계자에게 의존성 업데이트의 중요성과 미수행 시의 위험을 명확히 설명하고, 유지보수 비용에 이 작업을 포함하여 정당한 대가를 받습니다.
- 의존성 상태 추적 및 측정: 프로젝트의 의존성 상태를 정량적으로 측정하고 추적하기 위해 내부 도구인 Revisor를 개발했습니다. Revisor는 젬 파일의 모든 젬을 분석하여 오래된 버전의 수, 젬의 중요도 등을 고려한 ‘건강 점수(Health Score)’를 0-100 사이로 산출합니다. 또한, 이 로직을 외부에 공개된 젬인 Polariscope로 추출하여 누구나 자신의 루비 프로젝트의 의존성 상태를 스캔하고 점수를 확인할 수 있도록 했습니다. 의존성 상태 변화를 시각화하는 공개 레일즈 애플리케이션인 Gorama도 제공하여 프로젝트의 시간 경과에 따른 의존성 변화를 한눈에 파악할 수 있게 합니다.
- 자동화된 업데이트: Dependabot과 같은 도구를 활용하여 월별로 자동화된 Pull Request(PR)를 생성하고, 이를 개발, 테스트, 프로덕션 의존성 그룹으로 나누어 관리합니다. 이때
Gemfile.lock
충돌을 피하기 위해 각 PR을 개별적으로 스테이징에 배포하고 테스트한 후 프로덕션으로 병합하는 전략을 사용합니다. 이는 수동 작업 시간을 크게 줄여줍니다.
이러한 체계적인 접근 방식을 통해 Infimum은 매월 약 8시간 정도의 노력으로 수십 개의 프로젝트 의존성을 최신 상태로 유지하며, 이는 루비 커뮤니티가 여전히 활발하고 강력함을 증명하는 사례가 됩니다.