ANDPAD Rails 6.0へのアップグレード

r7kamuraと言います。2020年9月頃からANDPADの開発に参画しています。

2021年2月、ANDPADで利用しているWebアプリケーションフレームワーク Ruby on Rails (以下Rails) のバージョンを5.2から6.0にアップグレードしました。今後アップグレードを行う方が同様の作業を行えるよう、今回の変更に伴い必要となった作業について、あらためて言語化してこの記事で共有できればと思います。

全体の流れ

大まかに分けると、今回は次のような手順で作業を進めていきました。

  1. Rails 5.2系の最新のバージョンに上げる
  2. Rails 6.0版のブランチを用意してテストを通す
  3. Rails 5.2と6.0に両対応したコードに変更する
  4. Rails 6.0で検証を進める
  5. Rails 6.0に本番環境を切り替える
  6. Rails 5.2向けの対応を取り除く

Gemのバージョン変更

Railsアップグレードガイドでも、パッチバージョン側から徐々にバージョンを上げていくことが推奨されています。今回は、当時5.2系の最新版だったRails 5.2.4.4に上げた後、当時6.0系の最新版だったRails 6.0.3.4に上げました。

Railsのバージョンを上げるときは、次のように依存関係にあるGemを bundle update で指定してアップグレードします。本当は bundle update --conservative rails だけで済めば良いのですが、色々あってこれらの引数が必要になっています。利用しているGemによっては、ここに他のGemも含めなければならない状況も出てくるでしょう。

bundle update --conservative \
  actionmailer \
  actionpack \
  actionview \
  activemodel \
  activerecord \
  activesupport \
  rails \
  railties

Rails 6.0版のGitブランチを用意し、Gemのバージョン変更と今後の変更をひとまずはこのブランチに含めていくことになります。

テスト

Gemのバージョン変更を終えた後は、テストが成功するように変更を加えていきました。具体的には、次のように段階を踏んでいきました。

  1. rails console を起動できるようにする
  2. テストが全て成功するようにする
  3. テストで警告が出ないようにする

この作業の中で、Rails 6.0で廃止される機能を置き換えたり、各種Gemにパッチを送ったり、アプリケーション側でモンキーパッチを入れたりと、色々な変更を入れていくことになりましたが、説明が煩雑になるので詳細については割愛します。どの問題も各ライブラリのGitHub Issuesに既に報告されている、あるいは自分で報告した問題ばかりで、今回の変更に際して特別に配慮が必要になった大きな問題というのはありませんでした。

差分の管理

変更をRails 6.0版ブランチに加えていくと、徐々に差分が大きくなっていき、レビューやコンフリクトの解消、問題発生時のRevertも難しくなっていきます。移行期間中は新旧両バージョンで動作するコードを目指すことにし、Rails.gem_version等を利用した条件分岐を適宜入れつつ、Rails 6.0版ブランチの差分を徐々に主流のブランチに取り込んでいきました。

主流のブランチに変更を取り込むべくPull Requestをつくる際には、「Rails 6.0」のようなラベルを付与するようにしておくと便利です。この記事も、そのラベルの付いたPull RequestやIssueを振り返りながら書いています。

全ての差分を主流ブランチに取り込んでいくと、Rails 6.0版ブランチはGemfileとGemfile.lockの差分のみになりますが、これもGemfile.lockを2つ用意することで新旧両バージョンで動かせるようにしました。具体的には、環境変数RAILS_VERSIONとBUNDLE_GEMFILEを指定して、二つのGemfile.lockを切り替えて運用することにしました。

f:id:r7kamura:20210216190619p:plain

テストの並行運用

Rails 6.0への対応中にRails 5.2でしか動かないコードが新たに追加されていくと困るので、対策としてRails 5.2とRails 6.0の両方でCIのテストを動かすようにしました。前述したように環境変数だけで切り替えられるようにしておけば、この変更自体は大した手間ではありません。当然CIに掛かるコストが増えますが、やっておいて良かった変更だと思っています。

いつ頃からテストを並行運用するようにしておけば良いかについてですが、テストがまだ失敗する段階から新バージョンのテストを動かすようにすると、「失敗するのが当然」という印象が定着してしまう可能性が高まるので、おおよそ新バージョンでテストが全て成功するようになった頃に追加するのが良いだろうと考えています。

検証

Rails 6.0での検証は、多くの現場でも行われているであろう方法で、検証用の環境にRails 6.0版をデプロイして手動で確認を行いました。リリース時に問題が起きて差し戻す可能性も考慮し、差し戻したときに問題が起きないかという検証も行いました。結局差し戻しは発生せず、また差し戻しによる問題も検証時には発生しませんでしたが、例えば新→旧バージョンへの変更はセッションやキャッシュのエンコーディング方式に互換性が無かったりする可能性もあるので、この検証は大事だと思います。

また、開発者には任意で開発環境でもRails 6.0を利用して開発を進めてもらいました。この辺りも、環境変数だけでバージョンを切り替えられるようにしておいたおかげで簡単に対応できたのではないかと思います。

切り替えと後片付け

検証で問題が無いことが分かったので、本番環境のRails 6.0への切り替えを行い、処理性能や報告されている例外に問題が無いことを確認しました。

その後、移行期間用に入れていた条件分岐を外してRails 5.2のサポートを廃止し、Rails 6.0からの新機能を導入するといった後片付け的な変更を加えました。

ここまで特に触れていませんでしたが、今回はRails.configurationへの変更は加えずにアップグレードを行いました。Rails 5.2以前にデフォルトになっていた設定が残ることになりますが、今後 load_defaults 6.0 相当の設定に近づくよう徐々に変更を加えていく予定です。

バージョンの変遷

今回のバージョン変更の位置付けについて整理するために、Railsのリリース履歴とANDPADでのバージョンの変遷についてあらためて振り返ってみます。

https://rubygems.org/gems/rails/versions によると、Railsは次のような履歴でリリースされてきました。

  • 2014年12月 Rails 4.2リリース
  • 2016年06月 Rails 5.0リリース
  • 2017年04月 Rails 5.1リリース
  • 2018年04月 Rails 5.2リリース
  • 2019年08月 Rails 6.0リリース
  • 2020年12月 Rails 6.1リリース

一方、ANDPADは次のように変遷してきました。

  • 2015年05月 Rails 4.2で開発開始
  • 2016年12月 Rails 5.0にアップグレード
  • 2017年06月 Rails 5.1にアップグレード
  • 2020年10月 Rails 5.2にアップグレード
  • 2021年02月 Rails 6.0にアップグレード

ANDPADでのアップグレードはRails 5.1以降長らく停滞していましたが、最近になって徐々に最新版に近づいてきました。次回、遂に最新版であるRails 6.1にアップグレードしようと考えています。

まとめ

以上、ANDPADのRails 6.0へのアップグレードについて振り返ってみました。まとめると、徐々に変更して差分を抑えること、両バージョンを試しやすい環境をつくることが重要だと考えています。

最後に

ANDPADでは、共に働く仲間を募集しています。今回のRailsアップグレードのような改善系の仕事だけに留まらず、様々なポジションを募っているので、興味を持たれた方はぜひ採用サイトをご覧いただき、我々がどのようなサービスを提供しているのか、どのように開発を進めているのかについてより詳しく知っていただければと思います。

engineer.andpad.co.jp