
みなさんは普段リファクタリングにどれくらい時間を割いていますか?
将来的な品質や開発スピードを担保するためには定期的なリファクタリングが必要ですが、普段の業務が忙しくてなかなか時間を割けない方も多いと思います。
そこで今回は、AIを活用して効率よくリファクタリングできないかを検証してみたので、その振り返りを兼ねてご紹介したいと思います。
リファクタリングの進め方
今回のリファクタリングは、直近取り組んでいた機能開発に関連するコードを対象にしています。
Cursorのチャットスペースを使い、以下の手順で進めました。
- リファクタリング候補の洗い出し
- リファクタリング箇所の選定
- 実装方針を決定
- 実装
- テストのカバレッジを確認
- リファクタリング実装
- テストの追加
リファクタリングの実践
先述した進め方に沿って、実行結果をまとめます。
1. リファクタリング候補の洗い出し
AIに以下のプロンプトを投げて、リファクタリング候補を優先度順にまとめてもらいました。
機能Aの中でリファクタリングできそうな箇所、共通化できそうな箇所などを洗い出して、優先度順にまとめてください。 観点に以下を含めてください。 - 問題点 - 改善案 - 期待される効果 - 工数 優先度は以下の順で検討してください。 1. 保守性向上につながるか 2. 対応工数低めで対応できるか
AIの回答(一部抜粋)
### 1. シリアライザー間のXXXロジックの共通化 - 対象ファイル: - … - 問題点: 同一ロジックが重複 - 対応案: ${クラスA}に${メソッドA}を追加し、シリアライザーから呼び出す - 効果: 変更箇所が1箇所に集約、保守性向上 - 工数: 1-2時間 ... ### 8. 有効期限計算ロジックの集約 - 対象ファイル: - … - 問題点: 有効期限計算が複数箇所に分散(TODOコメントあり) - 対応案: ${クラスA}を作成し、計算ロジックを集約 - 効果: 計算ロジックの一元化、テスト容易性向上 - 工数: 3-4時間 ... ## 推奨対応順序 1. 優先度:高の1-4を順次対応(合計5-8時間) 2. 優先度:中の5-7を対応(合計4-6時間) 3. 優先度:中-低の8-10は必要に応じて対応 特に優先度:高の1-4は対応工数が少なく、保守性向上の効果が大きいため、優先して対応することを推奨します。
トータルで12箇所ほど挙げてくれました。問題点と改善案も提示してくれたため、調査にかかるコストはかなり削減できたと思います。
2. リファクタリング箇所の選定
リファクタリングの優先度を検討した結果、「8. 有効期限計算ロジックの集約」を最初に着手することを決定しました。
主な観点は以下の通りです。
- TODOコメントが残り(チーム内で既に問題意識がある)
- 設計の健全性を大きく損なっている
優先度に関しては、AIと人間の認識にズレが生じる結果になりました。
要因としては以下が考えられます。
- 対応工数に関する影響が大きくなってしまった
- AIに実装を任せるので、多少の差分は無視できる前提で指示するべきだった
- TODOコメントも考慮に加え、顕在的な課題として評価できると良かった
ここは人間の判断基準を詳細に言語化して、プロンプトを磨き込む余地がありそうです。
3. 実装方針を決定
リファクタリング箇所が決まったので、「8. 有効期限計算ロジックの集約」の実装方針についてAIにサンプルコードを出力してもらい、それをレビューする形で方針を固めていきました。
主な観点は以下の通りです。
- 本当にリファクタリングの価値があるか
- 保守性向上につながる有効な共通化になっているか
- 逆にコードの可読性を損なっていないか
- やりたいことに対して必要最低限の差分になっているか
また、この時点で「本当にリファクタリングの価値があるか」を再度見直すことも重要だと感じました。
例えば「1. シリアライザー間のXXXロジックの共通化」の実装方針を検討する際、いくつかの実装パターンを提示してもらいました。しかし、どれも局所最適な共通化に留まり、長期的な保守性向上にはつながらないことが判明しました。
こういったケースについても、実際のコードを見ながら解像度高く判断することで、無駄な実装を避け、効率的なリファクタリングにつなげることができます。
4. 実装
実装フェーズは3ステップに分けて進めます。
a. テストのカバレッジを確認
リファクタリングは、「ソフトウェアの外部から見たときの動作を変えずに、コードの内部構造を改善する作業」です。外部から見たときの動作が変わらないことを担保するため、まずはテストのカバレッジが十分かどうかをAIにチェックしてもらいます。
AIの回答(一部抜粋)
## テストカバレッジの評価 ### 十分にテストされている箇所 1. モデルAのメソッドa: 境界値テストあり 2. モデルBのメソッドa: 複数パターンのテストあり ### テストが不足している箇所 1. モデルAのメソッドb: 直接テストなし(xxx経由で間接的にテスト) 2. モデルBのメソッドb: ユニットテストなし(APIテストのみ)
テストが不足している箇所を挙げてくれましたが、間接的にテストされており、必要なパターンは網羅されていたので、問題なしと判断しました。
b. リファクタリング実装
テストが十分だと確認できたら、安心してリファクタリングを実装できます。
実装方針についても既にすり合わせていたので、ほとんど手戻りなく完了しました。
c. テストの追加
最後に、今回は新規クラスを追加したので、その単体テストを追加してもらいました。
これで実装フェーズはコンプリートです。
結果として、有効期限計算ロジックを1箇所に集約することで、保守性とテスト容易性が向上しました。
| クラス | 変更前の主な責務(Before) | 変更後の主な責務(After) | 改善効果 |
|---|---|---|---|
| Model A | ステータス判定 有効期限の計算・判定 |
ステータス判定 | 単一責任の達成。 本質的なロジックに集中。 |
| Model B | ログ記録 有効期限の計算・判定 |
ログ記録 | 疎結合化。 インフラ層からドメインロジックを分離。 |
| Serializer | 表示フォーマット 有効期限の計算・判定 |
表示フォーマット | 表示層の純粋化。 計算ロジックを排除。 |
| Model C(新規) | N/A | 有効期限計算の集約 | ロジックの変更箇所が1箇所に集約。 |
やってみた感想
調査の工数をほぼ0にできた
- どこを、なぜリファクタリングするのか
- 安全にリファクタリングできるか(テストは十分か)
といった点を調査してまとめるのは、本来時間のかかる作業ですが、ここをAIにサクッとやってもらえたのは良かったです。
優先順位は人間の判断が必要
今回、AIが優先度低めに設定していたリファクタリングを最初にやる判断をしました。
先述したように、優先度の判断基準に関する指示は改善の余地がありそうです。
それに加えて、機能開発と並行してリファクタリングを進める場合、「現在進行中の開発とコンフリクトしないか?」という観点も必要になると思います。
リファクタリングの都合で機能開発のスピードを落とすわけにはいかないので、チームの開発事情と照らし合わせて判断できると良いですね。
チームでどう運用していくか
リファクタリングは一度やって終わりではなく、継続してやっていく必要があります。
今回の取り組みを通して、工数をかけず安全にリファクタリングする手順は確認できました。
今後はチームとして安定したコード品質、開発スピードを担保するため、以下の2つに取り組んでいきたいと思います。
- 技術負債を可視化してチームで共通認識を持てるようにする
- 機能開発と並行したリファクタリングの実施を、チーム開発のサイクルに落とし込む
さいごに
この記事では、AIを活用したリファクタリングの実践例をご紹介しました。
AIの支援により、調査工数を大幅に削減しながら、安全にリファクタリングを進めることができました。一方で、優先順位の判断やチーム開発との兼ね合いなど、人間の判断が必要な部分も明確になりました。
今後もAIを上手く活用しながら、チーム全体でコード品質を維持・向上させていく取り組みを続けていきたいと思います。
AIを活用した開発改善や、チームでの継続的なコード品質向上に興味がある方、ぜひ一緒にお話ししませんか?