使われていなさそうな関数を前に、本当に消してよいかを参照元をたどって静かに確かめている開発者

AIにデッドコード・重複を洗わせる|安全に消すための確認手順

リポジトリを開くと、いつからあるのか分からない関数がいくつも残っている。名前からして、たぶんもう使っていない。でも、消してビルドが通っても、本番のどこかでこっそり呼ばれていたらと思うと、指が止まる。

そこでAIに「未使用のコードを洗い出して」と頼むと、一覧はあっけないほど早く出てきます。ずらりと並んだ関数名を見て、少しだけほっとして——次の瞬間、この一覧、どこまで信じていいんだろうと、また手が止まる。

その慎重さは、正しい感覚です。デッドコードの判定は、AIがいちばん自信満々に外しやすい種類の仕事だからです。この記事では、AIに探させるところと、人が裏を取るところをはっきり分けて、戻せる形で少しずつ消していく手順を整理します。全部を一度にきれいにする話ではありません。今日、1つだけ安心して消せるようになるための型です。

結論:AIは「消す候補を挙げる」のは得意ですが、「消してよいと判定する」のは苦手です。だから、①範囲を1ディレクトリ・1テーマに絞って洗わせる → ②AIの一覧を"候補"として受け取る(判断はさせない) → ③静的解析・全文検索・実行ログの3方向で裏を取る → ④1テーマずつ、戻せる単位で消す、の順で進めます。消す判断は人が持ったまま、探す手間だけAIに預ける。それが安全で、いちばん速い進み方です。

削除は、機能追加と違って「うまくいっても誰も気づかない」仕事です。だからこそ、うまくいかなかったときにすぐ戻せる形にしておくことが、そのまま安心につながります。

なぜ「消せないコード」がたまっていくのか

責任は、たぶん誰にもありません。コードが消えずに残るのには、はっきりした理由があります。

そしてもうひとつ、最近特有の理由があります。AIに書かせるコードが増えると、似た処理が増えやすいことです。前に頼んだことを覚えていないAIは、必要になるたびに新しい関数を作ります。一つひとつは正しくても、リポジトリ全体で見ると、同じような処理が少しずつ違う形で散らばっていく。

つまりこれは、あなたの片付けが下手だから起きているのではなく、開発の進め方の副産物です。だからこそ、意志の力ではなく手順で片付けます。

AIが得意なこと・苦手なこと

本当にもう誰も通らない未使用の通路と、見えにくいけれど裏から実際に人が通っている使用中の通路を左右に並べ、見た目だけでは区別できないことを示した比較図
見た目はどちらも「使われていなさそう」。裏に道がつながっていないかを確かめるのが、人の仕事

まず、AIとの役割分担をはっきりさせておきます。ここがぼやけたまま進むと、結局いちばん危ない使い方になります。

AIが得意なこと(任せてよい)

AIが苦手なこと(人が持つ)

いちばん危ないのは、AIが自信を持って断言してくれることです。「この関数はどこからも参照されていないため、安全に削除できます」——この一文は、AIのハルシネーション(もっともらしい誤り)と同じ顔つきで出てきます。文章の強さは、根拠の強さではありません。

だから、AIには候補を出させるところまでにして、判定は次章の3方向の裏取りに任せます。

消してはいけない「使われていないように見えるコード」

裏取りの話に入る前に、静的な参照検索では見つけにくい呼ばれ方を押さえておきます。ここを知らないと、grepで0件だったから安心、と進んでしまいます。

「未使用に見えるけれど使用中」の代表格が、この8つです。AIに候補を出させるときは、この観点で自己申告させると、見落としがぐっと減ります(プロンプトの型は後半に載せます)。

安全に消す4つのステップ

流れはこうです。この順に進めると、途中で怖くなっても、いつでも止まれます。

ステップやることひとことで言うと
①絞る洗う範囲を1テーマに限定する「全部やらない」
②洗うAIに候補と根拠を出させる「判定はさせない」
③裏を取る解析・検索・ログの3方向で確認「本当に未使用か」
④消す戻せる単位で少しずつ消す「いつでも戻せる」

いちばん効くのは、地味ですが①の「絞る」です。ここを飛ばして「リポジトリ全体の未使用を洗って」と頼むと、精度の低い長大な一覧が返ってきて、結局どれも消せません。

ステップ1:洗う範囲を1テーマに絞る

範囲を狭くするほど、AIの精度は上がります。AIコーディングの安全なスコープ設計と同じ考え方です。

絞り方の例です。

このとき、AIにはコードだけでなく前提も一緒に渡します。「このサービスは他チームからも呼ばれている」「バッチは別リポジトリにある」——こうした既存コードベースの文脈を先に伝えるだけで、無責任な「削除可能です」が減ります。

ステップ2:AIに候補と根拠を出させる(判定はさせない)

ここでの頼み方のコツは、結論ではなく材料を出させることです。「消してよいか」ではなく、「消してよいか判断するために、私は何を確かめればいいか」を聞きます。

出させたいのは、この4つです。

  1. 候補の場所(ファイルと関数・クラス名)
  2. なぜ未使用と思ったかの根拠(どこを見て、何が無かったのか)
  3. 確信度と、その理由(「渡された範囲では参照が見つからない」なのか「明らかに旧実装」なのか)
  4. 見えていない参照経路の可能性(前章の8パターンのうち、どれに当てはまりうるか)

4つ目が肝心です。AIに自分の視界の外を自己申告させると、「設定ファイルからの参照までは確認できていません」といった但し書きが付いてきます。この但し書きが、そのまま次のステップの確認リストになります。

