Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Ruby on Railsで持続可能な開発を行うために取り組んでいること
Search
AK
March 01, 2025
Technology
3
220
Ruby on Railsで持続可能な開発を行うために取り組んでいること
TokyoWomen.rb #1の登壇資料です。
https://tokyowomenrb.connpass.com/event/342573/
AK
March 01, 2025
Tweet
Share
More Decks by AK
See All by AK
クラシルの現在とこれから
am1157154
1
1.2k
Other Decks in Technology
See All in Technology
職種に名前が付く、ということ/The fact that a job title has a name
bitkey
1
250
PostgreSQL Unconference #52 pg_tde
nori_shinoda
1
230
ひまプロプレゼンツ 「エンジニア格付けチェック 〜春の公開収録スペシャル〜」
kaaaichi
0
150
チームの性質によって変わる ADR との向き合い方と、生成 AI 時代のこれから / How to deal with ADR depends on the characteristics of the team
mh4gf
4
340
年末調整プロダクトの内部品質改善活動について
kaomi_wombat
0
210
AWS のポリシー言語 Cedar を活用した高速かつスケーラブルな認可技術の探求 #phperkaigi / PHPerKaigi 2025
ytaka23
8
1.5k
Proxmox VE超入門 〜 無料で作れるご自宅仮想化プラットフォームブックマークする
devops_vtj
0
160
DevOps文化を育むQA 〜カルチャーバブルを生み出す戦略〜 / 20250317 Atsushi Funahashi
shift_evolve
1
110
ソフトウェアプロジェクトの成功率が上がらない原因-「社会価値を考える」ということ-
ytanaka5569
0
130
KCD Brazil '25: Enabling Developers with Dapr & Backstage
salaboy
1
130
Symfony in 2025: Scaling to 0
fabpot
2
210
問題解決に役立つ数理工学
recruitengineers
PRO
7
2.3k
Featured
See All Featured
Build your cross-platform service in a week with App Engine
jlugia
229
18k
A designer walks into a library…
pauljervisheath
205
24k
BBQ
matthewcrist
88
9.5k
Visualization
eitanlees
146
16k
The Language of Interfaces
destraynor
157
24k
Visualizing Your Data: Incorporating Mongo into Loggly Infrastructure
mongodb
45
9.5k
Fight the Zombie Pattern Library - RWD Summit 2016
marcelosomers
233
17k
Raft: Consensus for Rubyists
vanstee
137
6.9k
Creating an realtime collaboration tool: Agile Flush - .NET Oxford
marcduiker
29
2k
Learning to Love Humans: Emotional Interface Design
aarron
273
40k
4 Signs Your Business is Dying
shpigford
183
22k
What's in a price? How to price your products and services
michaelherold
245
12k
Transcript
Akina Matsushima 2025/03/01 TokyoWoman.rb #1 Ruby on Railsで 持続可能な開発を行うために 取り組んでいること
松嶋 瑛奈 (Matsushima Akina) dely株式会社 バックエンドエンジニア • 2019/11~: 現職にSREとして入社 •
2022/10~: バックエンドエンジニアに転向 • Ruby/Rails歴3年目 💎 • Kaigi on Rails 2024のスポンサーLTが初登 壇、 今回で2回目です! 📣 自己紹介 @25_aaa 3 @akingo55
None
None
今回のテーマは、「持続可能な開発」
持続可能な開発? 🤔
プロダクトの性質やフェーズにあわせて、 「品質」と「開発速度」のバランスを取る こと
バランスを取りやすくするためには、 どうすればいいのか?
不要な複雑さを減らし、ソフトウェアを 「単純」にすること
今日話すこと 1. デッドコードを定期的に削除している話 2. Datadog APMを用いてパフォーマンス改善している話 💡 9年目を迎えたRailsアプリケーションを運用する中で、私たちがソフト ウェアを「単純」にするために取り組んできた2つのことについて話します。
1.デッドコードの削除 🧹
消そう。以上。 実行されないコードは消すだけだ。 引用:「Tidy First? 2章 デッドコー ド」
なぜ不要なコードが蓄積されてしまうのか? • 時間を捻出できない ⏰ ◦ 普段は機能開発に追われているため、改善系のタスクに着手する時間がとれない ◦ 改善チームやPjTを立ち上げられたらいいが、そもそも人手不足 • 後回しにして忘れ去られてしまう
◦ とりあえずバックログに入れるが、優先度低くて一生やらないタスクになる ◦ そして忘却の彼方に • そういう文化がない 😢 ◦ 機能開発こそが価値を生むものだなど、運用を軽視する文化が根強いと放置されがち ◦ 誰かが声を上げない or 障害が起きて大惨事にならない限り変わらない
私たちの解決策 • 時間を捻出できない ⏰ or 後回しにして忘れ去られてしまう ◦ 機能開発が落ち着く年末に、早めにコードフリーズして時間つくる(去年は12/19) ◦
高頻度である必要はないし、年に1回程度だと調整・説得しやすい ◦ 誰でも運用を回せるように、あらかじめ削除フローは整備しておく ◦ 年1回のコードの大掃除としてイベント化する ▪ 「年末 = 大掃除」のイメージがあるので定着しやすい • そういう文化がない 😢 ◦ 一朝一夕で文化は変わらない ◦ 強い気持ちで、根気強く地道に浸透させていくしかない
どのような手段を使うか? • 動的解析ツールを使って、プロダクションコードの使用率を計測す る (ex. coverband) • 静的解析ツールを使って、ソースコードから使われていないメソッ ドやクラスを抽出する(ex. debride)
• プロダクション環境のアクセスログからAPI単位で不要なコードを抽 出する
どのような手段を使うか? • 動的解析ツールを使って、プロダクションコードの使用率を計測す る (ex. coverband) • 静的解析ツールを使って、ソースコードから使われていないメソッ ドやクラスを抽出する(ex. debride)
• 👉プロダクション環境のアクセスログからAPI単位で不要なコード を抽出する 既存のログ基盤を活用できること && 年1回の運用なので運用コストが 一番少ない方法を選択
何を消していくのか? • サポート対象外のバージョンで使われていたモバイルのAPI • 機能として既に存在しないWebのAPI • 誰も使わなくなった社内の管理サイトの機能 ◦ 1年以上アクセスがないページや使われた痕跡がない機能は基本的に削除する •
運用が既に止まっているrakeタスク • 不要なバッチ処理 ◦ 効果の薄いプッシュ通知、誰も見ていないSlack通知 etc.
削除フロー例 1. 現在使われているAPIのパスとメソッド一覧をペアにしてCSV形式で出力 a. モバイルAPIはモバイルエンジニアに依頼する b. アクセスログから抽出する 2. ActionDispatch::Routingで出力したルーティング一覧と照らし合わせ る
※削除対象のAPIを抽出するスクリプトをチームで使い回せるようにしてい るが、年1回の実施なので完全自動化まではしていない
コードの大掃除の効果 • 毎年1万弱のコードが削除されている ◦ 2024年は約9200行削除できた 🎉 ◦ 年1運用なので、負担も少なく継続しやすかった • CIの時間が短くなる
◦ CIの時間を短縮するTipsは様々あるが、コード削除だけでも1分以上短くできる • 年末早めのコードフリーズで、運用や改善タスクを実施する時間も割 けるようになった ◦ gemのバージョンアップ ◦ APIのパフォーマンス改善 ◦ 後回しにしていたアプリケーションエラーの解消等
2. パフォーマンス改善 💨
そもそも何でパフォーマンスを改善するのか? 理由は以下の3つしかないと言われている 1. 顧客体験を向上させる 2. 運用コストを減らす 3. トラフィック増加による障害を防ぐ 引用:「Ruby on
Rails パフォーマンスアポクリファ 第1章」 • 現代のWebアプリケーションは、高速であることが「当たり前」 • Googleの研究によると、検索結果の表示が100ms~400ms遅くなるだけ で0.2~0.6%の利用ユーザーが減少したと報告されている 引用:https://research.google/blog/speed-matters/
パフォーマンス改善のお作法 • 推測するな、計測せよ && まずボトルネックを解消せよ ◦ APMを導入し、トレースデータを活用すると改善が捗りやすい(Datadog, NewRelic etc.) ◦
パフォーマンスの良し悪しを判断する指標があるとベター(SLOなど) • ダッシュボードを作成し、パフォーマンスを可視化する ◦ 作っておしまいにならないことが大事!!! ◦ 弊社の場合 ▪ 週次のサーバーサイド定例でダッシュボードを眺める時間を確保 ▪ 短期と長期の観点で見て異変がないか ▪ 改善が必要と判断されたものはチーム単位で改善タスクとして積む
効果的にパフォーマンスを改善するには? 🌟 最もユーザー体験の改善に繋がるものから順番に改善していく! どんな指標をもとに判断すればいい? • 99パーセンタイル値のレイテンシが悪い順? • リクエスト数✕平均レイテンシの値が悪い順?
個人的におすすめなやり方 • レイテンシの閾値を設定し、エン ドポイントごとにこの閾値を超え た回数をカウントする • その回数が最も多いエンドポイン トから改善していく • ユーザーに負の体験を与えている
ものから効果的に改善できる 実際のDatadogのダッシュボードから抜 粋
実際の改善事例の紹介 🐶
事例①:eager_loadの罠 • ページングありで取得するレコード数も制限されている • N+1対策のためのeager loadもしていて問題なさそう ・・・? • 早いときもあるし遅いときもあるぞ
事例①:eager_loadの罠 • レシピに紐づくユーザーのレーティングに関するレコードが膨大 になっていた • 人気なレシピの場合、レーティングが数万件ついてることも ・・・ 👈 犯人!
事例①:eager_loadの罠 • SQL実行時に ActiveSupport::Notifications経由で instantiation.active_recordイベントを取 得しているので、トレースデータのスパンタグ にセットされる • SQLの実行には取得レコード数が増えても 0.1s以下だが、ActiveRecordはインスタン
ス化するのに時間がかかってしまう
事例①:改善方法 UserRatingはリアルタイムに取得する必要はないので、recipesテーブル にuser_rating_countカラムを追加、バッチ処理で更新するスタイルに変 更 • その結果、P99の値が平均して1/10まで減少した 👏 • includesメソッドは便利で容易に使いがちだが、取得されるレコー ド数も考慮にいれないとパフォーマンスに影響する
✏
事例②: IN演算子の使い方には気を付けよう • あれ、謎の空白が目立つな? • トレースデータに何も表示されず、何が起きてるのか分からない • 発行されているSQLはINNER JOINしているな •
SQLも改善できそうだけど、空白の部分の時間が長すぎるぞ
事例②: IN演算子の使い方には気を付けよう ①で取得したIDを②のクエリのIN演算子に渡しているので、インスタンス化する時に オーバーヘッドが生じてそう 🤢(JOINするとトレースに表示されない ⚠) ① ② IN演算子に大量のIDが渡っ てきているこれは・・・
😇
事例②: IN演算子の使い方には気を付けよう • 初期からある内部リンク用API で、ロジックの見直しは今まで されていなかった • 記事に関連するレシピを取得し ているが、MIN_LIMITだけ決 めて、MAX値を決めてなかった
のでIN演算子に大量のIDを渡し てしまっていた • IN演算子も大量の要素を渡して しまうと、インデックスが使わ れずフルスキャンが走る可能性 があるので注意!
事例②: 改善方法 IN演算子に渡すID数に制限を設け、オーバーヘッドをなくす 全体で見ると1/10、クエリの速度は1/20まで改善 🎉 ① ②
事例③:効果的なインデックス貼れてないかも・・・ • 複数のテーブルをINNER JOINいるが、最適なインデックスが存在していな いことで、非常に遅いクエリが実行されていた 😇
事例③:効果的なインデックス貼れてないかも・・・ • explainで実行計画見ると、一番 カーディナリティの低いインデック スが使用されていた • そのインデックスは消去法で選択さ れており、他に使われている箇所は なく、有用なインデックスではな かった
• sys.schema_index_statisticsで インデックス使用率見れるよ (MySQL)
事例③:改善方法 • 不要なインデックスは削除し、WHERE句で指定されているカラムで複合インデッ クスを貼ることで改善した(2.61s → 347ms) • 複合インデックスは左から順に使われるので、WHERE句に指定する順番には注意 ⚠(leftmost prefixルール)
• Railsだとscope使うときにインデックスがどう貼られているか気をつけると
改善結果 • 他にもエンドポイントごとに様々な改善を実施した ◦ APIのレスポンスデータは余分なものを減らし、必要最低限なものだけ 返すようにしたり ◦ 過剰に発行されているクエリを削減したり ◦ 過度なDRYによって、非効率なクエリが発行されているコードを最適
化したり etc. • 最終的に、全体のP99.9の値が800-900msから300ms台まで減らせた 🎉
まとめ • プロダクトの品質と開発速度のバランスを取ることは難しいですが、ソフ トウェアを単純にしていくことで、両者のバランスは実現可能 • 単純さの追求は、Railsアプリケーションを安全に楽しく開発できること にもつながるよ • そのための手段として、「デッドコードの削除」や「パフォーマンス改 善」を効果的に行うための事例を紹介しました
• 年末のコードのお掃除会、おすすめなのでぜひ! • APMはそれなりに高いけどパフォーマンス改善が捗るし、どの部分がボト ルネックになりやすいのか理解が深まるのでおすすめ!
ありがとうございました!