최신 버전으로 관리하는 것이 좋은 이유

어떤 소프트웨어도 항상 관리되고 최신 버전으로 업데이트 되고 관리되는게 좋다.
물론 업데이트 하지 않아도 소프트웨어를 더 확장 시킬 수 있으며, 돌아는 간다.
그래서 대부분의 개발팀에서 언어와 프레임워크 버전을 올리는 것에 대한 중요도는 다른 개발에 비해 후순위로 밀리기 마련이다.

하지만 당연하게도 방치된 소프트웨어는 늘 제약조건을 갖게 된다. 최신 기술이나 스펙과 연동할 수 없다거나, 더 이상 보안 패치조차도 진행이 되지 않아 잘 격리하고 관리하지 않으면 보안 이슈까지 갖게 된다.

버전이 너무 오래되서 지급된 최신 장비에서 개발환경을 설정하는 것 조차 어려워지는 경우들도 존재한다.
최신 버전에서는 기본으로 지원하는 기능이지만 오래된 버전에선 지원하지 않아 외부 라이브러리를 써야하거나 편법을 이용해야하는 경우도 자주 있다.

그리고 버전만 업데이트 했을 뿐인데 성능이 개선되어 사용해야 할 자원을 아끼는 경우도 있다.

물론 최신 버전이 안정화 되기 전에 먼저 업데이트 했다가 낭패를 보는 경우도 있기 때문에 조심해야 할 필요도 있다.

Ruby 버전 업데이트

Ruby 버전을 올릴때 가장 조심하는 부분은 Ruby 버전 그 자체가 문제가 되지는 않는다.
이미 다음 버전에서 호환되지 않을 메서드나 기능들에 대해서는 보통 마이너 패치를 할 때 다음 버전에 없어지는 메서드나 기능에 대해서 Deprecated Warning 로그를 남겨주는 편이라 대응하기 때문에 대응만 하고 버전을 올리면 된다.

버전 업데이트를 준비하면서 거의 항상 문제가 되는 부분은 Ruby와 함께 사용하고 있는 라이브러리들이 문제인데 국내 루비스트 기준으로는 보통 Rails 때문에 루비를 쓰는 경우가 많다고 보면 된다.
물론 이외의 라이브러리가 지원을 하지 못해서 업데이트를 못하는 경우도 있다.
한번 버전을 올리는 것을 놓치게 되면 겉잡을 수 없을 정도로 굴러버린 스노우볼이 되서 업데이트가 불가능한 경우도 많다.

작성 기준으로 Ruby 버전이 2.7이고 레일즈 버전이 6.0.3.4 버전이 최신버전이고, 과거에 회사에서 사용한 버전이 2.6 / Rails 5.1 일때도 그만큼은 커녕 Ruby는 2.2 혹은 2.3에 Rails는 4 버전대인 경우들이 있었다.

팀의 기조

우리 팀은 다행히 버전을 올리는 것에 대한 동의가 어느정도 되어있었고, 우선 순위가 높지는 않았지만 급한 일이 없을 때 내가 진행한다고 해도 그 누구도 막지 않고 오히려 지원해줬다. 테스트 케이스도 경험했던 다른 회사들보다 더 꼼꼼하게 작성되어있어서 쉽게 올릴 수 있었다.

물론 모든 시스템의 버전을 다 올릴 수 있었던 것은 아니다.

우리도 노후화 된 프로젝트의 경우 쉽게 올릴수 없어서 장기적으로 바라보기로 결정하였고 그런 노후화 된 프로젝트의 경우 마이너 보안 패치를 최 우선으로 하는 것으로 진행했다. 대신 비교적 최신 시스템들은 빨리 업데이트 할 수 있도록 노력하고 있다.

진행 방식 및 팁

테스트케이스를 믿고 업데이트 하며 수정해나가기

