Kaigi on Rails 2024に参加してきました!
10/25(金)、26(土)に@有明セントラルタワーホール & カンファレンス(東京)で行われたKaigi on Rails 2024に参加してきました。
技術カンファレンスに参加する旨みは、普段の業務では触らない技術を知るきっかけになったり、他社事例を聞くことで自社システムへの理解が深まったりすることだと思います。
私は今回が初参加だったんですが、HotwireやGraphQL、Solid Queue、OmniAuthなどの技術についてや、他社事例(テスト時間の高速化とか、ERBからViewComponentへの移行とかPackwerkを用いたリファクタリングとか)からさまざまな知見を得ることができました。
本記事では個人的に面白かったセッションをいくつかピックアップして紹介していこうと思います。
タイムテーブルはこちらです。
ちなみに弊社のバックエンドはRailsをメインに利用しています。なので私は普段からRailsの恩恵を受けまくっていますし、私にとってRailsはとても好きなWebアプリケーション開発フレームワークです。
印象に残ったセッション Day1
基調講演
めっちゃ良かったのでシンプルに内容をまとめます。
Ruby on Railsの"Rails"とはRails newからIPOまでの道のりのこと。
サービス成長するにつれてRailsから外れてしまう。
Rails framework gives you structure.
Ruby on Railsは構造を提供してくれるが隙間があり、その隙間をそれぞれが埋めようとして歪ませる。
Rails Way gives you guidance.
Rails Wayは哲学でありそれを追求することで生産性が保たれる。
Rails Wayに従って隙間を埋めるためのガイドがLayered Design for Ruby on Rails Application
Railsの仕組みを理解してモデルを上手に育てる - モデルを見つける、モデルを分割する良いタイミング -
こちらのセッションは基調講演の内容に近い内容でした。
Fatモデルという問題提起から始まって、その対処法としてイベント系エンティティを切り出したり、POROにロジックを切り出したり、FORMオブジェクトを使ったりという方法が提案されていました。
よくある方法では、サービスクラスに実装してcallメソッドで呼び出すというプラクティスもありますが、Rails Wayに近い形でいうとサービス層自体を推奨しないということでした。
自分も以前texta.fmを聴いてこの手法は知っていて日常の業務で使おうと思って試したこともあるのですがまだまだイベント系エンティティの切り出しとかがしっくりこない感じがある。あとは単純に既存のデータモデルの設計に影響を受けるので完全に自由に設計できるわけでもないので難しいと感じていました。このあたりは日々鍛えていきたいなと思います。
また発表者の方のzennの記事で「Railsの練習帳」というのがあるらしく、こちら宿題としてやっていこうと思いました。ありがたすぎる。
Sidekiqで実現する長時間非同期処理の中断と再開
デプロイ時に長時間非同期処理が残ってしまっている場合に今までは指差し確認を行なっていたが、ジョブの中断・再開処理を実装して解決したという発表です。
ただ冪等性を確保した実装をするだけでは処理が最初からやり直しになってユーザ体験が下がってしまったり、想定外の箇所で停止した場合にメールが二重送信されてしまう等のリスクがあるという課題があります。
これらの課題を解決する中断処理と再開処理はどうあるべきかから考えて設計・実装していったところが勉強になりました。
この中断・再開処理をRSpecでテストする方法も勉強になりました。
and_wrap_originalという元のメソッドをそのまま呼び出しつつ追加の処理をかけるソッドを使うと、任意のタイミングで中断が発生することを再現できるそうです。
発表の最後にはSidekiq Iterationという機能が紹介されていました。
中断時に進行状況(カーソル)を保存し、再開時には保存したポイントから処理を再開できるそうです。コールバックも充実しているのでこれで実現できそうですが、まだベータ版なのでproduction利用はもう少し先になりそうです。
リリース8年目のサービスの1800個のERBファイルをViewComponentに移行した方法とその結果
8年にわたるViewの運用で色々な課題が見えてきたのでViewComponentへの移行を決断し、移行作業には自動変換スクリプトを用いて行ったという発表でした。
ERBの問題点として挙げられていたのがこの3つです。
Viewファイルを読まないと必要なパラメータがわからない
一貫性のないパラメータの渡し方
テンプレート内のロジックの多さ
ViewComponentを使うとコンストラクタでパラメータを渡せるので必要なパラメータが一目瞭然になるのと、パラメータの渡し方の一貫性も保証できます。
移行によるパフォーマンス改善も期待されていましたが、実測値ベースでは差は見られなかったとのこと。
私も前職でJavaのフレームワークの移行で多くのviewのファイルの移行をしたことがあるので懐かしかったです。私の場合は自動変換スクリプトを作れず断念してパワープレーでやりましたが、エンジニアとしてあるべき姿を魅せられた感じがします。個人的に圧巻の内容でした。
ERBのパースの部分とか、変換ロジックの話がかなりすごかったのと、rspecも自動生成してたのが強すぎました。
パースした後に手に入る抽象構文木をどうこうという話をしていたけど全く理解できませんでした。悔しい。
また、この自動変換スクリプトは普通にいい値段で売れるくらいの価値あると思いました。120時間くらいで作ったらしいけど本当にすごい。
ActionCableなら簡単? 生成 AIの応答をタイピングアニメーションで表示。実装、コスト削減、テスト、運用まで。
生成AIの応答をタイピングアニメーションで滑らかに表示する上でActionCableを入れると簡単に実装ができますが、実運用を考えると色々な課題が見つかってくると言う発表でした。
実運用ででてくる課題で言うとこの辺りでそれぞれどのように乗り越えたのかが非常に勉強になりました。
コネクションの占有問題 -> ActionCableを実行するサーバはスタンドアロンとして実行する
LLMの応答時間が長い場合 -> Sidekiq使って非同期処理
非同期処理にRedisアダプタを使うと返ってくるトークンの順序が保証されなくなる問題 -> ActionCableにインデックス番号を伝えて組み直す
テストにおけるコスト削減 -> VCR使ってリクエスト数を削減
色々なことを気をつけながら実装しく流れがめちゃくちゃわかりやすく超勉強になりました。
そのほかで印象的だったのは発表者が「Railsで新しいことをやろうとしたときはRailsガイドを読んだ方がいい。」と言っていたことです。自分はそんなにRailsガイドに頼ってこなかったのでこれからはゴリゴリ使っていこうと思いました。
印象に残ったセッション Day2
都市伝説バスターズ「WebアプリのボトルネックはDBだから言語の性能は関係ない」
RubyとGOのHTTPサーバで性能を検証した話がとても勉強になりました。
RubyはGVLという仕組み上、1リクエストあたりのCPUを使う計算処理時間がI/O時間に比べて大きくなってくるとGOで実装したHTTPサーバ(GOMAXPROCS = 10)と比べてrpsやrequest timeに差が出てきてしまう。
実験では、「I/O時間」と「CPU処理時間」の割合を調整しながらベンチマークを取っていて、「CPU処理時間」の割合が大きいエンドポイントの場合は最大10倍くらいの性能差が出ていました。(実験の細かい条件については後日スライドか動画が公開されたら参照してみてください。)
後半はRailsサーバのチューニングの話になりましたが、CPU処理時間の割合を元にスレッド数を調整する方法や、プロファイラを使ってCPU処理時間の割合が大きい処理を改善していく方法が紹介されていました。
例示されていたもので言うとこの辺りになります。
JSON.parseは結構CPU使っているのでOjに置き換えるとめっちゃ早くなる
mysql2も結構CPU使っているのでtrilogyに置き換えたら10%くらい早くなる
言語特性とかpumaのリクエスト処理機構の仕組みまで掘り下げた話が本当に勉強になりました。
ActiveRecord SQLインジェクションクイズ (Rails 7.1.3.4)
SQLインジェクション対策としては以下の3点を意識する。
SQLフラグエントを受け取るメソッドを一定把握する
User.order("age: #{params[:order]}")は任意のSQLを実行できてしまう
クエリメソッドへ外部入力を雑に渡さない
User.where("name = #{params[:name]}")は任意のSQLを実行できてしまう
クエリメソッドへ外部入力を渡す時は以下のいずれかを行う
エスケープが確実に適用される形式を選択する
位置指定ハンドラ or 名前付きハンドラを利用する
sanitize_sql_arrayなどのsanitizeメソッドを組み合わせて利用する
渡される値が制限されるような入力値チェックを行う
Rails7.2からBrakemanというセキュリティ脆弱性を静的解析するためのgemがあるっぽいけど偽陽性は多いのでignoreリストみたいなもの作って運用でカバーする必要があるっぽいですね。
Sidekiq vs Solid Queue
2024年時点ではActiveJobのアダプターとしてSidekiqが有力ですが、Rails8.0からデフォルトでSolid Queueが採用されます。「SidekiqからSolid Queueに移行する必要があるのか?」や、「これからRails newする場合はどっちを採用すべきなのか?」という疑問を持っている方は必見の発表です。
ストレージ面、インタフェース面、機能面の3点から比較した結論としては下記の通り。
SidekiqからSolid Queueへの移行はするべき?
SidekiqからSolid Queueに移行することは基本的にメリットが薄い
Sidekiq EnterpriseやProが高いよという場合のコストカットくらい
あとはRedisを減らして運用負荷を減らすとか
新しく作るとしたら?
ジョブをあまり使わないとしたらSolid Queue
ジョブをたくさん使うならSidekiq
中間のサービスならSidekiq特有の機能で欲しいものがあればSidekiq
実績でいうとSidekiqは2万ジョブ/秒だが、Solid Queueは2000万ジョブ/日らしい。本当に要件次第になるとは思いますが調べるべきポイントが明確になったのはよかったです。
Identifying User Identity
サービス開発でUserモデルについてより深く再考してみるという内容です。「ユーザーのアイデンティティとは何か?」というところから考えて、「どのようなテーブル設計にするのか?」、「ユーザの登録、ログイン、退会をどう表現するか」、「ユーザのステータスをどう管理するか」、「管理者ユーザとユーザの権限の違いをどう乗り越えるのか」といった現実的な問題を、既存のパラダイムに縛られない本質的な視点から気持ちよく解いていきました。
発表を聞き終わったあとは脳みそが揺れるくらい良い内容でした。
こーゆー話聞くと本当にKaigi on Rails来てよかったと思いますし、自分でもアプリケーションを0から作りたくなりますね。
基調講演
スタッフエンジニアの島田さんの貴重な貴重な基調講演。ソフトウェアを設計する際に大事だと思っていることを話していただきました。
全体が機能するように設計すること
設計時点ではわからないことが多いので変化に向けて設計する
変化に向けた設計とはオプションを増やすこと
「オプションを増やす設計」とは「何にでも対応できるような構造や仕組み」ではなく「どの方向にも進めるようにシンプルに保つこと」
その上で本当の難しさは「シンプルさを保つこと」
シンプルさを保つには修復し続けることが必要
修復とは「元の状態に戻す」のではなく、「変わった後の全体と再度調和させる」こと
お手本となるソフトウェアはRailsである
修復という概念をクリストファー・アレグザンダーを引用して説明していたのがオシャレでした。エンジニアなら誰でもよく用いる「設計」という言葉の捉え方が高度すぎて素敵でした。
まとめ
Kaigi on Rails 2024は想像以上の収穫がありました。
印象に残ったのは発表者の何名かが「Railsガイドは良いよ」といっていたことです。私はRailsエンジニアながらあまり目を通したことがなかったのでこれからちゃんと読み込んでいこうと思いました。(大反省)
また、技術を深く知るとビジネス課題(機能要件や非機能要件を満たすだけではなく移行工数やコスト構造の改善など)をクリティカルに解決できるということがひしひしと感じました。このレベル感が自分がエンジニアとして目指したいところだと思いました。
そして、基調講演でも言われていたRails Wayについてもちゃんと自分の思想に取り入れていかないといけないと思いました。
本当は全ての発表を紹介したいくらいどれも示唆深い内容でした。とても良い時間だったので来年も参加したいなと思いました。
来年は東京駅 JP TOWER Hall & Conferenceです!