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
実録レガシー Rails アプリ改善ジャーニー / Legacy Rails app impr...
Search
shutooike
March 25, 2023
Programming
3
850
実録レガシー Rails アプリ改善ジャーニー / Legacy Rails app improvement journey
第90回 Ruby関西 勉強会で発表したスライド資料です!
https://rubykansai.doorkeeper.jp/events/150547
shutooike
March 25, 2023
Tweet
Share
Other Decks in Programming
See All in Programming
もう少しテストを書きたいんじゃ〜 #phpstudy
o0h
PRO
17
4k
Learning Kotlin with detekt
inouehi
1
130
メンテが命: PHPフレームワークのコンテナ化とアップグレード戦略
shunta27
0
300
『テスト書いた方が開発が早いじゃん』を解き明かす #phpcon_nagoya
o0h
PRO
8
2.4k
なぜイベント駆動が必要なのか - CQRS/ESで解く複雑系システムの課題 -
j5ik2o
14
4.6k
CI改善もDatadogとともに
taumu
0
200
ソフトウェアエンジニアの成長
masuda220
PRO
12
2.1k
未経験でSRE、はじめました! 組織を支える役割と軌跡
curekoshimizu
1
150
技術を改善し続ける
gumioji
0
120
生成AIで加速するテスト実装 - ロリポップ for Gamersの事例と 生成AIエディタの活用
kinosuke01
0
120
Honoをフロントエンドで使う 3つのやり方
yusukebe
7
3.5k
dbt Pythonモデルで実現するSnowflake活用術
trsnium
0
260
Featured
See All Featured
How to Ace a Technical Interview
jacobian
276
23k
Design and Strategy: How to Deal with People Who Don’t "Get" Design
morganepeng
129
19k
Improving Core Web Vitals using Speculation Rules API
sergeychernyshev
10
510
The Psychology of Web Performance [Beyond Tellerrand 2023]
tammyeverts
46
2.3k
Building Better People: How to give real-time feedback that sticks.
wjessup
367
19k
Done Done
chrislema
182
16k
A Modern Web Designer's Workflow
chriscoyier
693
190k
Producing Creativity
orderedlist
PRO
344
40k
Gamification - CAS2011
davidbonilla
80
5.2k
Building Adaptive Systems
keathley
40
2.4k
Fontdeck: Realign not Redesign
paulrobertlloyd
83
5.4k
Art, The Web, and Tiny UX
lynnandtonic
298
20k
Transcript
実録レガシー Rails アプリ改善ジャーニー 2023.3.25 第90回 Ruby関西 勉強会 / 舘林 秀和
@shutooike
自己紹介 舘林秀和 / Shuto Tatebayashi 所属 株式会社インゲージ 各種アカウント @shutooike 途中で名字が変わってややこしい
趣味 ひとこと コミュニティで発表するのが初めてなの で緊張してます
目次 ジョイン当時の状況 課題 改善ジャーニー 自動テスト編 バージョンアップ編 リファクタリング編 得られたもの これから まとめ
ジョイン当時の状況 2014年から開発している Rails アプリ フロントエンドはSPA バックエンドはAPI+Job サービスはたくさんのユーザーに使われている Ruby のバージョン2.3 RSpec
が導入されているが、カバレッジは20%以下 テストがないことがほとんど=レガシーコード QAはステージング環境でのドックフーディングと手動テスト頼み CIはあった(werkerを使用) 週に1回本番リリース
課題 テストが継続的に書かれてない 簡単な不具合修正、機能改善、負債返却で他が壊れることがある 以前と変わることは手動テストで担保するが 以前と変わっていないことを担保できていない ステージング環境によるドッグフーディングには限界が 変更に対する心理的安全性が低い 言語・ライブラリのバージョンアップが継続的に行われていない EOL切れ バージョンアップ時の防衛線がステージング環境にしかいない
同じようなロジックがあちこちに点在
改善ジャーニー 次のスライドから取り組んできたことおおよそ時系列で紹介していく この発表で説明しきれない詳細は今後ブログに書いていくつもり Twitter で @shutooike をフォローして、読んで、拡散して、感想ください(欲張 り)
自動テスト編
実行順序のランダム化 ファイル名順での実行になっており順番に依存したテストがちらほら spec ファイルを追加すると突然落ちるようになったり config.order = :random テスト数がそこまで多くなかったのでエイヤで :random にして、ローカルやCIで落ち
たら都度修正 Kernel.srand config.seed とすると Array#sample も seed で再現するようになる
テストデータが残らないように CIで特定のテストが失敗することが稀によくある 他のテストで作ったデータが原因 example ごとにデータを消す config.use_transactional_fixtures = true before(:all) で作りっぱなしのデータ
before(:each) に変更 after(:all) で削除
自動テストを書いていく(1) 日々の開発で自分が関わったコードからテストを書いていく なぜか書きにくいという実感が... 原因突き詰めたところ →「そうか!土台が出来てないんだ!」 プロジェクト発足
実際の最初の issue
スキップしていたモデルのコールバックを解放 User.skip_callback(:create, :after, :foo) 思考停止でのほぼ全てのコールバックがスキップされていた プロダクトコードではデータ作成時にコールバックで行っている処理を、テストデ ータ作成時は自分で明示的に処理しないといけない状況 テスト環境の挙動は出来る限り本番環境に近づけるべき 一部残したコールバックもある 時間がかかりすぎるもの
外部サービスを呼び出すもの モック化するという手もある
FactoryBot のフル活用 お馴染みのテストデータ生成ライブラリ シナリオに沿ったテストデータをサクッと作れないとテストを書くハードルが一気に上 がる 導入はされているが、上手く運用はされていない状況 FactoryBot の定義方針を検討・決定 詳しくはブログに書きます 方針に沿って
FactoryBot を再定義・既存のテストを修正 最初は頑張って全モデルでやろうとしたがその必要はなかった よく出てくるスタメンモデルだけでOK
自動テスト戦略を立てる ここまでテストを書いた感覚でテスティングピラミッドを目指すのは厳しいと判断 単体テストを継続的に書くのは開発者の力量に依存するところが大きい 良くない単体テストはむしろ開発生産性を下げる プライベートメソッドのテストを書く 期待値生成にコードと同じロジックを用いる... など まずは統合テストたくさん書いていくことにする 目指すはテスティングトロフィー 主な
Rails の責務である API の request spec を書いていく とりあえずある程度までカバレッジを上げたい
誰でも書ける request spec helper を用意 誰でも書けるように薄さにこだわる 正常系のみ 最低限の条件 ログインユーザー パラメーター
最低限の検証 APIの権限チェック HTTPステータスコードチェック APIを作ったら絶対書こうねという意識付け →「お約束」というネーミング
利用側のイメージ describe 'POST /api/messages' do context ' お約束' do let(:login_user)
{ create(:normal_user) } let(:minimum_required_params) { { text: 'Hi' } } it_behaves_like(:can_be_accessed_with, 'normal') it_behaves_like(:return_http_status_as, :created) end end どのように実装したかはブログに書きます
全APIに正常系テスト(お約束)を書いていく 全体カバレッジが60%ほどに APIのカバレッジは90%近くに 少なくとも最低限の正常系の動作が変わっていないことが担保できるようになったので 安心感が全然違う コスパ最強
request spec でAPIの振る舞いを検証する クリティカルユーザージャーニー(CUJ)を定義 ユーザーが 1 つの目的を達成するために行うサービスとの一連のインタラクション CUJをもとにサービスの主要な操作に関するAPIに対して正常系・異常系の振る舞いを検 証 振る舞いとは?
データのCRUD ジョブのキック 外部サービスの呼び出し... など 主要なAPIの動作の担保され安心感がさらに上がった
最低限のE2Eテストを書く SPAといいつつ複数画面がある メイン画面 編集画面 外部連携用画面... など 最低限の検証 画面が正常に開けることのみ確認 ステージング環境でのドックフーディングでは普段開かない画面がひっそり死んでるこ とに気づけるように
バージョンアップ編
Ruby 2.3 → 2.7.6 警告の対応 依存 gem のバージョンアップ 開発環境でバージョンアップ 自動テスト・手動テスト
他の開発者の開発環境に展開 ステージング環境バージョンアップ 手動テスト 本番環境バージョンアップ
Rails 5 → 6 警告の対応 依存 gem のバージョンアップ 開発環境でバージョンアップ rails
app:update new_framework_defaults 自動テスト・手動テスト ステージング環境バージョンアップ 手動テスト 本番環境バージョンアップ
リファクタリング編
複数モデルで使える共通の処理を concern に Rails がデフォルトで用意している仕組み 上手く使えたら綺麗に抽象化できる 上手く使えたら... 例 created_by, updated_by
を入れる処理
単体テストが書きやすくなるような実装に 自動テスト戦略で統合テストに注力したもう1つの理由として単体テストが書きにくい実 装になっていた ドメインロジックがコントローラー層に Fat Controller より単体テストが書きやすいようにドメインロジックをモデルに寄せていく必要がある Fat Model 自動テストがある程度書けたので振る舞いが変わらないことを担保しながらリファクタ
リングができる
[再掲] 課題 テストが継続的に書かれてない 簡単な不具合修正、機能改善、負債返却で他が壊れることがある 言語・ライブラリのバージョンアップが継続的に行われていない EOL切れ バージョンアップ時の防衛線がステージング環境にしかいない 同じようなロジックがあちこちに点在
得られたもの テストが書きやすい環境 APIを作成したらお約束テストを追加する文化 ある程度のカバレッジ コードの変更やライブラリのバージョンアップなどに対する心理的安全性 他に影響があるコード変更がCIで落ちる ライブラリのバージョンアップの非互換に気付けたことも
[再掲] 課題 テストが継続的に書かれてない 簡単な不具合修正、機能改善、負債返却で他が壊れることがある 言語・ライブラリのバージョンアップが継続的に行われていない EOL切れ バージョンアップ時の防衛線がステージング環境にしかいない → 継続してやっていく 同じようなロジックがあちこちに点在
→ 継続してやっていく
これから とりあえず「EOLを切らない」を目標に Ruby, Rails を上げていく dependabot をフル活用してライブラリアップデートを習慣化 テスティングピラミッドを目指す 単体テストが書きやすくなるよう引き続きリファクタリング ステージング環境で行っている手動テストの負荷低減
現在の最低限のE2Eから少し検証範囲を広げる
まとめ 自動テストは書かないと上手くならない 勘所を掴むまでクソテストコードを書いて書いて書きまくれ 幸いテストコードは書き直しやすい レガシーコード改善に銀の弾丸はない カバレッジも可読性、メンテナビリティも突然上がることはない 理想に向けてロードマップを引き地道にやっていくしかない レガシーコードを愛する ユーザーの課題を解決し、売上を立てるレガシーコードは偉大 なりたくてレガシーコードになった訳じゃない
その時々の最適解だったはず 恨みではなくリスペクトを持って接する
おまけ1 カバレッジは正しく測ろう 以下の2つを行ったらカバレッジがグッと上がった # config/envioroments/test.rb config.eager_load = true spring を使わずに
RSpec を実行 原因ははっきりわかっていないがおそらくコードの分母が正しく測れるようになったか ら 知ってる人いたら教えてください
おまけ2 カバレッジを追い求めすぎない カバレッジが高いからバグが出ない訳じゃない 効果的なテストをすることが一番重要 カバレッジは目標にせず、指標にするべき
None
None
None