우선 테스트케이스 커버리지가 만족할 수준이 아니라면 시도 조차 못했을 것 같다. 신규 프로덕트들의 평균 테스트 커버리지는 80% 이상을 갖추고 있기 때문에 진행할 수 있었다. 버전을 업데이트 하고 테스트를 돌리고 정상적으로 돌아가는지 테스트하면서 진행했다. 실패하면 그 이유를 확인해보고 수정하고 테스트 하고를 반복하면서 버전 업데이트에 영향을 주는 비즈니스 로직을 수정했다.

커버리지를 언급해서 우리 조직이 TDD를 할 것이라고 생각할 수 있지만 우리 조직은 TDD를 표방하는 회사는 아니다. 다만 테스트케이스의 중요성은 모두가 인지하고 있고 우리 팀원들 모두가 테스트케이스를 짜야 하는 것에 대해서 동의하고 있다.

테스트 환경에 배포하기

우리 팀은 개발팀이 개발 후 배포하여 다른 클라이언트와 테스트 해볼 수 있는 서버와 QA팀이 QA를 진행하는 테스트 환경, 그리고 최종 서비스 환경과 동일하게 구성된 스테이징 환경을 구축해두었다.

처음 작업이 완료되고는 개발 테스트 서버에 적용하여 하루 정도 테스트를 했고, 그 후에는 QA 서버에 배포를 해서 며칠을 두었다. 이슈가 나타나거나 APM(Application Performance Monitoring)에 경고가 나올 것이라고 생각해서 였고 실제로 거기서 마이너한 이슈들을 찾을 수 있었다.

카나리 배포

사실 버전 업데이트는 아주 큰 일이기 때문에 QA팀에 전수 테스트를 요청해야 할만큼의 큰 일이기는 하다. 다만 이것만 가지고 전수테스트를 요청하고 설득하는 것은 너무 큰 일이라고 생각했다.

우리 팀은 이러한 배포가 있을 때는 카나리 배포로 여러대의 서버 중 단 한대에만 해당 버전을 적용하여 유저의 응답을 소화하면서 상태를 보는 것을 정책으로 정해두었고 이번 배포에서도 동일하게 적용해서 카나리 배포를 했다. 물론 카나리 배포였기 때문에 발생하는 문제도 있었다.
예를 들면 Rails 5에서 Mailer Job은 DeliveryJobParameterized::DeliveryJob 인데 Rails 6.1 대응을 위한 Rails 6의 Mailer Job은 MailDeliveryJob 였기 때문에 발생했었다.
Rails 5로 배포 된 인스턴스 데몬들은 MailDeliveryJob를 모르고 Rails 6 인스턴스는 DeliveryJobParameterized::DeliveryJob를 모르기 때문이다.

이런 자잘한 이슈를 제외하고는 응답을 정상적으로 하는 것을 확인했고 카나리 배포 며칠 뒤 정상 배포를 하며 배포를 마무리 할 수 있었다.

* 카나리 배포의 유래는 광산에 카나리아 새를 새장에 넣어 함께 들어가서 유독가스가 발생시 카나리아가 민감하게 반응하여 광부들이 빠르게 눈치채고 생존할 수 있도록 했다는 것에서 착안된 이름이라고 한다.

결론

덕분에 Rails 6의 Multiple Databases 기능도 사용할 수 있게 되었고, Ruby 2.7과 Rails 6 자체의 퍼포먼스가 올라서 다른 노력없이 성능 개선의 효과도 얻게 되었다. 동료들도 많은 자극이 되었다고 해주어서 기분이 좋았다.

이러한 버전 업데이트를 할 수 있기 위해서 내가 생각하는 요약된 결론은 아래와 같다.

  • 팀 조직이 자신의 프로덕트가 노후화 되지 않도록 노력하는 가치에 대해서 중요하게 생각해야한다.
  • 테스트케이스는 개발 속도를 향상시키기도 하지만, 리팩토링이나 버전 업데이트나 환경 이식에도 유용하다.
  • 개발 환경, 테스트 할 수 있는 환경은 많이 있는 게 좋다.
  • 전수 테스트가 어려울 때는 카나리 배포를 해보고 문제가 있으면 빠른 롤백을, 문제가 없다면 배포를 진행하는 방법도 있다.