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 improvement journey
Search
shutooike
March 25, 2023
Programming
3
750
実録レガシー 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
Rubyのパフォーマンスプロファイリングの改善 / Enhancing performance profiling for Ruby
osyoyu
1
410
Modern Angular: Renovation for Your Applications
manfredsteyer
PRO
0
140
CSC307 Lecture 14
javiergs
PRO
0
220
CSC307 Lecture 06
javiergs
PRO
0
360
Javaの現状2024夏 / Java current status 2024 summer
kishida
4
1.4k
AWSでゲームサーバーを運用! Amazon GameLiftのお話
iriikeita
0
200
Folding Cheat Sheet #7
philipschwarz
PRO
0
150
コード生成を伴うLLMエージェント - 2024.07.18 Tokyo AI
smiyawaki0820
11
4.1k
スクラムマスターって孤独じゃないですか?
yoshitaroyoyo
1
140
SDCon2024: Enabling DevOps and Team Topologies thru architecture: architecting for fast flow
cer
PRO
0
780
The rollercoaster of releasing an Android, iOS, and macOS app with Kotlin Multiplatform | droidcon Berlin
prof18
0
110
ピグパーティにおけるMongoDB CommunityバージョンからAtlasへの移行事例
10969hotaka
0
130
Featured
See All Featured
A Philosophy of Restraint
colly
200
16k
Making Projects Easy
brettharned
111
5.7k
How GitHub Uses GitHub to Build GitHub
holman
471
290k
Put a Button on it: Removing Barriers to Going Fast.
kastner
58
3.3k
For a Future-Friendly Web
brad_frost
173
9.2k
Scaling GitHub
holman
458
140k
"I'm Feeling Lucky" - Building Great Search Experiences for Today's Users (#IAC19)
danielanewman
224
21k
XXLCSS - How to scale CSS and keep your sanity
sugarenia
245
1.2M
Statistics for Hackers
jakevdp
792
220k
Fight the Zombie Pattern Library - RWD Summit 2016
marcelosomers
228
16k
How GitHub (no longer) Works
holman
305
140k
The Illustrated Children's Guide to Kubernetes
chrisshort
39
47k
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