広告DMPの開発者がKaigi on Rails 2024に参加した話




## はじめに
※ この記事は、[Supershipグループ Advent Calendar 2024](https://qiita.com/advent-calendar/2024/supership) の5日目の記事になります。


こんにちは。Supership社で広告DMPプロダクト [Fortuna](https://supership.jp/business/fortuna/) の開発をしている jo です。
最近念願のアーロンチェアを購入し、骨盤からデスクに向かって業務に臨んでいます。


# Kaigi on Rails 2024とは？

さて、今日は **Kaigi on Rails 2024** について紹介します。
**Kaigi on Rails 2024** は、東京有明で2024年10月25日・26日に開催された、
Ruby on Rails を中心とした技術カンファレンスです。

https://kaigionrails.org/2024/

その内容は、公式サイトに
* 『Kaigi on Railsのコアコンセプトは 「初学者から上級者までが楽しめるWeb系の技術カンファレンス」 です』
* 『Kaigi on Railsは技術カンファレンスへの参加の敷居を下げることを意図して企画されています』

とあるように、
* 日々の業務にすぐ取り入れられる実践的な Rails の内容と
* 初学者から楽しめるような入りやすい雰囲気の

両方を楽しめるカンファレンスです。

**Supership社のエンジニア学習支援費の制度** を使って参加してきたので、その参加録です！


# 今回書く内容
とはいえ、2日間で30以上もの講演がある Kaigi on Rails。

今回は視聴した講演のうち、
**「後日持ち帰った際、自社の開発チーム内で特に議論を巻き起こした発表」** について
紹介させて頂きます。

全部で3つです。

- ① [基調講演](https://kaigionrails.org/2024/talks/palkan/)（Palkanさん）
- ② [Sidekiqで実現する長時間非同期処理の中断と再開](https://kaigionrails.org/2024/talks/hypermkt/)（hypermktさん）
- ③ [Data Migration on Rails](https://kaigionrails.org/2024/talks/ohbarye/)（ohbaryeさん）

:::note
2024/12/05 執筆時は、残念ながら講演のアーカイブ動画等は出ておりません。
ただし、発表スライドはほぼ公開されているので、ぜひお手元でも確認してみてください！
:::


## ① 基調講演 "Rails Way, or the highway"
### 発表概要
Day 1 最初のPalkanさんの基調講演。発表スライドは [こちら](https://speakerdeck.com/palkan/kaigi-on-rails-2024-rails-way-or-the-highway)。

![beauty_1729823289206.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214319/926dbbaf-9c1e-3efe-2b1c-35f1c9acba14.jpeg)


<details><summary>ざっくり要約するとこんな感じ</summary>

#### Rails の開発体験の話
- Rails は **Hello World** から **IPO** までサポートすると主張
- 特に Rails 8 は Hello World から最初バージョンまでのスピード重視（ゼロイチ）
- が、「イチ」と IPO の間には無限のステップがある。Rails は本当にカバーしてくれるのか…？

#### 私たち Rails 開発者は、しばしばフレームワークを歪めてしまう
- 煩雑なロジックの置き場所
- 様々な機能に対応するための、様々な Gem の導入で

#### じゃあどうする？
- “Master & **extend** Rails” 「Railsを習得し、**拡張**する」
- Master
    - Railsのシンプルな設計パターンを学ぶ
- Extend
    - 各ユニットの分離。新しい抽象化によって、担当分野を分けよう

#### Extend = **抽象化レイヤーの導入**
- Railsらしい開発者体験に沿う（ベースクラスの継承など）
- 抽象化レイヤーの間に、明確な境界を引く
- 既存のコードのなかで抽象化できることを探そう
- 複雑なロジックは、分けたところにおこう

</details>

### チームの課題と
私の所属する Fortuna プロダクトの Rails アプリケーションは、
約7年以上前から開発されている中堅そこそこサイズのアプリケーションです。

Rails の MVC に乗り切らないロジックも多数存在し、それらのコードベースは全て
`lib/classes/` ファイル配下に切り出し、クラス定義しています。

長年のメンテナンスで、一応「抽象化レイヤー」たる `lib/classes/` はありつつも、
**配下のファイル切り分けや、クラス命名はまちまち**。
また、ベースクラスを用意・継承しているクラスは多くありませんでした。

### 議論
そんな中、発表についてチームメンバーで議論し、
* 「機能別に、例えばAとBという抽象化レイヤーで切り分けてみてもいいかもね」
* 「xx、みたいなベースクラスを定義してもいいかもね」

といった発言が活発に上がっていて、コードベースの見直しにつながりました :tada:

▶️ 当日の議事録を一部抜粋
![スクリーンショット 2024-12-02 15.25.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214319/eb693b80-faad-07d1-93fe-6e38af00b6b3.png)


### まとめ
昔のメンバーによって定義され**なんとなく**で実装を続けていた「抽象化レイヤー」ついて、今現在のメンバーで活発な議論を巻き起こす良いきっかけとなりました！
Palkanさん、ありがとうございます。





## ② Sidekiqで実現する 長時間非同期処理の中断と再開
### 発表概要
こちらも Day 1 の発表から。hypermktさんの講演になります。
スライドは[こちら](https://speakerdeck.com/hypermkt/pausing-and-resuming-long-running-asynchronous-jobs-with-sidekiq)。

<details><summary>ざっくりとした要約</summary>

#### 長時間ジョブがあるプロダクトで、デプロイする辛さ
- データや処理の不整合
- 実行時間の増加（最初から再実行になる）
#### 中断処理・再開処理が欲しい！
- 中断：Sidekiqのプロセス停止を検知して、任意のタイミングで処理を停止
- 再開：中断した箇所から継続再開できること

#### 具体的な実装の仕方
- 長期実行ジョブのループ処理内部等に、Sidekiqの停止を検知するメソッドを埋め込み
- Sidekiqが停止された時には例外を発火
- 中断した場所（ID番号 or 行番号）をRedisに保存
- Sidekiq再開時に、中断した場所を見てそこから処理を再開する


</details>

### チームの課題との親和性
Fortuna アプリケーションでは、Rails 上で動く Sidekiq の非同期処理ジョブから、
各種環境（GCP・AWS）のデータ分析基盤を実行しています。

特に、GCP 上のデータ基盤 ([Dataproc](https://cloud.google.com/dataproc/docs/concepts/overview?hl=ja)) の最大クラスター数にコスト的制約があり、
数千万・数億行のテーブルへの無邪気な HiveQL クエリ等を実行されてしまうと、
処理が詰まって失敗してしまうこともしばしば。

開発メンバーがデプロイ作業をする際は、まさにSmartHRさんと同じような運用をしていました😭
![スクリーンショット 2024-12-02 16.18.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214319/7afca1c0-302b-825d-6afc-e55c33f1829f.png)

(ref. https://speakerdeck.com/hypermkt/pausing-and-resuming-long-running-asynchronous-jobs-with-sidekiq?slide=15)

### 巻き起こった議論
#### 我々のプロダクトではhypermktさんのノウハウは直接は活かせなそう
- 我々のプロダクトは、Sidekiq から外部のデータ基盤（GCP・AWS）を実行
- 長時間かかってしまうのは、それらデータ分析の処理（特にDataproc）
- そのため、Ruby・Railsのジョブそのものに中断・再開処理は仕込めない

#### Sidekiq ↔︎ Dataprocの呼び出し方は改善の余地あり
* 現状、Sidekiq のプロセス停止時に、呼び出し先の Dataproc も kill しているはず
    * せっかく途中まで進んだ Dataproc の処理を無駄にしていそう
    * kill されきれてない Dataproc 孤児👶プロセスもありそう
* Dataproc 実行プロセスの情報を保持するデーモンを作って、再開時に同じジョブを引けたら、使い回せそう

#### 中断・再開ではなく、子の処理をさらに Sidekiq ジョブで非同期実行しては？
- 既に Sidekiq を入れ子にして子の処理をバラバラに実行させてはいる
    - ループしていた各処理を、バラバラにキューに入れて実行
    - 直列ではなく並列で
- そうすると、リトライは Sidekiq に任せられる
    - 中断されたとしても、最小単位で止まるので、ダメージは小さい

#### (余談) Dataproc から Big Query に移行できたら解決する説
* コスト要因で、Dataproc の最大クラスター数を上げられないのが、そもそも原因
* オートスケーリングでささっと終わる、Big Queryなら悩む必要ないかも？
  * 従量課金制の恐ろしさはあるけれど
  * Big Query を「銀の弾丸」扱いしすぎないよう注意


### まとめ
Sidekiqの長時間実行ジョブの日々の苦労もあってか、
こちらの講演についても、白熱した議論が巻き起こりました。

チームメンバーで直近の課題感を合わせ、解決案の議論までできたこと、
hypermktさんに感謝です！



▶️ チームでの議論の議事録
![スクリーンショット 2024-12-02 16.30.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214319/e44161f7-d2ab-36bf-2e44-23b244c16f09.png)





## ③ Data Migration on Rails
### 発表概要
最後に紹介するのは、ohbaryeさんの講演です。

"Data Migration" とあるので、`db:migrate` 関連の話と思われるかもしれませんが、
本公演は database migration の話ではなく、既存のデータそのものの移行・変更についてでした。

```
x database migration
○ data migrate
```

個人的には **「データケア」** と捉えると、理解しやすかったかと思います。
発表のスライドは[こちら](https://speakerdeck.com/ohbarye/data-migration-on-rails)。


<details><summary>ざっくり概要</summary>

#### data migrate に関する課題感
![スクリーンショット 2024-12-04 10.31.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214319/9992928f-5523-441b-d495-27cf73231194.png)

（ref. https://speakerdeck.com/ohbarye/data-migration-on-rails?slide=74）

#### 代表的なアプローチ
- SQL直接操作
- rails console, rails runnerを直接操作
- db:migrateと同時実行
- rake task, ruby script
- 専用Gem

</details>



### チームの課題との親和性
#### 既存の運用
Fortuna アプリケーションでも、特定の環境の一部データだけ更新したいというケースはしばしば。その際は、

* runner タスクで Ruby ベースのコードを用意
* Pull Request 化して他メンバーからレビュー
* Approveされたらマージ。担当者が本番環境に入って、手動実行
* 作成した runner タスクは、削除したりしなかったり

といった運用を取っていました。

ohbaryeさんの講演でいう、4番目の `「rake task, ruby script」` に近しい運用かと思います。

#### 課題感
上記運用では、メンバー間のレビューもあり、実行したスクリプトのログは残る状態です。
ただし、課題感も山積していました

* runner スクリプトの命名・コード規約がないため、似たような名前のタスクが複数存在
* runner ファイル名にタイムスタンプがなく、どのファイルがいつ実行されたものか、Git history を漁らないと分からない
* 使い終わった runner を削除するルールが明確化されていなく、中途半端に消したり残したりしている

#### 巻き起こった議論
* 命名規則、削除のルールはチームで明確化しよう
    * コードベースに残った、もう使わない runner を削除しよう
    * runner タスクのファイル名には、必ずタイムスタンプをつけよう
    * 使い終わった runner は、必ず削除するようにしよう

一旦は上記の運用ルールを試してみて、今後また振り返った際に、必要に応じて Gem 導入も考慮しよう、といった結論に至りました。

▶️ 議論の様子
![スクリーンショット 2024-12-04 14.52.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/214319/235775c5-483d-410b-aaf8-82a1e8cae51b.png)


### まとめ
ルールが明確化されず、なんとなく課題感は感じていた Data Migration の運用ルールについて、
こちらの講演が、メンバー間での議論の発端となりました。

発表いただいたohbaryeさんに感謝です。


## 全体のまとめ
さて、ここまで長く書きましたが、　Kaigi on Rails 2024に参加した全体の感想として、

**「自分達の Rails プロダクトの
　<ins>普段、課題感は感じつつもなんとなくスルーしていた内容</ins> について、
　メンバー間で議論し、課題意識や解決策を共通認識化できた」**

と感じます。

このように議論・学習の契機となった Kaigi on Rails、ぜひ来年以降も参加したいです！
運営や発表者の皆様、ありがとうございました。

:::note info

最後に宣伝です。

Supershipではプロダクト開発やサービス開発に関わる人を絶賛募集しております。
ご興味がある方は以下リンクよりご確認ください。
[Supership 採用サイト](https://supership.jp/recruit/)
是非ともよろしくお願いします。
:::