Kaigi on Rails 2023参加レポート:学びからプロジェクトへの応用まで

こんにちは!株式会社High Link プロダクト開発エンジニアのタイガです。 2023年10月27日と28日に行われた Kaigi on Rails 2023 に参加しましたので、その感想などをレポートしていきます。 最後にはトークセッションの内容から実際にプロジェクトに対して実践してみたいと思います。

そもそも Kaigi on Rails とは?

Kaigi on Railsのコアコンセプトは「初学者から上級者までが楽しめるWeb系の技術カンファレンス」です。Kaigi on Railsは技術カンファレンスへの参加の敷居を下げることを意図して企画されています。また、名前の通りRailsを話題の中心に据えるカンファレンスではありますが、広くWebに関すること全般(例えばフロントエンドやプロトコルなど)についてもカバーすることで参加者の知見を深め、また明日からの仕事に役立てていただければと考えています。 (https://kaigionrails.org/2023より引用)

Ruby on Railsを中心としたウェブ開発技術に関する技術カンファレンスで、ウェブ開発の初心者からベテランまでが交流し学び合える場のようです。

会場の雰囲気

2020年から開催されている当イベントですが、ご時世もあり今回が初のオフライン開催。

出展されているブースはどれも工夫が凝らされていて、 出展企業のサービスに関わるアンケートやRuby on Railsの挙動に関するクイズの回答を行うと景品がもらえるブースやくじ引きを行えるブースがあり、トークセッションの休憩時間も常に盛り上がっていました。

ちなみに我がCTOはコーヒーの飲み比べチャレンジで見事コーヒー豆をゲットしていました。

ズラッと並ぶノベルティ

じゃがりこまで!

トークセッション

Kaigi on Railsでは2日間で36ものトークセッションが開催されました。

その中でも印象に残った2つのトークセッションについて感想を書きたいと思います。

5000件のN+1問題と戦っている話

このセッションでは、N+1問題の基本から、その解決策、問題を見つける方法までを最初に丁寧に解説してくれたことで、内容に深く入り込むことができました。特にBulletの設定とRspecを用いてN+1問題の検出する方法は知らなかったので、良い学びでした。

大量のN+1に対して機械的に対応できる gemを作ろうとする中でどの層(ビュー、コントローラ、モデル)で includesメソッドを使用するかという課題へのアプローチとして、日常的に直面するN+1問題にどう対応しているかという基本的な思考へと立ち返ったというお話は非常に参考になりました。機能が複雑になりすぎたり、過剰に考えてしまって行き詰まる経験は、私たち全員に共通するものです。

またそういった技術的にどう解決していくかだけでなく、チームの状況などを踏まえて、どう課題と向き合っていくかをお話されているのがためになると感じました。

ペアプロしようぜ 〜3人で登壇!? 楽しくて速いペアプロ/モブプロ開発〜

思わず「ペアプロしようぜ」って気持ちになれるようなペアプログラミングの真の効果と楽しさを再確認させてくれるエネルギッシュな発表でした。お互いが課題とコードに対して共通認識ができているので実装完了がほぼマージになるのがペアプロならではの利点だと思います。

個人的にはペアプロめっちゃ疲れるという思いがあったんですが、時間を決めてドライバーとナビゲーターを交代するとか、当たり前だけど休憩を挟みましょうっていうルールを設けて行うというのは、おっしゃる通りで良いアプローチだと思いました。 特に技術力に差があったりするとドライバーの人が全コード書いてしまって、ナビゲーターは画面共有されたVSCodeを見ているみたいなことになりがちで、バランスを取りやすい方法があると実践しやすそうです。

個人的にはざっくりしたコードの方針まではペアプロでやって、最初に共通認識を作ってしまうとこまでをペアでやるだけでもすごく効果があると思っています。即マージまでは行かないですが手戻りが少なくておすすめです。

ライブコーディングでの実践はなかなかハラハラしましたが、プレゼンがとても上手で楽しく見れるセッションなので、ぜひアーカイブを見てみてほしいです。

早速実践してみた

カンファレンスに参加して学んだことを活かすためには、やはり自分たちのプロジェクトに対して実践してみるのが一番ですね。 今回は 「5000件のN+1問題と戦っている話」を参考にして、プロジェクトからN+1を減らしてみたいと思います。

まずは今回学び得た Bulletの設定を以下の設定に変更してテストを実行してみます。

Bullet.raise = true #これによりN+1クエリがあるとテストが失敗する

当然 mainブランチは通常オールグリーンの状態なので、赤く表示された部分が N+1が発生している箇所だとわかります。

このエラーの中からN+1の原因を特定し一つ修正してみたいと思います。

N+1問題の特定

プロジェクトのコードを共有することができないので、今回は例として構造的に類似しているモデルをここに示し、問題点を説明します。

以下のようなユーザー、チケット、そしてコンサートのモデルとメソッドを定義します。

class User < ApplicationRecord
  has_many :tickets

  # このユーザーが購入した全てのチケットのコンサートの価格の合計を計算
  def sum_ticket_prices
    tickets.sum { |ticket| ticket.price }
  end
end

class Concert < ApplicationRecord
  has_many :tickets
end

class Ticket < ApplicationRecord
  belongs_to :user
  belongs_to :concert

  delegate :price, to: :concert
end

ユーザーが購入したチケットのコンサート価格の合計を計算するメソッドは、 以下のようにシンプルに見えますが、ここでN+1が発生していました。

# このユーザーが購入した全てのチケットのコンサートの価格の合計を計算
def sum_ticket_prices
  tickets.sum { |ticket| ticket.price }
end

チケットモデルを詳しく見ると、チケット自体は価格を持たず、delegateを通じて関連するコンサートの価格を取得していることが分かります。このため、sum_ticket_prices メソッド内で各チケットの価格を計算する際に、コンサートのデータを呼び出すためのクエリがチケットごとに発生してしまいます。典型的な N+1問題ですね。

class Ticket < ApplicationRecord
  belongs_to :user
  belongs_to :concert

  delegate :price, to: :concert
end

トークセッションで学んだように、この問題を解決するためには、関連データの事前読み込みが有効です。includes メソッドもこの目的で使用できますが、発行されるクエリがコード上から直感的に理解しにくいという問題があります。

このため、より直接的な事前読み込みを実現する preload を選択することにしました。

# このユーザーが購入した全てのチケットのコンサートの価格の合計を計算
def sum_ticket_prices
  tickets.preload(:concert).sum { |ticket| ticket.price }
end

これで N+1が解消されました。

終わりに

初めて参加したKaigi on Railsでしたが、セッション内で実際のプロジェクトに近いコードを用いて説明してくれることが多く、そのおかげなのか参加したエンジニアメンバー全員が関わっているプロジェクトで早く試してみたいというような会話が生まれているのが印象的でした。 また、技術的な話だけではなくプロジェクトを推進するための個人やチームの心構えなどについても発表しているセッションが多かったのも、このカンファレンスの特徴だと思いました。

次回は会社でブースを出したい!と個人的には思っています。 楽しみに待っていてください。

High Linkに興味持ってくださった方はぜひお気軽にお話ししましょう。

herp.careers