enpayのRubyが3.1.0にアップデートしました🎉
💎

enpayのRubyが3.1.0にアップデートしました🎉

こんにちは、エンジニアの 森塚(@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 に依存しています。

ちなみに

Ruby の日本語リファレンスマニュアル(通称 るりま) では YAML の説明はまるっと psych の方に投げられています)

この psych のバージョンアップは大きめの非互換な変更があり、アプリケーション側とライブラリ側どちらもこの非互換な変更に対応している必要があります。

変更の詳細に関しては本記事では詳細に説明しないため、以下も併せて読んでもらえると 🙇

プロと読み解く Ruby 3.1 NEWS - クックパッド開発者ブログ

技術部の笹田(ko1)と遠藤(mame)です。クックパッドで Ruby (MRI: Matz Ruby Implementation、いわゆる ruby コマンド) の開発をしています。お金をもらって Ruby を開発しているのでプロの Ruby コミッタです。 本日 12/25 に、ついに Ruby 3.1.0 がリリースされました( Ruby 3.1.0 リリース )。今年も Ruby 3.1 の NEWS.md ファイルの解説をします。NEWS ファイルとは何か、は以前の記事を見てください。 本記事は新機能を解説することもさることながら、変更が入った背景や苦労などの裏話も記憶の範囲で書いているところが特徴です。 今回リリースする Ruby 3.1 は総論として、Ruby 3.0との互換性を重視したリリースとなっています。 つまり、あまり大きな非互換はありません。 比較的アップグレードしやすいと思いますので、みなさん是非試してみてください。 ちなみに、Ruby 2.6はあと4ヶ月でEOL(サポート終了)で、Ruby 2系列最後の2.7も1年4ヶ月でEOLになると思われます。 月日が立つのは早いですね。 Ruby 3.1 の目玉として、次のようなものがあげられています。 ハッシュリテラルやキーワード引数の省略記法の導入 新しいJITコンパイラであるYJITの導入による性能向上 開発環境の向上 デバッガの刷新 エラー箇所に下線をひく error_highlight の導入 IRB のオートコンプリートとドキュメント表示 本記事では、これらを含めて NEWS ファイルにあるものをだいたい紹介していきます。 Values in Hash literals and keyword arguments can be omitted.

プロと読み解く Ruby 3.1 NEWS - クックパッド開発者ブログ

エンペイでは今回はワークアラウンドな対応として一旦 Gemfile で psych のバージョンを 4.0.0 未満となるようにして対応と影響の確認を後回しにすることにしました。

gem 'psych', '< 4.0.0'

これは Rails7.0 へのアップデート時に他のライブラリのアップデートやしっかりめの QA も行うので、このときに一緒にやってしまおうという判断です。

余談

enpay では dependabot を利用しているんですが今回確認するまで psych のバージョンは 3.3.0 でした。一方、2022/2 時点の Psych3 の最新バージョンは 3.3.2 です。

あれ、なんで dependabot で通知が来ていないんだ?と思って調べてみたら理由は dependabot の設定でした。

dependabot ってデフォルトでは子の依存までは見てくれないんですね。

上記の記事にある通り、dependency-type: all を設定すると見てくれる様になるのでこちらも Rails のアップデート時に一緒に設定する予定です。

CircleCI のイメージの変更

Ruby3.1 とは直接関係はない話ではあるのですが、一緒に書いておきます。

エンペイでは CI は CircleCI を利用していますがこれまで利用していた CircleCI のイメージが 2021/12/31 で廃止されていました。

エンペイでの対応としては公式のマイグレーションガイドにある通り、CircleCI のイメージを prefix が cimg の次世代版に置き換えるだけで済みました。

次世代 CircleCI イメージへの移行

Last updated * Reading time 2020 年より、CircleCI では CircleCI イメージの次世代版の展開を開始しました。 これらのイメージは、 CircleCI 2.0 の発表時にリリースされた従来の CircleCI イメージに代わるものです。 次世代版は CI/CD 環境に合わせてゼロから設計されており、 従来よりもスピードと効率、そしてなによりも信頼性が大きく向上しています。 次世代 CircleCI イメージの特徴について詳しくは、 こちらのブログ記事 をご覧ください。 従来イメージが今後廃止されることに伴い、ここでは新しいイメージへの移行プロセスについて説明します。 従来のイメージから次世代版に移行するには、名前空間を変更する必要があります。 イメージの Docker 名前空間について、従来のものはすべて circleci でしたが、次世代イメージでは cimg に変わります。 たとえば、従来の Ruby および Python のイメージを次世代版に移行するには、それぞれ次のように変更します。 - circleci/python:3.8.4 + cimg/python:3.8.4 既存のイメージについて、今後いくつかの変更が行われる予定です。 以下のイメージは廃止され、次世代イメージへの置き換えは行われません。 buildpack-deps イメージを現在使用している場合は、新しい CircleCI ベース イメージ

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,
)
ちなみに

def foo = 1 という書き方は Ruby3.0 で導入された一行メソッド定義という構文です 🐱

と同じ名前を指定したい場合何度も同じ名前を書かなければならず長い名前のキーだったりキーの数が増えれば増えるほど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 の頃からパターンマッチを利用していて(犯人は主に自分なのですが 😇 )アップデートが完了したことにより警告が出なくなったのでもう何の遠慮もなく使えます 🤩

そしてこれによる喜びの声がこちらになります 🤪

image

最後に

Ruby のバージョンアップが完了したので現在は Rails7.0 へのアップデートに取り組んでいます。

エンペイでは機能開発しつつライブラリのバージョンアップやリファクタリング等の改善作業も積極的に行っています。

まだまだやりたいことに対して手が足りていない状態なので、ご興味がある方は以下のリンクからぜひぜひご応募ください〜 📤