はじめに
の1日目です!
こんな人に読んでほしい
- 古いコードで新しくしたいけど、難解だから手がつけられない…
- レガシーシステムの刷新をしたいが、大変そうなので諦めている
こんなことがありました
とある日、社内業務システムの保守・運用・追加開発担当になり、コードを読んでみると…なんだこれは!カオス!!
- 時を経て積み重なったであろう大量の条件分岐
- クラス名やメソッド名と意味が違う処理をしている
- コメントが無い、または実装と違うことが書いてある
- デッドコードがあちこちに残っている
- コードを書いた前任者が退職済で意図が分からない
- 数個だけあるユニットテストもメンテされていないまま
- ていうか、phpファイルでhtmlをechoしてるの初めて見た
毎日バグ報告を受けてはログを探し、その機能ではログを出していないことに気づき、時間をかけてコードを解読し、修正する日々が始まりました。
その時、私は今までどれだけ恵まれた環境で開発できていたのかを実感しました。
※今までは大手SIerの下で綺麗なシステムをいじってました。
なぜそうなった?
いろんな先輩方からこのシステムの経緯を聞いた結果、個人的に下記が原因だと考えています。
- システムを作り始めた当初は、開発担当が1人だった
→レビュー体制がない - スタートアップで、とにかく動くものを作れ!で要件決めも開発もスピード最優先
→正常系以外の考慮がされていない、コードを綺麗にしている暇もない - 当時の開発担当者が自動テストに明るくなく、時間もないので手動で正常系の主なケースしか確認していなかった
→イレギュラーケース、エラーケースのバグに気づかない - そんな状況なのでもちろんドキュメントはない。口頭で合意して口頭で確認
→開発した人しか背景や正しい仕様が分からず、本人も日に日に忘れていく - コメントを書いても整備が置き去りに
→コメントとコードの内容が一致せず、コメントに惑わされる・コメントを信用できなくなる
一応補足
当時の担当者を責めるのはNGだと思ってます。そういう状況だったのは仕方ないですし。
やるべきことは再発防止と、これからどうするか考え実行することで、そのために原因を挙げています。
理想と現実のギャップ
会社も大きくなってきて人が増えたのでバグ問い合わせも同時に増え、このままではまずいのでバグ直しまくって、安定稼働を目指しましょう!となりました。
しかしバグ改修するにも、コード読み解くのに時間がかかっちゃって大変…もう全部リファクタしたい!AIとか使えばなんとかなるんじゃね!?
と思ったりもしましたが…現実はそう上手くはいかないものです。
- 社内業務で毎日使っていて、システムを止めることはできない
- プロジェクト全体のリファクタリングには大きな手間がかかる
- 先述したようにドキュメントもなく、現場で動かすこと優先で作ってきたので、正しい仕様が曖昧。従ってAIに正しい仕様の指示ができないw
- そもそも事業部(ビジネス)としては、リファクタよりも「このバグ直して」「ここもっと使いやすくして」の方が優先
- 自動テストがないので、リファクタするならそこから必要
- そして自動テストできるようなコードではない(ハードコーディングしまくりで密結合)
小さく始める改善
一気にリファクタするのは困難だと分かったが、放っておくのはしんどい…
「正しい仕様を人に聞きまくって書き起こす」みたいな大層なことをやるのは、自分の力量的にも会社のリソース的にも難しそうだったので、まずは自分ができることからやっていこう!と思いました。
新機能追加から始めるユニットテスト
まずはリファクタを安心してできるようにするためには自動テストが必要だと思ったので、チーム内で「ユニットテスト書きませんか?」と提案。
ユニットテストを触ったことがないメンバーもいるので、強制はせず、「書く余裕がある人、書きたい人は書こう!」という方針になりました。
チーム内ではユニットテストがりがり書いたことあるのが自分だけだったので、自分の中では以下のルールを定めています。
- 新機能を作る時は書くチャンス!リリース期日と相談しながら書こう
- 既存機能の場合は、プロダクトコードを修正できそうなら書こう!
バグ修正のついでにリファクタリング
ユニットテストを自分が、しかもできる時に作るだけではなかなか進まないので、「バグ修正のついでにリファクタリング」はがっつりやりました。
- バグ修正でファイルに手を加える際、ついでにコードを整理してみる
- DB操作がControllerに散らばっている場合はUseCase層に切り出してまとめる
- ログ出力を追加する
- 古いコメントを更新・コメントの新規追加
- 「何をしているか」ではなく「なぜそうしているか」を書くのがベスト!
- 「何をしているか」はコードを読めばわかるようにしよう!
- その他は大体 リーダブルコード に書いてあることを実践すればOK!
- 一気に全てを変えるのではなく、「今触る場所だけ」改善する
- AIにコードレビューしてもらう
- GithubでPR作成時に、Gemini Code Assistにレビューしてもらうようにしました。結構「ここ整理した方がいいよ」的なレビューもくれるのでリファクタに役立ってます
これ、自分からやり始めたらチームメンバーも段々修正に合わせてリファクタしてくれるようになってきて、やってよかったなぁと思ったことの一つです。
「また今度やろう」を今やる!すぐやる!でもできる範囲でね!というのが大事な気がします。
特にログは超重要
ログは、未来のあなたを救ってくれます。ガチです。
バグの原因調査で、真っ先にログを見ますよね?
ログがないと、どこで何が起きたのか、バグ報告からしか読み取れず、調査の難易度がぐっと上がります。
ログは出しましょう。
ただし出力量と、書いていいこと・いけないことには注意しましょう。
フレームワークなら簡単に出せると思いますし、フレームワークがなくてもファイル操作ができればログファイル作成→書き込み→保存 で出来る!
ログはローテーションしよう
ログを出しまくっていると、もちろんサーバーの容量圧迫につながります。
ローテーション設定をして、サーバーの容量を食いすぎないようにしましょう。
- ログの保管期限は?
- 何日単位で圧縮させる?
- 情報として何を出す?
- AWSなどのログ集約サービスにまとめる?
などをチーム内もしくはチーム外の人も交えて話し合って決めましょう!
まずは一般的な運用してみてから様子を見て決めるというのもアリです。
ログに書いていいこと(書くべきこと)
基本的に5W1Hの「who」「why」抜き、つまり「when,what,where,how」があれば完璧だと思ってます。
- 発生日時(フレームワークなら自動で出してくれたりする)
- 何が起きたか
- どこで起きたか
- 入ってきたパラメータとレスポンス(INPUT / OUTPUT)
- 例外の場合はスタックトレース
ログに書いてはいけないこと
基本、漏れたらダメなことは書いてはいけないです。
- 個人情報(住所、氏名など)
- 機密情報(APIキーなど)
バグ修正の合間に静的解析
特定の操作をすると500エラーで落ちる、みたいなバグがちょくちょくあったのですが、以前「静的解析は安心感のために入れたほうがいいぞ!」といっていた先輩のことを思い出し、静的解析ツールを導入することにしました。
バグ修正の息抜きに、ちょっと他の作業をしたかったというのもありますw
- ルールの厳しさを設定できるツールだったので、まずは一番優しいレベル(激ヤバなバグのみ検出)から始める。慣れてきたらレベル上げてこうね、となった
- コード品質の可視化、潜在的な問題の発見ができる安心感
そんなこんなで、少しずつ改善しています
この取り組みによって、
一気に変えるのは難しい。でも、少しずつなら変えられる!
ということを実感しています。
「レガシーだから触らない」「上の人が改善する気がないから諦める」のではなく、
レガシーシステムと共存し、地に足つけて少しずつ改善していくことが、未来の自分とチームメンバーを救ってくれます。
おかげで私は、こうしてアドベントカレンダーに書くことが1つできてますし、チームメンバーも最近ユニットテスト書いてくれるようになりました。何事も経験だなぁと思います。
レガシーコードに悩んでいる皆さん、まずは今日からできることを少しずつやっていきましょう!