🤮

技術的負債が溜まったRailsプロジェクトにアサインされたら

2022/08/27に公開

半年かけて、負債返却に取り組んだ時の備忘録

初期状態

  • Ruby 2.6系
  • Rails 5.2系
  • テストは数個
    • ジェネレーターによって作られた何の意味もないテストファイルは沢山
  • ローカル環境構築もままならない
    • 初期データが足りないから一部のページは動かない
    • ソースコードを書き換えないと動かないものがある
  • リモートにある開発環境も壊れている
    • 一部の機能が動かない
    • 本番とDBのスキーマが違う(あとでわかったこと)
    • 初期データが本番と違う(あとでわかったこと)
    • assets系の挙動が本番と違うから開発ではOKでも本番でレイアウト崩れが起きるとかがある
  • 一番詳しかった人は退職済み
    • 過去の経緯とかはロストした

という状況が初期状態

(実際は、これ以外にもいくつかのRailsアプリケーションがあってそちらも弄りながらやっていた)

半年後の状態

  • Ruby 2.7系
    • インフラ側が落ち着いたら3.0系にあげていく
  • Rails 7.0系
  • カバレッジは約70%
    • 自分を含めた2名のエンジニアでひたすらテストコード書いた
  • ローカル環境構築はいくつかbrew installして./bin/setupで構築できる
  • リモートにある開発環境で動作確認ができる
    • environments/development.rb を本番に近づけた

まずまず、立て直した

この状態にする間も新規機能開発を完全に止めた訳ではなくちょこちょこ新機能追加はしながらやった

どのようにやっていったか?

再現性のあるローカル開発環境構築手順を作る

やった事としては以下の通り

  • MySQL は docker-compose を利用して入れる
  • ソースコードを直接書き換えないといけない部分はSettingsのフラグで制御する
  • 何度も作っても壊すを繰り返して手順を確定させる
  • seeds.rbの整備

ここはテストがない状態でソースコードを弄っていたのでもの凄く怖い。小さい変更を重ねていく

DBの不整合を直す

リモートにある開発環境で db:migrate ができなかったからマイグレーションを何とかする事から始めた
(ブランチを切り替えて db:migrate して放置していた疑惑)

このプロダクトでは、スキーマの管理と動作に必要なデータ(マスタデータ)の投入をマイグレーションで行っていた

そこで、

  1. マスタデータの管理の移行
  2. スキーマ管理の移行

の順番で移行を行った

  • マスタデータは自作のgemで管理
    • https://github.com/taka0125/master_data_tool
    • seed_fuなどが有名だが各環境で差分がある可能性が高かったので dry-run が実行できるものを作成した
    • この選択は正しかった。本番・リモート開発環境・ローカル環境で細かい差異があったw
  • スキーマの管理に関しては ridgepole に移行する
    • ローカルで db:migrate を行った上で ridgepole のエクスポート機能を使ってスキーマをエクスポートする
    • その後、各環境でdry-runを繰り返し「正解のスキーマ」を探す
    • 基本的には本番のスキーマを正とすればいい

リモートの開発環境を直す

DBの不整合が直った時点でほとんどの問題は解決した

一部、動いていない機能は本番の設定データなどを参考に新たに設定していく

(この時、本番と開発が同一の外部サービスのアプリケーションを使っているとか怖いことも判明した…)

E2Eテストの導入

リモートの開発環境の整備ができた段階で「テストはないが機能開発ができる」状態になったので、この辺りから負債返却以外にも新規実装もやっていた

NewRelicが導入されていたのでリクエスト数が多い順に並べてTop40くらいまでのエンドポイントのテストを書く事を目標にして始めた
(Top40より下はリクエスト数も1週間に1回あるかないかくらいだったので対応工数の割にリターンが少なそうだった)

ある程度使われているエンドポイントをテストで保護してRuby/Railsのアップデートに着手することにした
(E2Eテストで書いた最初のテスト「◯◯の権限を持っている時に××ができる」で権限がないのに実行できてしまうマズいコードを見つけてしまったのでこれの対応で数週間が飛ぶ)

bundle updateを行う(Rails以外)

まずは、Ruby/Railsを上げずに使っているgemを可能な限り最新にした
リモートの開発環境整備が終わっているのでここで動作確認が取れるようになっていたのが大きかった
いくつかの不具合を直しつつ、開発環境で動くようになったらいよいよ本番へ

Rubyのアップデート

Ruby 2.6系 => Ruby 2.7系のアップデート

これも開発環境で動作確認をして、本番適用

インフラ絡みでいくつかはまった点はあったがRailsアプリケーション側での問題はなかった

Railsのアップデート

Rails 5.2 => Rails 6.0

Railsのアップデートに関しては https://railsguides.jp/upgrading_ruby_on_rails.html に従って進めていく

限定的な状況下で起こる不具合を踏んで一部のユーザで正しい挙動をしないページが後から見つかってリバートしたがそこまで大きな問題もなく移行が完了

Rails 6.0 => Rails 6.1

この辺りは Rails 5.2 => Rails 6.0 からそれほど時間を空けずに検証して適用した。(2週間後くらいには適用された)

Rails 6.1 => Rails 7.0

時間を空けずに検証して適用した

これから

Rubyのアップデートが残っているが落ち着いたら今まで通りに進めて行くことで解決はしていきそう

既存コードのリファクタリングなども徐々にやっているので少しずつ前に進めている

まとめ

  1. 開発・動作確認できる環境を整備しよう!
  2. 完璧を求めなくていいから、自分の不安がなくなるくらいにはテストを充実させよう!
  3. あとは度胸!

Discussion