AIによるリファクタリングがなぜ失敗するのか
AIによるリファクタを何回もしました
ここ1年はC向けアプリを開発しており、開発の過程でコード全体のリファクタが度々ありました。
その過程で学んだ教訓があります。
この教訓、私は血と涙で学びました。ええ、一度ならず、何度もね。その輝かしい戦犯記録は、今もgitのcommit履歴にクッキリと刻まれています。
あれは、数百行を超えて肥大化したReactコンポーネントという名の魔物と対峙していた時のこと。
私の傍らには、無敵の相棒「Claude Code」がいました。だから私はこう思ったのです。
「なあClaude、このコンポーネント、いい感じにリファクタリングしといて」とだけ告げ、あとは魔法が起こるのを待つだけだと。だってAIって、そういうもんでしょう?
絶望のリファクタリング惨事
甘かった。あまりにも、甘すぎた。
Claudeは、一見すると完璧なリファクタリングコードを吐き出しました。カスタムフックは抽出され、ロジックは分離され、propsは芸術的に整理されている。
完璧だ、これこそ私が望んだ未来だ。
私は意気揚々とアプリを起動しました。そして…画面は沈黙。
真相はこうです。
Claudeのやつ、裏ではとんでもないことをしでかしていたのです。
- 複数のコンポーネントにまたがる状態管理を静かに、しかし確実に破壊。
- 主要な変数をリネームしたはいいが、他の場所での参照はガン無視。
- 一見すると重複コードに見えるが、実は絶妙なエッジケースを処理していた生命線のようなコードを、ゴミと判断して削除。
最悪だったのは、この大惨事の後始末に、手動でリファクタリングするより遥かに長い時間がかかったことです。gitで戻せばいいが、一部は奇跡的にうまく動いていたので残したかったのです。しかし、変更セットがあまりに巨大な怪物と化していたため、「この部分だけ残して、あとはポイ」なんて器用な真似は不可能でした。
すべてが一つの巨大な塊として絡み合っていたため、私はその呪われたコードを丸ごと受け入れ、手作業で解きほぐす地獄の旅に出るしかありませんでした。数時間、変更の痕跡を血眼で追い、何が起きたのかを探りましたが、やがて敗北を悟り、すべてを捨ててゼロからやり直したのです。
なぜAIは壮大なリファクタリングで盛大にやらかすのか
さらに数回の自爆実験(どうやら私は痛い目を見ないと学べないらしい)を経て、AIに「全部やっといて」と丸投げするのが、なぜ破滅への片道切符なのかを理解しました。
-
デカいファイルの前では記憶喪失になる。
- AIは複雑なコードの無数の相互接続を把握しきれません。家の配線図も渡さずに「ちょっとこのブレーカー周りをイケてる感じにしといて」と頼むようなもの。そりゃ大停電しますわ。
-
あなたの秘伝のタレ(アーキテクチャ)の味を知らない。
- あの関数が他の3つのコンポーネントにどんな隠し味を加えているかなんて、AIには分かりません。
-
勝手に良かれと思って致命的な判断を下す。
- 機能の完全性より、見た目の美しさを優先することがあります。AIが「これ、いらなくね?」と判断したものが、実はビジネスの根幹だったりするのです。
-
ビジネスロジック?何それ美味しいの?状態。
- AIはパターンでコードを再構築します。あなたのコードが「なぜ」そう書かれているのかは理解しません。結果、見た目は美しいが全く動かない、芸術的なゴミが爆誕します。
その結果は、火を見るより明らかです。
- 参照の集団失踪(変数名を変えたら、あちこちで迷子が発生)
- 副作用の謎の蒸発(あれ、いつの間にかアクセス解析が動いてない…)
- 単純なコードが超サイヤ人化(たった5行の処理に、なぜかフックが3つも…)
- 機能のサイレントお祈り(「バグじゃない、仕様変更だ」…消えたけどな!)
AIリファクタリングフレームワークを打ち立てよ
数々の地獄巡りの末、私は安全にリファクタする手法を編み出しました。そう、焦って自分のルールを破らない限りは、ある程度はうまくいきます。
ステップ1:Gitにベースラインを刻む
まずはクリーンなブランチを切り、コミット。これが、すべてが燃え上がった時のための脱出ポッドです。
フェーズ1:手を出すな、まずはレビューさせよ
「全部直せ」は禁句。代わりにこう命じます。
「このコードを分析し、改善・モジュール化すべき点のリストをMarkdownファイルとして作成せよ。まだ一行たりとも書き換えるな。」
これにより、AIを暴走させずに、まず分析と思考に集中させます。破壊者ではなく、優秀なコンサルタントとして動いてもらうのです。
フェーズ2:神(=人間)によるフィードバックタイム
AIが作成したリストを、今度は神であるあなたがレビューします。
- 無駄な提案は斬り捨てる(「全ての関数をアロー関数に?結構です」)
- 真の病巣を指摘する(「問題はそこじゃない、この状態管理こそが癌だ」)
- 触れてはならない聖域を指定する(「決済ロジックだけは、何があっても触るな!」)
これで主導権はあなたのものです。たとえ自分の判断に自信がなくても(私も大抵ない)、「この部分は君の知識で最善を尽くしてくれ」とメモを残せば、AIの専門知識を借りることもできます。
フェーズ3:タスクを粉々に砕け
次に、チェックリストを、脳が理解できるレベルまで細かく分解します。例えば:
- フォームのバリデーションロジックをカスタムフック
useFormValidation
に切り出す - フォームの各セクションを、それぞれ別のコンポーネントに分離する
- 状態管理を
useState
からuseReducer
に書き換える
最重要機密:一度に処理するのは、たった一つのタスク。
ひとつ。たった、ひとつだけ。
フェーズ4:ブランチに隔離して実行せよ
各タスクに対して、以下の儀式を執り行います。
- 専用のブランチ(独房)を用意する(ステップ1を忘れるな、絶対にだ)
- AIには超具体的な命令を下す。「このブロックだけを
useValidation
というフックに抽出しろ。他のコードには指一本触れるな」 - 一つの変更が成功するたびに、即コミット。
AIを、熱意はあるが時々盛大に勘違いする新人ジュニア開発者だと思ってください。初日から「アプリ全部リファクタリングしといて」なんて鬼のような指示は出しませんよね?
フェーズ5:検証、そして破滅からの帰還
変更を加えるたびに:
- テストを走らせる(テスト、ありますよね…?ありますって言って!)
- 手動で動作確認(ボタンを連打し、フォームを破壊する勢いで入力)
- 壊れたら:即ロールバック。スコープをさらに狭めて再挑戦。
- 動いたら:リストに勝利のチェックを刻み、次のタスクへ。
このサイクルが、あなたが破滅の道へ進みすぎるのを防ぎます。現在地も分からなくなってから地図を見るのではなく、こまめに標識を確認しながら運転するのです。
番外
黄金の小技集
-
コメントをを残す:
// フォームのバリデーションを処理
のようにコメントを書いておくと、AIの理解度が格段に上がります。ガレージの箱にラベルを貼ってから、誰かに整理を頼むようなものです。 -
スコープを限定する:
「いい感じにして」ではなく、「この関数だけ抽出して。変数名は変えるな」と命令する。AIはあなたの忠実なる下僕です。遠慮は無用。鬼軍曹になりきって命令しましょう。 -
失敗は友達:
CursorのチェックポイントやGitを使ったり、単に元のコードを別のファイルに保持しておきましょう。常に「どうせ壊れる」と想定し、逃げ道を用意しておくのです。 -
段階的に構築する:
偉大なリファクタリングは、常に小さな一歩の積み重ねです。これはAIがいようがいまいが真理ですが、AIがいると、この原則はさらに重要になります。
これぞAIリファクタリングの真骨頂
この分割統治法をマスターしてから、AIは私の頼れる相棒になりました。破壊神から、超有能なジュニア開発者へと進化したのです。
AIが得意なこと:
- 単一の関数をフックに抽出する(これ、めちゃくちゃ得意)
- (導きがあれば)クラスコンポーネントを関数コンポーネントに変換する
- あなたが詳細に指示したデザインパターンを実装する
- 型定義やドキュメントを自動生成する(マジで神。これだけでも飯が食える)
AIが苦手なこと:
- コードベース全体を理解すること(文脈を読めない)
- アーキテクチャに関する決定を下すこと(ビジネスニーズを知りません)
- ユーザーにとって重要な、微妙なエッジケースの価値を知ること
- AIが理解できないビジネスロジックを保持したまま実装すること
最後に
AIを使ったリファクタリングは、「全部修正して」と魔法の杖を振ることではありません。
AIを、あなた自身の専門知識を何倍にも増幅させるための究極のブースターとして使うことなのです。
作業を分割しましょう。
具体的な指示を与えましょう。
常に逃げ道を準備しておきましょう。
AIは設計図を描く建築家ではありません。建築家は、あなたです。
AIは、あなたよりも速くコードを書くことができる、非常に賢いキーボードにすぎません。
この現実を受け入れた時、AIリファクタリングはただの夢物語ではなく、信じられないほど強力な武器となるのです。
忘れないでください。一度に、一つの変更だけ。
そして、できれば、いや絶対に、最初にgitブランチを作成しましょう。
この記事はAdam Bertramさんの記事オマージュです。
実際に私が何度かLLMによるリファクタリングをした経験から、この記事に共感して、日本語化(超意訳)しました。
Discussion