重複コードを洗わせるときは、もう一つ質問を足します。「これは同じ役割ですか、それとも、たまたま似ているだけですか」。似ているからという理由だけで無理に共通化すると、あとで片方だけ仕様が変わったときに、共通化した関数がフラグだらけになっていきます。重複の解消は、目的が同じものだけ。ここは人が決める場所です。

ステップ3:3方向で裏を取る

AIの候補が出たら、AIの外で確かめます。3方向から見ると、見落としがかなり減ります。

(1) 言語の仕組みで確かめる

まずは、その言語やビルドツールが元から持っている未使用検出に頼ります。コンパイラ・型チェッカの未使用警告、Linterの未使用変数・未使用インポート検出、未使用エクスポートの検出ツールなど、言語ごとに定番の仕組みがあります。AIの推測と違って、これらは構文を解析した結果なので、根拠がはっきりしています。

ただし、これらも前章の動的な呼び出しは苦手です。「機械が0件と言った」も、まだ根拠の1つ目と考えてください。

(2) 全文検索で、言語の外まで探す

次に、関数名・クラス名をリポジトリ全体の全文検索にかけます。ポイントは、対象を広げることです。

名前がありふれている場合は、部分一致で拾いすぎることもあります。逆に、文字列で組み立てられた名前(接頭辞+変数)は、そもそも引っかかりません。検索で見つかったら使用中、見つからなくても未使用とは限らない——この非対称を覚えておくと安全です。

(3) 実際に通ったかをログで確かめる

いちばん確実なのは、本番で通っているかどうかです。

この「消す前に、まず見えるようにする」は遠回りに見えて、いちばん心臓に優しいやり方です。数週間から、月次・年次の処理が絡むならその周期をまたぐまで待ちます。年に1回しか動かない処理を、2週間の無風で判断してはいけません。何をログに出しておけばよかったかの観点は、ログ出力の不足をAIに指摘させるにまとめました。

3方向のうち、(3)が取れるなら(3)がいちばん強い根拠です。急ぎでないなら、ログを仕込んで待つ。それが結局、いちばん速いことが多いです。

ステップ4:戻せる単位で消す

裏が取れたら、いよいよ消します。ここでも一気にはいきません。

コメントアウトして残す、という選択肢もありますが、あまりおすすめしません。消えていないコードは、次の人にとって"消していいのか分からないコード"のままです。履歴に残っているなら、思い切って消したほうが、リポジトリは軽くなります。

ありがちな落とし穴と、その回避

どれも、根っこは同じです。「消してよい」は証明が要る側の主張で、「まだ消さない」は保留のままでいい。急がなくて大丈夫です。

明日からやること(小さく始める3つ)

いきなりリポジトリ全体に手を付けず、まずこの3つから。

  1. 1ディレクトリだけ選んで、AIに候補と根拠を出させる:判定は求めず、「何を確かめればいいか」まで聞く。
  2. 候補を1つだけ選んで、全文検索を設定ファイルとテンプレートまで広げてかける:これだけで「実は使用中」が見つかることがあります。
  3. 確信が持てない1つに、ログを1行だけ仕込む:判断を、来月の自分に渡してあげる。これも立派な前進です。

今日ひとつ消せなくても大丈夫です。「これは未使用、これは要確認」と仕分けできた時点で、リポジトリはもう整理され始めています。

コピーして使うプロンプトの型

未使用コードの候補を洗わせる

以下のコードについて、使われていない可能性のある関数・クラス・ファイルの
「候補」を挙げてください。削除してよいかの判断はしないでください。

【前提】
- 対象範囲:(ディレクトリ/機能を書く)
- このコードは(他チーム/別リポジトリ/バッチ)からも呼ばれる可能性が(ある/ない)
- フレームワーク・DIコンテナ:(あれば書く)

【出してほしいもの】各候補について、
1. 場所(ファイル・シンボル名)
2. 未使用と考えた根拠(どこを見て、何が無かったか)
3. 確信度(高/中/低)とその理由
4. あなたからは見えていない参照経路の可能性
   (リフレクション等の動的呼び出し/フレームワークの規約による自動呼び出し/
     設定ファイル・DIからの指定/テンプレート・SQL・ジョブ定義/別リポジトリ/
     機能フラグでオフ中/例外時のみ通る経路/テストからのみ参照)

渡した範囲の外は「確認できていない」と正直に書いてください。

重複コードを洗わせる

以下のコードから、処理が重複している箇所の候補を挙げてください。

各候補について、次を分けて書いてください。
- どこが同じで、どこが違うか(差分を具体的に)
- 「同じ役割の重複」か「たまたま似ているだけ」か、その判断理由
- 共通化した場合に増える引数・分岐(複雑になるなら、そう書いてください)
- 共通化しないほうがよい理由が思いつく場合は、それも

共通化の実装はまだしないでください。まず候補と判断材料だけをください。

消す前のチェックリスト(コピーして使えます)

削除の候補ごとに、上から確認します。全部に○が要るわけではなく、(3)のどれか1つでも根拠が取れているかが目安です。

候補を受け取ったとき

消す前の裏取り

消すとき

重複を共通化するとき

最後に

削除は、報われにくい仕事です。うまくやっても機能は増えず、誰も気づかない。それでも誰かがやらないと、次に触る人が同じところで指を止め続けることになります。

使われていないコードを1つ確かめて消し切り、少し身軽になったリポジトリを前に落ち着いて次へ進もうとしている開発者

消せなかったコードが残っているのは、あなたが慎重すぎたからではありません。壊さないことを優先してきた、それだけのことです。その慎重さは、これからも手放さなくていい。慎重なまま、確かめる手順だけを増やせば、少しずつ消していけます。

一度に全部きれいにしなくて大丈夫です。今日ひとつ「これは未使用」と言い切れたなら、それはもう、次に触る人への贈り物になっています。

よければ、こちらも

関連用語