こんにちは、エンジニアの 森塚(@sanfrecce_osaka) です。
酢昆布とか梅干しとか酸っぱいものが好きなんですが一度にたくさん食べすぎると知覚過敏になるということを最近知りました。
さてエンペイでは技術的負債が溜まらないよう、利用している言語やライブラリのアップデートを定期的に行っています。サーバーサイドのライブラリに関しては dependabot を利用して毎スプリント(エンペイでのスプリント周期は1週間)、タスクを積んで対応しています。(フロントエンドに関してはしばらく滞っているのでそこは今後の課題ですね 😅 )
そんな中、2022年2月17日 に enpay の Ruby のバージョンが 3.1.0 に上がりました 🎉 (主に対応してくれた @hoguccさん thx ‼️ )
この記事ではバージョンアップ時に対応が必要だったことやバージョンアップによって受けられた恩恵を紹介していこうと思います。
バージョンアップ時に必要だった対応
エンペイでは最もインパクトの大きい 3.0 へのバージョンアップを終えていたということもあり、大きな修正が必要な対応やクリティカルな問題は発生しませんでした。
メール関連の Gem
Ruby3.1.0 ではいくつかの Gem が default gem から bundled gem に変更になりました。
これらのうちメール関連の Gem (net-pop, net-imap, net-smtp)は actionmailer と actionmailbox の依存 Gem (正確には actionmailer と actionmailbox が依存している mail の依存 Gem)のため、Rails のバージョンが 6.1 以下の場合に net-pop や net-imap、net-smtp を読み込もうとした時点で LoadError が発生します。
この現象は Rails7.0 では https://github.com/rails/rails/pull/44083 で修正されているのですが、Pull Request の description にある通り Rails6.1 にはバックポートされていないためワークアラウンドな対応として Gemfile に net-pop、net-imap、net-smtp を追加しました。
psych
Ruby3.1 では psych のバージョンが 3 から 4 にアップデートされました。
psych は YAML を読み書きをする際に使用されるライブラリで Ruby の yaml はこの psych に依存しています。
この psych のバージョンアップは大きめの非互換な変更があり、アプリケーション側とライブラリ側どちらもこの非互換な変更に対応している必要があります。
変更の詳細に関しては本記事では詳細に説明しないため、以下も併せて読んでもらえると 🙇
エンペイでは今回はワークアラウンドな対応として一旦 Gemfile で psych のバージョンを 4.0.0 未満となるようにして対応と影響の確認を後回しにすることにしました。
gem 'psych', '< 4.0.0'
これは Rails7.0 へのアップデート時に他のライブラリのアップデートやしっかりめの QA も行うので、このときに一緒にやってしまおうという判断です。
CircleCI のイメージの変更
Ruby3.1 とは直接関係はない話ではあるのですが、一緒に書いておきます。
エンペイでは CI は CircleCI を利用していますがこれまで利用していた CircleCI のイメージが 2021/12/31 で廃止されていました。
エンペイでの対応としては公式のマイグレーションガイドにある通り、CircleCI のイメージを prefix が cimg の次世代版に置き換えるだけで済みました。
Ruby3.1.0 に上がった恩恵
error_highlight
error_highlight は Ruby3.1 から入った機能で、NameError や NoMethodError が発生した場所を以下のように highlight してくれる機能です。
% ruby -e "1.time {}" [7:20:43]
-e:1:in `<main>': undefined method `time' for 1:Integer (NoMethodError)
1.time {}
^^^^^
Did you mean? times
機能の詳細に関しては以下の記事で作者の 遠藤さん(@mametter) が解説してくれているのでそちらも併せて読んでいただけると 🙇
この highlight はエラーメッセージの一部として出力されているので、Sentry でのエラーの通知内容にも含まれます。
なので通知されるエラーの調査が 3.0 までに比べて非常に捗るようになりました 🙌
ハッシュやキーワード引数の省略記法
Ruby3.1 ではハッシュやキーワード引数を利用する際にメソッド名や変数名と同じキー名を指定したい場合はキーに渡す値を省略できるようになりました。
JavaScript に慣れている方だとおなじみの記法ですね。
const func = ({ giraffe, elephant, rhinoceros }) => ({ giraffe, elephant, rhinoceros })
const giraffe = 'きりん'
const elephant = () => 'ぞう'
const rhinoceros = 'さい'
func({ giraffe, elephant, rhinoceros })
以前までは
def call_method(giraffe:, elephant:, rhinoceros:)
{
giraffe: giraffe,
elephant: elephant,
rhinoceros: rhinoceros,
}
end
def giraffe = 'きりん'
def elephant = '象'
elephant = 'ぞう'
rhinoceros = 'さい'
call_method(
giraffe: giraffe,
elephant: elephant,
rhinoceros: rhinoceros,
)
と同じ名前を指定したい場合何度も同じ名前を書かなければならず長い名前のキーだったりキーの数が増えれば増えるほど1行あたりの文字数が増えて改行が必要になりどんどん読みにくくなってしまっていましたが、Ruby3.1 からは
def call_method(giraffe:, elephant:, rhinoceros:)
{ giraffe:, elephant:, rhinoceros: }
end
def giraffe = 'きりん'
def elephant = '象'
elephant = 'ぞう'
rhinoceros = 'さい'
call_method(giraffe:, elephant:, rhinoceros:) # => {:giraffe=>'きりん', :elephant=>'ぞう', :rhinoceros=>'さい'}
と非常にスッキリ書けるようになりました。
メソッドの返り値も利用できるのが JavaScript と違うところですね。
なので以下のようなコードも動きます。
hash = { p: } # => { p: nil } ※Kernel.#p の返り値が nil のため
パターンマッチ
Ruby3.0 までは 1行パターンマッチ が experimental な機能だったため、1行パターンマッチ やパターンマッチを利用する右代入を使用した際に警告が出力されていました。
a = { b: 1, c: 2 } # => {:b=>1, :c=>2}
a in { b:, c: }
# (irb):2: warning: One-line pattern matching is experimental, and the behavior may change in future versions of Ruby!
a => { b:, c: }
# (irb):4: warning: One-line pattern matching is experimental, and the behavior may change in future versions of Ruby!
Ruby3.1 では 1行パターンマッチ が experimental でなくなり警告が出なくなったことでパターンマッチが晴れて Ruby の正式な言語機能となりました。
パターンマッチを利用する右代入はハッシュからまとめて値を取り出すときに、1行パターンマッチは条件判定を行いつつ変数への束縛を行いたいときに非常に便利だったんですが、これまでは利用すれば利用するほど警告が出てノイズになるのでプロダクションコードではなかなか気軽には利用できませんでした。
エンペイでは Ruby3.0 の頃からパターンマッチを利用していて(犯人は主に自分なのですが 😇 )アップデートが完了したことにより警告が出なくなったのでもう何の遠慮もなく使えます 🤩
そしてこれによる喜びの声がこちらになります 🤪
最後に
Ruby のバージョンアップが完了したので現在は Rails7.0 へのアップデートに取り組んでいます。
エンペイでは機能開発しつつライブラリのバージョンアップやリファクタリング等の改善作業も積極的に行っています。
まだまだやりたいことに対して手が足りていない状態なので、ご興味がある方は以下のリンクからぜひぜひご応募ください〜 📤