25+ 실제 현장 Rails 업그레이드 질문 (그리고 개발자들이 실제로 필요한 답변)
Source: Dev.to
왜 업그레이드해야 할까?
- 보안 – 오래된 Rails 버전은 패치를 받지 못해 애플리케이션이 위험에 노출됩니다.
- 성능 – 최신 버전은 더 나은 성능과 도구를 제공합니다.
- 호환성 – 최신 gem들은 보통 최신 Rails 릴리스를 요구합니다.
- 유지보수 – 장기적인 기술 부채를 줄이고 온보딩을 용이하게 합니다.
복잡도 평가
업그레이드 난이도는 여러 요인에 따라 달라집니다:
- 현재 뒤처진 Rails 버전 수
- 사용 중인 Ruby 버전
- 오래되었거나 호환되지 않는 gem 수
- 코드베이스에 남아 있는 레거시 패턴(Sprockets, 오래된 AR 문법, monkey patch)
Rails 업그레이드 감사나 gem 호환성 도구를 실행하면 차단 요인을 빠르게 파악할 수 있습니다.
업그레이드 순서
- 먼저 Ruby 업그레이드 – 최신 Rails 버전은 최소 Ruby 버전을 요구하는 경우가 많습니다.
- Rails를 단계별로 업그레이드 – 메이저 버전을 건너뛰지 말고 한 번에 하나씩 올립니다.
흔히 마주치는 문제점
- 유지보수가 중단된 또는 호환되지 않는 gem
- ActiveRecord 동작 변화(NULL, 타임존, 쿼리 등)
- Zeitwerk로 전환 시 자동 로딩 문제
- API 변경으로 영향을 받는 백그라운드 잡/메일러
- 문서화되지 않은 Rails 내부에 의존하는 테스트
업그레이드 전략
- 큰 버전 점프를 피함 – 메이저 버전을 하나씩 올립니다.
- 주요 기능 개발을 일시 중단 합니다.
- 프로덕션에 가까운 데이터를 가진 스테이징 환경을 사용합니다.
- 작은 배포 단위로 진행해 문제를 조기에 발견하고 모든 사용자에게 영향을 주지 않게 합니다.
- 백업 및 롤백 계획을 미리 준비합니다.
의존성 정리
유지보수가 중단된 gem을 만나면 세 가지 선택지가 있습니다:
- 대체 가능한 다른 gem으로 교체한다.
- 포크해서 내부적으로 패치한다.
- 더 이상 필요하지 않다면 제거한다.
업그레이드는 의존성을 정리하기에 최적의 시점이며, gem 수가 적을수록 향후 업그레이드가 원활해집니다.
핵심 워크플로우 테스트
복잡한 로직을 가진 대규모 앱의 경우:
- 모든 핵심 워크플로우(결제, 임포트, 잡)를 테스트한다.
- 새로운 쿼리 패턴을 확인하기 위해 SQL 로그를 모니터링한다.
- 수백만 레코드를 다루는 경우 부하 테스트를 실행한다.
- 위험도가 높은 컴포넌트는 업그레이드 동안 API/서비스 뒤에 격리하는 방안을 검토한다.
안전망 추가
업그레이드를 시작하기 전에 가장 중요한 워크플로우에 대한 기본 테스트를 추가합니다:
- 현재 출력을 캡처하는 스냅샷 테스트
- VCR 같은 도구를 이용한 요청 녹화
- 핵심 기능을 검증하는 스모크 테스트
- 주요 사용자 흐름에 대한 기능 테스트
우선 고수준 시스템 테스트부터 시작하고, 필요 시 수동 QA를 병행하며, 스테이징에 자주 배포합니다.
레거시 JavaScript와 자산
Rails 업그레이드가 레거시 JavaScript 작동을 막지는 않지만, 오래된 UJS 관행이나 Sprockets 기반 자산은 패치가 필요할 수 있습니다. importmaps, ESBuild, Webpacker 로 마이그레이션한다면 Rails 코어 업그레이드와는 별개의 트랙으로 진행하세요.
설정 마이그레이션
secrets.yml 혹은 환경 변수만 사용하던 오래된 앱은 config/credentials.yml.enc 로 전환해야 합니다. Rails는 제너레이터와 환경별 파일 병합 기능을 제공하니, 모든 환경에서 마스터 키 관리가 일관되도록 합니다.
ActiveStorage와 파일 업로드
ActiveStorage가 크게 개선되었습니다. Paperclip이나 CarrierWave 를 사용 중이라면 Rails 업그레이드 전후에 마이그레이션을 수행하세요. 업그레이드 도중에 진행하면 복잡도가 증가합니다.
대시보드·관리 gem
내부 Rails 헬퍼에 크게 의존하는 대시보드 gem은 업데이트가 필요할 수 있습니다. 대부분 최신 버전으로 업그레이드하면 해결되며, 드물게는 폐기된 헬퍼 사용을 직접 패치해야 합니다.
ActionCable과 Redis 어댑터
업그레이드 시 최신 Redis 어댑터, 향상된 동시성, 간결한 설정을 기대할 수 있습니다. 오래된 구독 식별자나 커스텀 미들웨어가 있다면 폐기 여부를 확인하세요. 최신 ActionCable 설정은 대부분 매끄럽게 마이그레이션됩니다.
콜백과 내부 동작
Rails가 진화하면서 after_initialize, around_validation 같은 콜백의 동작이 바뀔 수 있습니다. 초기 경고를 확인하고 서비스 객체로 리팩터링하거나 새로운 ActiveModel 콜백으로 옮겨야 합니다.
버전을 건너뛰는 위험
여러 메이저 버전을 한 번에 건너뛰면 기술 부채가 급증하고, 폐기된 동작이 한 번에 깨져버립니다. 점진적인 폐기 경고를 놓치게 되며, 비용과 위험이 기하급수적으로 증가합니다.
데이터베이스 어댑터
오래된 mysql2, pg, mongoid 버전을 사용 중인 경우 SSL 기본값, 타임존 규칙, 연결 관리 등 어댑터 파괴적 변화에 직면할 수 있습니다. 해당 의존성을 별도로 업그레이드하고 커넥션 풀 동작을 검증하세요.
CI/CD 파이프라인 고려사항
CI 파이프라인에서도 Ruby 버전, 시스템 의존성(Node, Yarn, Redis) 및 캐시 전략을 최신으로 맞춰야 합니다. 오래된 빌드 이미지나 깨진 Dockerfile을 흔히 발견하니, 업그레이드 전에 파이프라인을 새로 고쳐 잡음(noise)을 최소화합니다.
일정 추정
- 50k–200k LOC 규모 앱: 테스트 커버리지, gem 복잡도, 건너뛴 버전 수에 따라 3–8주 소요.
- 테스트 스위트가 탄탄한 앱은 훨씬 빠르게 완료됩니다.
- 테스트가 없는 앱은 하드닝과 회귀 검증에 더 많은 시간이 필요합니다.
성능 벤치마킹
업그레이드 전후로 벤치마크를 수행합니다. rack-mini-profiler, Scout, Skylight 같은 도구를 활용해 느린 쿼리, 메모리 사용 급증, 캐시 동작 변화를 감지합니다. 성능 저하는 주로 ActiveRecord 동작 변화나 캐시 레이어 변경에서 발생합니다.
결론
Rails 업그레이드는 겁이 날 수 있지만, Ruby를 먼저 업그레이드하고 메이저 버전을 하나씩 진행하며, 의존성을 정리하고 안전망 테스트를 추가하고 성능을 모니터링하는 체계적인 접근법을 따르면 자신 있게 진행할 수 있습니다. 그 결과 보안 강화, 성능 향상, 유지보수 비용 감소, 개발자 만족도 상승 등의 이점을 얻을 수 있습니다.