$30 off During Our Annual Pro Sale. View Details »

令和に完全勝利するための Railsアップデート戦略 / Reiwa Rails Update

seiga
January 23, 2020

令和に完全勝利するための Railsアップデート戦略 / Reiwa Rails Update

seiga

January 23, 2020
Tweet

Other Decks in Programming

Transcript

  1. 令和に完全勝利するための Railsアップデート戦略 @seiga 平成.rb #11 -平成Reject会議-

  2. 自己紹介 • 名前: seiga / 林 星河 • twitter_id: seiga_hayashi

    • 所属: Classi 株式会社 • 平成5年生まれ
  3. そろそろRailsアップデート やらなきゃヤバイですね

  4. なんでヤバイの? • EOLによるセキュリティリスク • 新規 APIを使えないことなどによる相対的な開発効率の低下 • 処理速度の向上などの恩恵が受けられない

  5. 特にEOLによるセキュリティリスクがヤバイ Rails5.1以下に重大なセキュリティ問題が発生された場合、手作 りpatchなどで対応しなければならない! • バグ修正 ◦ 6.0.Z • セキュリティ問題 ◦

    6.0.Z, 5.2.Z • 重大セキュリティ問題 ◦ 6.0.Z, 5.2.Z
  6. 重大セキュリティ問題もひとつ前までなの? 「最新のシリーズのリリース全部と、ひとつ前のシリーズ の一番最後のリリースがサポート対象」

  7. Railsのバージョン管理スキーム Rails X.Y.Z • パッチZ ◦ バグ修正。セキュリティに関わる場合だけ API変更や機能追加の可能性もある • マイナーY

    ◦ 新機能が追加される。 APIの変更が含まれる場合もある。 ◦ 重大な変更の場合マイナーリリースまたはメジャーリリースで非推奨通知が行われる • メジャーX ◦ 新機能が追加される。多くの場合 API変更も含まれる。 ◦ マイナーリリースより変更の重大性が高い
  8. そもそもRailsのアップデートって 何やるの?

  9. Railsのアップデートでやること • (必要に応じて)Rubyのアップデート • Railsのアップデート • Railsバージョンに依存するgemのアップデート、patch当て、 fork、乗り換え • アプリケーションがアップデート前後で同じ挙動する事を保証

    • deprecatedなメソッドなどを対応する方法に置き換え
  10. やること多いけど まぁいけるっしょ!

  11. - gem 'rails', '~> 4.1.16' + gem 'rails', '~> 6.0.2.1'

    bundle update
  12. 原因がわからない大量のエラーが発生or起動すらできない 各バージョンの変化が全部混ざってくるのでエラーの原因を特定 するのは並大抵のことではない Rubyのアプデ由来のエラー Rails5.0のアプデ由来のエラー Rails5.0に依存するgemのアプデ由来のエラー Rails5.1のアプデ由来のエラー Rails5.1に依存するgemのアプデ由来のエラー Rails5.2のアプデ由来のエラー Rails5.2に依存するgemのアプデ由来のエラー

    etc... 一つのエラーを構成する要素にはいくつもの原因が ...
  13. 完全勝利したい

  14. Step by Step戦略

  15. Step by Step 『複数の作業を一度に行うと、それらの作業が混線して、どれ も失敗する可能性が高くなる』 『一歩ずつ進めると、最後の一歩を後戻りすることが楽になり ます』 プリンシプルプログラミング p228より

  16. Step by Step戦略のメリット • 問題の切り分けがしやすくなる • 問題が起こった時にrevertする範囲が狭くなる • 不確定要素がなくなるので、不安を感じることのないまま作業 できる

    アプデ工程も可能な限りStepに分けることで、 「進みやすく」「戻りやすい」開発になる
  17. Step by Stepを意識した Railsアップデート

  18. 出発点 • テストカバレッジ率を十分に高くする ◦ 80%以上は必要 ◦ request spec/system specのような全部の層を通過するような薄いテストを書 くのがコスパが良し

    ◦ simplecovあたりを使えば楽に計測できる
  19. • Railsはマイナーバージョンのlatestに更新しておく ◦ 例えば4.2.9だったら4.2.11.1に上げておく ◦ パッチバージョンの上昇のみなので基本的特にすることないはず • deprecation warningsを全て解消しておく

  20. 必要なRubyのバージョンが足りない場合 目的のRailsバージョンに必須のRubyバージョンを満たしていな い場合はあらかじめやっておく

  21. まずは公式ドキュメントを読む • https://railsguides.jp/upgrading_ruby_on_rails.html ◦ Railsのアップデートに対応する各バージョンに対応するアップグレードの主な 注意点が記載されている • https://railsguides.jp/5_0_release_notes.html ◦ 各バージョンごとに、どんな変更があるのかが記載されている

  22. Rails gemのアップデート マイナーバージョン単位で指定する その後 bundle update rails -gem "rails", "~>

    4.1.0" # 4.1.x latest +gem "rails", "~> 4.2.0" # 4.2.x latest Gemfile
  23. Bundler could not find compatible versions for gem "xxx" 1.

    bundlerエラーから根本原因となっているgemを見つけ、 https://rubygems.org/で新旧両方のRailsをサポートするgem バージョンを見つける 2. このgemのみを更新するための新しいブランチをmasterから 作成 3. Railsは旧バージョンのまま、そのgemの新しいバージョンを指 定してbundle update xxx
  24. 4. 更新したgemの変更ログを見つけて読み、それに応じてアプリ ケーションを調整 5. テストが通るまでアプリケーションを調整 6. ブランチをmasterにマージしてRailsのアプデ再開 Railsの新旧両方に互換性のあるバージョンが見つからない場合(Devise、 ActiveAdmin、Ransackなど)は仕方ないので注意深くRailsと一緒に上げる

  25. bundle update --conservative xxx • 対象gemの依存先gemのアップデートを抑制する • gemのアップデート差分を最小にしたい時や、依存解決がうま く噛み合わない時に活用できる •

    最終的にはbundle update --conservative rails activemodel activerecord actionpack activesupport actionview railtiesみ たいになる これつけて厳密にやるかやらないかはアプリ規模次第
  26. rails:updateでアプリケーションの設定を更新 • Rails4まで ◦ bundle exec rake rails:update • Rails5以降

    ◦ bin/rails app:update Conflict に対するOverwrite y/nは一旦全部yで受け入れていい その後gitやIDEの機能で適切に合体させるのが効率いい
  27. どうやって適切に合体させるの? • gitによるdiff • http://railsdiff.org で比較できる前バージョンと後バージョンの diff • 別途rails newしておいたアプリの同ファイルとのdiff

    ポイントはdiffを絶対に新しいバージョンに合わせるという気持ち。 次のバージョンアップ時に楽になる。
  28. まずは起動できるようにする • rails c • rails s • exec rspec

  29. テストが通るようにする うまくやるポイント • 公式ドキュメントやRailsの各stableブランチのコミットログを見 る • masterにもバックポートとして同じ修正が入れられると差分が 少なくなって良い

  30. rspec出力を保存することでアプデのお供に bundle exec rspec spec -o specresult.txt >& deprecation.txt いい感じにspec

    resultsとdeprecationsが分けて出力されるので アプデ作業のお供として便利(タスク化,grep,グルーピング)
  31. new_framework_defaults_x_x.rbをうまく使う 5.0以降から使える。自動的に前バージョンの挙動を守るような設 定が記述されているので、Stepを刻むのに役立つ テスト通過したら、一つずつ新バージョンのデフォルト設定にする と効率良い # Enable origin-checking CSRF mitigation.

    Previous versions had false. Rails.application .config.action_controller .forgery_protection_origin_check = false # Rails4.2 # Rails.application.config.action_controller.forgery_protection_origin_check = true # Rails5.0 config/initializers/new_framework_defaults.rb
  32. deprecation warningを解消する • 次のアップデートのために、deprecation warningが解消され ている状態を徹底する • テストと同様にバックポートをmasterに仕込めると良い

  33. deprecation warningsのtraceが見たい! gemがdeprecations吐いちゃってる場合などに特定できる • ActiveSupport::Deprecation.debug = true ◦ バックトレースが見れる •

    ActiveSupport::Deprecation.behavior = :raise ◦ 例外を投げる • 標準エラー出力をジャックする方法もある ◦ https://nekogata.hatenablog.com/entry/2020/01/17/144831 ◦ ActiveSupport::Deprecationを使っていないタイプも通用するようになる
  34. ステージング環境で手動テスト • インフラ環境*バージョンによる問題発見ができる • なるべく本番と近い環境が大事

  35. リリース • マイナーバージョン単位でリリースするのが大事。本番環境と バージョンの組み合わせ特有の問題発見をしやすくできる • 何か問題が起こった時はひとつ前のバージョンにすぐにrevert できるので、切り戻し範囲が少ない

  36. Step by Step戦略のまとめ 1. Railsに依存するgemのバージョンを上げる 2. Railsのマイナーバージョンあげる 3. テスト通るようにする 4.

    deprecation warningを解消する 5. ステージングで検証してリリース これを目的のバージョンまで繰り返す 4.1to4.2, 4.2to5.0, 5.0to5.1….
  37. 完全勝利は近い!

  38. その他伝えたいこと

  39. リファクタリングしたくなっても堪える • 気持ちは本当にわかる...本当にわかる... • が、まずはアプデを終わらせるのを最優先として強い気持ちで ぐっと堪えよう

  40. 期間を設定する時は気をつける • アプリケーションでやってることを全て把握してないと無理 • gem自体のバグを踏み抜く場合もある • 弊社では13人年の試算がされた。実際そのぐらいかかってい る。 • 先の見えない作業になりがち。予想の三倍ぐらいのスケ

    ジューリングをしよう。
  41. ペアプロ、モブプロを活用しよう • Ruby、Rails、その他gem、アプリケーション自体への知識を 深めるチャンス • 知識差がとても大きいので、純粋にスピードが上がる • レビュー時の負担軽減される • アプデ工程への心理的ハードルが下がる

  42. ペアモブでなくとも複数人で巻き込んでやる 知ってる、知らないの差が大きいので、詰まったらすぐチャットに 投げるなどをした方がいい

  43. 継続的なアップデートをするために • gemのバージョン指定は積極的に外そう • Dependabotといったgemバージョン自動追従botを導入して gemのアプデに敏感になるのもよし • ペアモブプロでアプデへの恐怖心をなくす • チームとしてアプデは各期で必ず発生する工数という認識を

    固める
  44. Ruby2.7にはいつ上げる? Rails6.1にした後にRuby2.7に上げるのが良さそう(早くて6月ごろ?)

  45. おまけ:アプデに役立つgem

  46. FactoryBot5系にアプデする際に一括修正する gem rubocop-rspec を入れる事で対応できる を実行。非推奨のところが全てcorrectされる。 bundle exec rubocop --require rubocop-rspec

    --only FactoryBot/AttributeDefinedStatically --auto-correct
  47. Rspecのrequest paramsの非推奨を一括置換 DEPRECATION WARNING: Using positional arguments in integration tests

    has been deprecated, in favor of keyword arguments, and will be removed in Rails 5.1. Deprecated style: get "/profile", { id: 1 }, { "X-Extra-Header" => "123" } New keyword style: get "/profile", params: { id: 1 }, headers: { "X-Extra-Header" => "123" } bundle exec rails5-spec-converter すると一括置換してくれる が大量に出るので、gem rails5-spec-converterを使用 4.2to5.0で利用。Rspecを使っていると
  48. 参考資料 https://speakerdeck.com/soarteclab/railsbaziyonatupushi-don g-wu-yu https://speakerdeck.com/r7kamura/railsatupuguredobai-jing https://developers.freee.co.jp/entry/rails5-yatteiki https://inside.pixiv.blog/sue445/4751 https://qiita.com/jnchito/items/cce3b2795e1c66735310