どうもこんにちは。
ベルサール渋谷ガーデンで開催されたKaigi on Rails 2026のDay1に参加しました。
今年は自分の予定が噛み合わない部分があり、Day1のみ参加しました。(18時~のセッションは私用のため、聴けませんでした...)
今回のセッションでは、テストの高速化、AIエージェントによるデバッグ、ドメインモデリング、非同期処理、APIスキーマ、認証と、幅広い話を聞くことができました。
特に印象に残ったのは、テストの高速化、AIエージェントによるデバッグ、ドメインモデリングのお話でした。ここでは、参加中のメモをもとに、学んだこととこれから試してみたいことを書いていきたいと思います。
この記事は聴講メモに、公開スライドや公式ドキュメントで調べた内容を補った参加備忘録です。登壇内容の逐語録ではありません。聴講できなかったHerbの話は、後半の追加調査として分けています。
てか今回は話聞くのに必死で、写真を撮ることをすっかり忘れていました。
Sponsor LTで気になった技術と設計
株式会社mov様:RubyからDuckDBを使う
株式会社mov様のLTでは、RubyからDuckDBを利用する話が紹介されていました。
DuckDBは分析・集計向けのSQLデータベースで、アプリケーションのプロセス内に組み込んで動かせます。特に気になったのは、S3上のファイルをSQLで集計できる点でした。
例えば、S3に保存したParquetファイルをread_parquet('s3://...')で読み、集計する使い方があります。SQLをS3自身が実行するのではなく、DuckDBがS3からデータを読み取って処理します。DuckDBの公式ガイドに具体例があります。
S3の中身を検索する = Athenaのイメージが強かったですが、Ruby側からS3に対してSQLを実行できるというのは、かなり幅が広がるんじゃないかなと思っています。
(Railsのイベントの中でAthenaっぽい?と思う日が来るとは思わなかった。)
Ruby向けにはduckdbというgemがあり、RubyでSQLから呼べる関数を定義するAPIや、Apache Arrowとの連携も用意されています。ただし、確認したドキュメントでは一部が実験的機能となっていたため、使いたい機能ごとに条件を確認したいです。ruby-duckdbのドキュメントを読みながら、小さなファイルの集計から試してみたいと思いました。
これは触って試したいgemとしてメモ!
株式会社with様・株式会社タイミー様:モノリスを中心に、必要な境界を作る
株式会社with様では、Railsモノリスを中心に置きながら、必要な領域を目的に特化したサブシステムとして拡張する方針が紹介されていました。株式会社タイミー様でも、大きなモジュラーモノリスと複数のサブシステムを組み合わせた構成の話がありました。
2つのスポンサーセッションを聞いて、アプリケーション内部の責務を整理することと、別のシステムへ分割することを分けて考えたいと思いました。
自分が携わっているアプリケーションは、別のシステムへ分割するということを実現できていません。(ほんのちょっとだけできてる。)正直、別のシステムへ分割することのメリットデメリットを整理することができていないので、モジュラーモノリスについてはもっと勉強しなきゃなと思いました。
あと、僕は元withユーザーで非常に大変お世話になりました。
Keynote:Railsの継続性と、AI時代の開発
スポンサーセッションの後はKeynoteでした。
Keynote: Where the tracks go nextでは、DHHが登壇しました。
英語の聞き取りに苦戦...
スマートグラス欲しくなった...(でも高いんだよなぁ...)
まず、Omarchyで目指しているものを「RailsのようなLinux」と捉える話がありました。RubyやRailsで大切にしてきた美しさ、親しみやすさ、使い始めから整った体験を、Linuxにも持ち込もうとしていると理解しました。Omarchyの公開記事も、その背景を知る参考になります。
また、Railsは改善を重ねながらも基本的な構成を保っており、約20年前のコードでも処理の意図を読み取れるという話が印象に残りました。古いコードがそのまま動くという実行互換性の話ではなく、構造や規約が読み手の手がかりになるという意味であると解釈しました。こういう点でもメンテナンス性の高さを実感することができますね。
そこから、AIエージェントとRailsの相性や、人間が生成されたコードを1行ずつレビューし続ける難しさにも話が広がりました。(メモが追いつかず...)
自分の中に残った問いは、AIが大量にコードを書けるようになった今の時代で、人間は何を根拠に正しさを判断するのか、ということです。かなり前から言われているように、結局は人間がボトルネックで、どれだけAIが正確な実装を行なったとしても人間の目で見て判断をしなければいけないところが出てきます。
1行1行レビューしていくのは現実的に不可能なので、レビューのフェーズを仕組み化することで、一定の担保を取る必要があるのかなと思って聞いていました。
FactoryBotをやめればRSpecは速くなるのか?
登壇者は、スマートバンクのnissyiさんです。セッション紹介はこちらです。
タイトルからはFactoryBotとFixturesの比較を想像しましたが、持ち帰ったのは、ツールの置き換えを決める前に、時間がかかっている場所を計測するということでした。
自分自身、RSpecを使ってRailsのCIを回していて、その実行時間には悩んでいたので、良いお話を聞けたなぁと思っています。以前書いた以下の記事のCI環境構築の時も、RSpecの実行時間が15分以上かかることでレビューできる状態までに時間がかかるなぁと思っていました。(あ、読んでみてください。)
話を戻しますね。
FactoryBotのcreateを各exampleで実行すると、そのたびにデータの生成と保存が発生します。さらに、関連先でも別の関連レコードを作っていると、1つのFactoryから大量のINSERTが生まれることがあります。
一方、Fixturesへの移行には、既存のテストデータの定義や準備方法を見直すコストがあります。AIでそれらしい変換を行い、テストを通せても、変換後の前提データが意図どおりかを確認する負担は残るという話もありました。
実際の改善では、TestProfでFactoryの生成回数や所要時間などを調べ、FactoryBotを使い続けながら、次の施策を組み合わせていました。
-
let_it_beで共通データの作成をまとめ、example間で再利用する - テストに不要な関連レコードの生成を減らす
-
fixture_kitで作成済みデータを再投入するSQLをキャッシュする
let_it_beを使う上で、注意が必要なのは、exampleごとにDBの変更をロールバックした時に、共有されているRubyオブジェクトは前のexampleの値を保持し続けるということです。正直よくわからんかったので、以下のように整理しました。以下のテストコードがあるとします。
let_it_be(:user) { create(:user, name: "Taro") }
it "名前を更新できる" do
user.update!(name: "Bob")
expect(user.name).to eq("Jiro")
end
it "最初の名前を確認する" do
expect(user.name).to eq("Taro")
end
この時に、こんな感じでDBの持っている値とRubyのオブジェクトが持っている値が変わっちゃうぜという話なのかなと解釈しています。
| タイミング | DBに保存された名前 | 共有しているuser.name
|
|---|---|---|
| 最初 | Taro | Taro |
| 1つ目のテストで更新した後 | Jiro | Jiro |
| 1つ目のテスト終了後、DBをロールバック | Taro | Jiroのまま |
| 2つ目のテスト開始時 | Taro | Jiroのまま |
この状態を解決するためにreload, refindというメソッドがあるようで、どちらか適切な方を選ぶことでDBとRubyオブジェクト側の不整合を抑えられるようですね。
# reload
# 各テストで最初にuserを参照するとき、同じオブジェクトへDBの値を読み直す動きをする
# ロールバック済みのDBからAliceを読み直せる
let_it_be(:user, reload: true) { create(:user, name: "Taro") }
# refind
# 各テストで最初にuserを参照するとき、DBから新しいオブジェクトとして取得する
# User.find(user_id)をやり直すイメージ
let_it_be(:user, refind: true) { create(:user, name: "Jiro") }
多分、TestProfの公式ドキュメントをよぉく読めばわかるのかな。
fixture_kitは、データを再現するSQLを利用する仕組みです。FixtureKitのREADMEを確認して、各手段が減らしているコストの違いを整理できました。
頑張ってちゃっぴーに翻訳してもらいながら読みました。
「FactoryBotをやめるべきか」という二択ではなく、データ生成のどこに無駄があり、どの方法なら既存資産を活かして減らせるかを考える話として参考になりました。
AIエージェントのデバッグ能力を向上させよう
登壇者はNaClのriraさんです。
スライドと、紹介されたdebug-mcpのソースコードが公開されています。
このセッションで印象に残ったのは、AIに修正を推測させるだけでなく、実行中の状態を調べる道具を渡すという考え方です。
debug-mcpは、Rubyのdebuggemによるデバッグ操作をMCP経由でAIから呼べるようにします。ブレークポイントで止める、変数やコールスタックを見る、式を評価する、実行を再開するといった操作を、AI自身が行えます。
Rails側にgemとして取り入れることで、コーディングエージェントのハーネス設計をある程度簡略化できるものであると理解しました。
ただ、MCPプロトコルを経由して、エージェントがブレークポイントを置いたりできるというのは魅力的だなぁと思いました。
スライドのデモでは、更新リクエストが200を返しているのに、DBの値が直っていないケースが扱われていました。AIは読み取り専用属性を疑い、モデルの設定、実際のUPDATE文、DBから再取得した値を調べていました。
HTTPの成功応答やメモリ上の値だけで判断せず、保存結果まで確認する流れが具体的でした。DBを直接修復してよいかという判断は人間に残し、修復後の確認はAIが行うという役割分担も参考になります。
Railsには、実行時の調査に使える仕組みがすでにあります。
| Railsの特徴 | デバッグに役立つこと |
|---|---|
| モノリス | 同じプロセス内の処理を、1つの接続から追いやすい |
| リフレクション | モデル自身にカラム、関連、バリデーションなどを問い合わせられる |
ActiveSupport::Notifications |
SQLやキャッシュ操作など、実際に発生したイベントを観測できる |
人間が調査するために使ってきた機能を、AIにも使わせられるという説明で、RailsとAIの相性をコード生成以外の面から理解できました。
失敗したRSpecのプロセスを停止して状態を残し、後からAIが調べる実験も紹介されていました。こちらはgem本体の公開機能とは別の実験実装です。「CIに入れるだけで自動修正される」という理解ではなく、再現しにくい失敗の証拠を残す仕組みとして捉えています。
このAIが調査する仕組みをローカルのCI実行の環境で動かすのは勿体無い気がしていて、PR作成時, push時に動くCI環境上でAIを動かして調査させるというのがベストプラクティスなんじゃないかなぁと思ったり。
(Lambda MicroVms使ってやってみるかぁ)
今まではAIが「何を見てどう判断した」というところまではあまり気にしていませんでしたが、今後AIに調査を頼む際は、コードを渡すことに加え、何を観測できれば仮説を確かめられるかまで考えたいなと思いました。
自分でAIエージェント構築する時はCloudWatchで見るんですけどねぇ...
Domain Modeling with Vanilla Rails:「操作」から再考するRailsの設計論
登壇者はyasaichiさんです。セッション紹介はこちらです。
Fat Modelへの対処を、どのレイヤーに処理を移すかという問題から、何をモデルとして捉えているかという問題へ戻して考える話でした。
例えば、メールアドレスでのサインアップと、外部認証によるサインアップでは、必要な入力や検証が異なります。それでも、作成されるものがユーザーだからと、すべての処理をUserに追加していくと、操作ごとのルールが同じモデルへ積み重なります。
ControllerやModelのコードが肥大化していくのを抑えるために、処理を切り出す時の基準を掴みきれていなかったんですが、「操作ごと」って聞いた時に「あぁ...なるほど...」となりました。
そこで、ユーザーという操作対象に加えて、サインアップという操作自体をモデルとして捉えます。Form Objectやイベントエンティティも、専門のルールを専門のオブジェクトに持たせるという観点で共通しています。
特に参考になったのは、既存コードから切り出す対象を見つける手順でした。
- モデルの実装を読み、扱っている業務ルールを理解する
- 別のユースケースでも、そのルールが必要かを比較する
- 共通して必要なルールと、特定の操作でだけ必要なルールを整理する
ただ単に大きなクラスのメソッドを移すだけでなく、ルールが属する概念を見つけるためにコードを読む、という順序がよいと思いました。
また、操作のモデルを作ること = そのまま専用テーブルを増やすことではありません。Active Modelを使い、テーブルを持たないオブジェクトに検証やフォーム連携の機能を持たせる方法もあります。
なんとなく、1モデル = 1テーブルっていうイメージがついちゃうんですよね。原則というか基本線はこれなんでしょうが、モデルの肥大化を抑えるためには、この原則を逸脱することもあるよねってことなんでしょう。きっと。
自分の書いているコードはこの切り出しがうまくできていないので、Fat Modelが大量にある...ヤダァ...
PumaからFalconに移行したRailsアプリケーションでの実践
登壇者はTwoGateのHayato OKUMOTOさんです。セッション紹介はこちらです。
お子さんが産まれたとのことで、おめでとうございます🎉
前提として、TwoGateさんのプロダクトは、イベントのなどのグッズ販売などのアプリケーションを提供されているそうです。このセッションで聴いたのは、外部ID基盤との違いを吸収する認証アダプターで、PumaからFalconへ移行した事例でした。外部APIの応答が遅く、販売開始や当落発表でアクセスが集中するという背景があります。
Falconでは、Fiberを利用し、ある処理がI/Oを待っている間に別の処理を進められます。待っている時間を重ねることで、処理できるリクエスト数を増やす狙いです。
実はFiberを目にしたのは、RubyGoldの試験勉強以来でした。実際にプロダクトに組み込まれているのは初めて見た気がする。(Falconを組み込んでいるプロダクトは見たことあるから見たことあったかも?)
もともと3本の外部APIを同時実行する要件があり、移行に合わせてFaraday+TyphoeusからAsync::HTTP+Barrierへ変更していました。直列だった処理を初めて並行化したのではなく、既存の同時実行をFiber上のTaskへ移した話です。
Fiberを使っていても、1本ずつ結果を待てば直列になります。3つのTaskを起動してから完了を待つという実装が必要になる点も、理解の助けになりました。
聴講メモに残した比較結果は次のとおりです。
| 構成 | 消費CPU1コア相当あたりのRPS |
|---|---|
| Puma構成 | 21.9 |
| Falcon構成 | 84.6 |
サーバー、HTTPクライアント、並行処理の実装を含む構成全体の比較であり、Falcon単体の効果や、1リクエストの応答時間の改善率を示すものではありません。
さらに、DynamoDBへの問い合わせを行う別アプリケーションでは、同様の改善が見られなかったという結果も紹介されていました。I/O待ちが短く、待ち時間を重ねる効果が小さかったのではないか、という仮説が挙げられていました。
採用した技術名と改善値だけでなく、効果が出なかった条件まで聞けたことが参考になりました。自分のアプリケーションでも、待ち時間がどこにあり、何を改善したいのかを確認してから検討したいです。
ActionController meets Protocol Buffers…たのしいAPIスキーマ定義!
登壇者はIVRyのsorahさんです。公開スライドはこちらです。
正直なところ、聴講中はProtobuf、RPC、gRPC、Connect RPCの関係を整理するのに精いっぱいでした。というかほぼ理解が追いついていない...。後からスライドを確認し、まずそれぞれが何を担当するのかを分けると理解しやすくなりました。(間違っている気もする...)
| 用語 | 自分なりに整理(あってる?) |
|---|---|
| Protobuf | データの形を定義し、各言語のコード生成やシリアライズに使う仕組み |
| RPC | 別のサーバーにある処理を、関数やメソッドのように呼び出す仕組み |
| gRPC | RPCを実現する具体的な技術の1つ |
| Connect | Protobufを利用できる、HTTPベースのRPCプロトコルとライブラリ群 |
| OpenAPI | HTTP APIのパスや入出力などを記述する仕様 |
今回の中心は、.protoをデータ定義の元にして、Railsの入出力や保存データ、利用者向けのAPI定義につなげる構成でした。
-
.protoからRubyのメッセージクラスを生成する -
protobufableで、APIの入出力やDBのJSONデータに利用する - gnosticでOpenAPIを生成し、既存の利用者向けにも提供する
- Protovalidateで、型に加えて値の条件を検証する
つまり、Protobufを採用したからJSON APIやOpenAPIをやめる、という話ではなかったです。レビューして合意する元の定義をProtobufに置き、必要な形式へつなげています。
RPCについては、connect_rpc_railsで通常のActionControllerのアクションとして処理し、Railsのコールバックやconcernsを活かす構成が紹介されていました。このライブラリで扱うConnectの単発RPCと、gRPCやストリーミングへの対応は分けて理解する必要があります。
関連コードはprotobufableとconnect_rpc_railsで確認できます。用語の背景にはProtobuf公式とConnect公式も参考になりました。
RailsのHot Reloadに乗せられない?
発表では、生成したProtobufコードをRailsのHot Reloadに乗せられないという課題も紹介されていました。
Railsの開発環境では、変更後のリクエストに向けてアプリケーションのクラスを読み直せます。一方、Protobufの生成コードには、プロセス全体のdescriptor poolへスキーマを登録する処理があります。同じ定義を再登録すると問題になるため、.protoを変更して再生成したときにはプロセスの再起動が必要になります。
普段は便利に使っている再読み込みも、外部の仕組みが保持する状態まで自動的に更新するものではない、と理解するきっかけになりました。
小さく作ってわかるRailsの仕組み〜mini-rails〜
登壇者はソニックガーデンのNoboさんです。セッション紹介はこちらです。
Railsを参考に、小さなフレームワークであるmini-railsを作った話でした。リクエストを受けてからレスポンスを返すまでを、小さな実装で追うという学び方をされているそう。
HTTPリクエスト→Rack→Router→Controller→View→Response
Autoloadによって明示的なrequireを書かずに使えるものがあり、before_actionもRailsと同様の書き方で利用できるようになっていました。
確かに、Railsフレームワーク全体を読んでいくのは大変だけど、mini版として似たようなものを作っていくのは勉強になりそうだなぁと思っています。mini-railsのGithubリポジトリはまだ公開されていないとのことでしたので、公開されたら読んでみようかしら。
Railsのためのパスキー実践入門〜マルチテナントSaaSでの意思決定〜
登壇者はSmartHRのutakahaさんです。セッション紹介はこちらです。
パスキーの暗号処理だけでなく、マルチテナントSaaSの認証として何を判断するのかが印象に残りました。
まず、登録と認証の流れを整理すると、次のようになります。
- 登録時に鍵ペアを作り、サービスへ公開鍵を登録
- ログイン時に、サービスがその認証用のchallengeを発行
- 認証器が秘密鍵で署名し、サービスが登録済みの公開鍵で検証
これは簡略化した説明なので、色々端折ってますが、実際にはchallenge、origin、RP IDなどの検証も必要です。WebAuthn仕様やwebauthn-rubyで、サーバー側が担う検証も確認できます。
RP IDをどこに置くか
RP IDをどこに置くかのお話をされていましたが、このあたりを書いてしまうと、セキュリティ周りが...って感じなので省略します。
ただし、認証・認可の過程で、Railsアプリケーション側のDBと照合して判定をするケースがあるようです。これはどの部分を大事にするかによって変わってくるものかなと思っています。
ログインできることに加え、使いやすさまで設計する
ログイン画面では、パスキーをオートフィル候補に出すConditional UIと、専用のログインボタンを併用していました。候補の表示による使いやすさと、パスキー対応の周知や環境差への対応を組み合わせた設計です。
「パスキーを使ってログインする」のボタンを周知の役割にするっていうのは賢いなぁと思いました。
複数の認証器を使い分けることを想定し、登録数の上限は15個とし、認証器の種別を示すAAGUIDを初期の名前付けに使います。登録後に利用者が名前を変更できることも含め、管理する場面まで考えられていました。
これらの判断は、登壇者本人の技術記事でも確認できました。
また、セッションでは既存のSAMLや2要素認証との関係も扱われていました。聞き取った範囲では、パスキーログイン時の追加認証を省く判断と、テナントが求める2要素認証の設定を保持することを分けていました。
追加で調べたこと:HerbとReActionViewはSlimでも使えるのか
自分は直接聞かなかったセッションなのですが、Marco RothさんのHerbのセッションの反響がX上でかなり凄かったように見えたので、調べてみました。
Herbは、HTMLとERBを一緒に解析するパーサーや、Linter、Formatterなどの基盤です。HTMLタグとRubyの分岐を含む構造を理解することで、テンプレートの検査や編集支援につなげます。Herb公式に概要があります。
ReActionViewはその基盤をRailsのビューへ組み込み、開発時のエラー表示や、状態に応じた画面の部分更新などを提供します。機能ごとに安定度や導入条件を確認して検討したいです。
気になったのは、Slim形式で開発しているアプリケーションへの導入です。調べた範囲では、既存の.html.slimをそのままHerbで解析する公式対応はありません。ReActionViewの公式概要でも、Slimなどのビューは対象外とされています。
slimに対応していない...無念...
Slimが最終的にHTMLを出力しても、Herbが必要とする元のテンプレートの構造がそのまま渡るわけではありません。
試すなら、まず一部の画面をHTML+ERBのテンプレートへ移さなきゃいけなさそう...はぁ...
これから試してみたいこと
- テストの計測:TestProfでFactoryの生成回数と時間を見て、不要な関連生成や共通化できる準備処理を探してみる
- AIの調査環境:小さな開発用Railsアプリでdebug-mcpを試してみる
- モデルの責務整理:既存モデルのルールを拾い、操作ごとに必要なものと共通するものを分別する
- 仕組みの理解:mini-railsのリポジトリが公開されたらコードを読む
当日は理解が追いつかなかった話もありましたが、メモを公開資料で補うことで、用語だけ知っていた技術のつながりを整理できました。
最後に
「ここ違うよ!」とかあれば、コメントください!
久々にRuby, Railsに染まった!楽しかったです!
