Ruby 프로젝트 의존성 관리: 미로에서 길 찾기

Marko Ćilimković, "Lessons From Escaping the Dependency Upgrade Maze"

작성자
EuRuKo
발행일
2025년 01월 13일

핵심 요약

  • 1 본 강연은 수많은 루비 프로젝트의 의존성을 최신 상태로 유지하는 문제의 중요성을 강조합니다.
  • 2 의존성 업데이트를 소홀히 할 경우 보안 취약점, 기능 비호환성, 개발 환경 설정 어려움 등 심각한 위험이 발생할 수 있습니다.
  • 3 정기적인 소규모 업데이트, 우선순위 설정, 그리고 Polariscope와 Gorama 같은 도구를 활용한 체계적인 접근법을 통해 의존성 관리를 효율화할 수 있습니다.

도입

오늘날 소프트웨어 개발은 재사용성을 극대화하는 라이브러리, 즉 젬(Gem)의 활용이 필수적입니다. 루비 커뮤니티는 방대한 수의 젬을 제공하며, 이는 개발 생산성을 크게 향상합니다. 그러나 젬은 독립적으로 존재하는 것이 아니라 다른 젬에 의존하는 복잡한 관계를 형성하며, 이는 프로젝트 내 수많은 종속성을 야기합니다. 이러한 의존성들은 시간이 지남에 따라 지속적으로 진화하지만, 많은 프로젝트에서 이들을 최신 상태로 유지하는 데 어려움을 겪습니다. 본 강연은 루비 프로젝트의 의존성 관리가 왜 중요한지, 그리고 수십 개의 프로젝트를 동시에 관리해야 하는 기업 환경에서 이 문제를 어떻게 체계적으로 해결할 수 있는지에 대한 깊이 있는 통찰을 제공합니다.

루비 프로젝트에서 의존성을 최신 상태로 유지하는 것은 단순한 권장 사항을 넘어 필수적인 요소입니다. 의존성 업데이트를 소홀히 할 경우, 다양한 문제에 직면할 수 있습니다. 첫째, 보안 취약점(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시간 정도의 노력으로 수십 개의 프로젝트 의존성을 최신 상태로 유지하며, 이는 루비 커뮤니티가 여전히 활발하고 강력함을 증명하는 사례가 됩니다.

결론

결론적으로, 루비 프로젝트의 의존성 관리는 단순한 기술적 작업이 아니라 프로젝트의 보안, 안정성, 그리고 미래 확장성을 보장하는 핵심적인 비즈니스 프로세스입니다. 의존성을 방치하는 것은 장기적으로 더 큰 비용과 위험을 초래합니다. Infimum의 사례는 정기적인 소규모 업데이트, 명확한 우선순위 설정, 그리고 Polariscope, Gorama와 같은 도구를 활용한 데이터 기반의 접근 방식이 복잡한 의존성 미로 속에서 길을 찾고 프로젝트를 건강하게 유지하는 효과적인 방법임을 보여줍니다. 이러한 노력을 통해 루비는 여전히 강력하고 아름다운 언어로 기능하며, 지속적인 혁신을 가능하게 합니다.

댓글 0

댓글 작성

0/1000
정중하고 건설적인 댓글을 작성해 주세요.

아직 댓글이 없습니다

첫 번째 댓글을 작성해보세요!