結論:デッドコード(到達しない・呼ばれないコード)と未使用コードの削除は、Claude Codeに「まず影響範囲を洗い出させ、テストで安全網を張ってから、小さな単位で刻んで消す」のが安全です。一括削除を鵜呑みにせず、差分は必ず人が確認します。
- 準備が9割:削除前にテストの有無と「使われていない」の定義(実行時 / ビルド時 / 外部公開API)を確定させる。
- 影響範囲を先に出す:消す前にClaude Codeへ参照箇所・呼び出し元・動的参照を列挙させ、人が読める形で確認する。
- 小さく刻む:1コミット1意図(未使用import削除、到達不能分岐削除など)で進め、振る舞いが変わらないことをテストで担保する。
対象読者:肥大化したコードベースを抱える開発者・PM・テックリード(Claude Code導入検討者・実装者)。
今日やること:まずは「削除候補リストだけ作って、消さないで」とClaude Codeに頼み、削除対象の棚卸しから始める。
動作環境:Claude Code(2026年6月時点)、git管理されたリポジトリ、CI上で動くテストスイートを前提とします。言語・フレームワークは問いませんが、本記事のサンプルはTypeScript/Pythonを想定しています。
コードベースが大きくなると、誰も呼んでいない関数、コメントアウトされたまま放置された塊、フラグで永久にオフになった分岐が溜まっていきます。これがデッドコード・未使用コードです。読むときのノイズになり、レビューを重くし、ときに「使われていると勘違いした改修」を生みます。Claude Codeはこの掃除を大きく加速してくれますが、「一括で消して」と頼んで鵜呑みにすると、動的に呼ばれていたコードまで巻き込んで壊すのが典型的な事故です。本記事では、安全に消すための手順を実装目線で整理します。

デッドコードと未使用コードの違いを先に定義する
掃除を始める前に、何を「不要」とみなすかを揃えておくと事故が減ります。一般にデッドコード(dead code)とは、実行されても結果に影響しない、あるいは到達できないコードを指します(参考:Wikipedia「Dead code」)。一方未使用コード(unused code)は、定義されているがどこからも参照されていない関数・変数・importなどを指します。
厄介なのは「使われていない」の判定が、文脈によって変わる点です。
- 静的に未使用:どのファイルからもimport・参照されていない(リンターやtsc、coverageで検出しやすい)。
- 動的に使われている:文字列キーやリフレクション、DIコンテナ、設定ファイル経由で呼ばれている(静的解析では「未使用」に見えるが実際は使われている)。
- 外部公開API:自リポジトリ内では参照ゼロでも、別チームや外部利用者が使っている可能性がある。
この3層を区別しないまま「参照ゼロだから消す」と進めると、動的参照や公開APIを壊します。だからこそ、削除はリンターの赤線を消す作業ではなく、「本当に消してよいか」を確認する作業として設計します。リファクタリングの考え方としても、デッドコードの除去は独立した小さな変更として扱うのが定石です(参考:Refactoring Catalog「Remove Dead Code」)。
ステップ1:削除前の準備(テストの有無と範囲の確定)
最初にやるべきは削除ではなく、安全網の確認です。次の3点を先に固めます。
- テストの有無を確認する — 削除対象まわりにテストがあるか。なければ、消す前に「振る舞いを固定するテスト(特性テスト)」を足せるか検討する。
- 「未使用」の定義を決める — 静的に未使用なものだけを対象にするのか、動的参照・公開APIも棚卸しするのか、スコープを言語化する。
- 対象範囲を区切る — 「このディレクトリだけ」「このモジュールだけ」と範囲を切る。リポジトリ全体を一度に掃除しようとしない。
Claude Codeには、まず消さずに棚卸しだけを頼みます。CLAUDE.mdに対象範囲や除外ルール(生成コード、公開APIなど)を書いておくと、毎回の前提共有が省けます(参考:Claude Code公式ドキュメント「Memory(CLAUDE.md)」)。
このリポジトリの src/utils/ 配下に限定して、未使用の可能性があるコードを棚卸ししてください。
【やること】
- エクスポートされているが他ファイルからimport・参照されていない関数/定数を列挙
- 到達不能と思われる分岐(常にfalseになる条件、return後のコード)を列挙
- コメントアウトされたコードブロックを列挙
【やらないこと】
- この段階ではコードを削除しないでください(候補リストのみ)
【注意して報告してほしいこと】
- 文字列キー・リフレクション・DI・設定ファイル経由で動的に呼ばれている可能性があるものは「動的参照の疑い」と明記
- 公開APIとして外部に使われている可能性があるものは「公開APIの疑い」と明記
不足している情報があれば、最初に質問してから作業を開始してください。
仮定した点は必ず「仮定」と明記してください。
ここで「削除しないで」と明示するのが効きます。いきなり消す提案をさせず、まず人が読める候補リストに落とすことで、後段の判断がしやすくなります。
ステップ2:影響範囲をClaude Codeに洗い出させる
候補が出たら、1件ずつ「本当に消してよいか」の根拠を確認します。削除の安全性は、参照箇所をどれだけ網羅できたかで決まります。Claude Codeに参照グラフを言語化させ、人が判断できる形にします。
候補リストのうち getLegacyUserToken という関数について、削除してよいか判断したいです。
次を調べて報告してください。
1. この関数を呼んでいる箇所(直接import・再エクスポート経由を含む)
2. 文字列で関数名を参照している箇所("getLegacyUserToken" でのgrep結果)
3. テスト・設定ファイル・スクリプトからの参照
4. 公開エントリポイント(index.ts の re-export 等)に含まれているか
結論として「静的に未使用」「動的参照の疑いあり」「公開APIの疑いあり」のどれかを根拠付きで判定してください。
判断に必要な情報が足りない場合は、削除を保留して理由を教えてください。
この洗い出しは、リンターやcoverageの結果と突き合わせるのが重要です。Claude Codeの調査結果だけ、ツールの結果だけ、どちらも単独では穴があります。静的解析が「未使用」と言い、coverageでも一度も通っておらず、Claude Codeのgrepでも参照が見つからない——この3つが揃ったものから消していくと安全度が上がります。
動的参照が疑われるものは、いったん削除せずに警告ログを仕込んで様子を見るという選択肢もあります。「もし呼ばれたらログを残す」ようにしておき、一定期間呼ばれないことを確認してから消す、という二段構えです。
ステップ3:小さく刻んで消す(1コミット1意図)
削除の実行は、できるだけ小さな単位に分けます。「未使用importの削除」「到達不能分岐の削除」「コメントアウト塊の削除」をまとめて1回でやると、後で問題が起きたときにどの変更が原因か切り分けられません。1コミット1意図を徹底します。
src/utils/format.ts について、次の1種類だけを削除してください。他の変更は混ぜないでください。
- 未使用のimport文のみ削除(関数本体やロジックには手を付けない)
削除後に変わったことを diff で示してください。
diff を見て私が確認してから、次の種類の削除に進みます。
「他の変更は混ぜないで」と明示することで、Claude Codeが気を利かせて変数名を直したりフォーマットを変えたりするのを防げます。掃除のコミットに無関係な変更が混ざると、レビュアーが「これは削除だけのはず」という前提で見られなくなり、結局すべてを精査するハメになります。
大きなディレクトリをまとめて掃除したい場合でも、ファイル単位・種類単位でファンアウトします。1回のセッションで全ファイルを書き換えさせず、サブエージェントに探索を委譲してコンテキストを節約しつつ、削除そのものは小さく分けて進めると安定します(参考:Claude Code公式ドキュメント「Subagents」)。
ステップ4:振る舞いが変わらないことをテストで担保する
デッドコードの削除は、定義上「振る舞いを変えない変更」のはずです。それを確認するのがテストです。削除のたびにテストを走らせ、グリーンであることを確認してから次へ進みます。コードが自分自身で正しさを検証できる状態にしておくことが、安心して削除を続けられる前提になります(参考:Martin Fowler「SelfTestingCode」)。
テストがない領域は、削除前に最小限の安全網を張ります。
これから src/billing/ の未使用コードを削除する予定ですが、この領域にはテストがありません。
削除作業の前に、現状の振る舞いを固定する特性テスト(characterization test)を追加してください。
- 既存の主要な入出力パターンを、現状の出力そのままでアサートする(リファクタの正解ではなく「今の挙動」を記録する目的)
- 外部依存はモックして、純粋に振る舞いの差分を検出できるようにする
テスト追加と削除作業は分けて、まずテストだけ提案してください。
特性テストは「正しい仕様」を書くものではなく、今の挙動を記録して、削除で挙動が変わらないことを検出するためのものです。これがあると、「消したつもりが、実は分岐の副作用に依存していた」というケースを早期に拾えます。テスト自動化の組み立て方は、Claude CodeでのQA・テスト自動化ガイドも参考にしてください。
ステップ5:レビューで「消し過ぎ」を確認する
テストがグリーンでも、それはテストでカバーされた範囲で問題がないことしか保証しません。テストの外側に動的参照や公開APIがある可能性は残ります。だから削除の差分は必ず人がレビューします。
レビュー観点をClaude Code自身に整理させて、人が確認する手間を下げる使い方もあります。
今回のデッドコード削除のPR差分について、レビュー観点を整理してください。
- 削除した各要素が「動的に参照されていないか」をもう一度チェックし、見落としがあれば指摘
- 公開API(index.ts の re-export 等)に含まれていたものを消していないか確認
- 削除に伴って暗黙に依存していた副作用がなかったか(ログ出力・初期化処理など)
これはあなたの判断を最終結論にするためではなく、私がレビューする際のチェックリストとして使います。
不確実な点は「要確認」と明記してください。
ここで大事なのは、Claude Codeのレビューを最終結論にしないことです。AIに削除させてAIにレビューさせると、同じ見落としをすり抜けます。最終的な「消してよい」の判断は人が下します。レビューの効率化についてはClaude Codeでコードレビューを効率化するガイドでも詳しく扱っています。
【要注意】よくある失敗パターンと回避策
失敗1:「未使用のコードを全部消して」と一括で頼む
❌「このリポジトリの未使用コードを全部消して」
⭕「src/utils/ に限定して、未使用importだけ削除して。diffを見せて」
なぜこれが重要か:一括削除は、動的参照・公開API・設定経由の呼び出しまで巻き込みます。範囲と種類を絞り、人が差分を確認できる粒度に分けるのが安全です。
失敗2:静的解析の「未使用」を鵜呑みにする
❌ リンターが「unused」と言ったから即削除
⭕ 静的解析 + coverage + Claude Codeのgrep、3つが揃ったものから削除
なぜこれが重要か:文字列キーやリフレクション、DI経由の呼び出しは静的解析で「未使用」に見えます。複数の根拠を突き合わせることで、動的参照の見落としを減らせます。
失敗3:テストなしで大きく消す
❌ テストがない領域をまとめて削除してコミット
⭕ 特性テストを先に足し、グリーンを確認しながら小さく消す
なぜこれが重要か:テストなしの大規模削除は、壊れたことに気づけません。安全網を張ってから刻むことで、振る舞いの変化を検出できます。
失敗4:AIの削除提案を差分確認せずマージする
❌ Claude Codeが「不要なので削除しました」と言ったのでそのまま採用
⭕ 削除diffを人が読み、消えたものが本当に不要か1件ずつ確認
なぜこれが重要か:正直に言うと、AIの一括書き換えは「ついでに必要なものまで消す」ことがあります。差分を人が確認する工程は省略できません。AIは補助ツールであり、最終判断者ではありません。
削除を継続的に回す仕組みにする
デッドコードの掃除は一度きりではなく、溜まる前に消し続けるのが理想です。1回ごとの削除を小さく保ち、テストとレビューを通す流れをチームの習慣にすると、コードベースが肥大化しにくくなります。技術的負債としてまとめて返済する観点は、Claude Codeで技術的負債を返済する実践ガイドで別軸から整理しています。本記事は「個別の不要コードを安全に消す」手順に絞っているので、負債全体の優先順位付けと合わせて読むと全体像がつかめます。
また、Claude Codeでの基本的なワークフロー(Plan Mode、差分の扱い、コミット運用)はClaude Code実践テクニック完全ガイドにまとまっています。削除作業もこの基本動作の上に乗せると安定します。
よくある質問(FAQ)
Q1. デッドコードと未使用コードは何が違いますか?
デッドコードは「実行されても結果に影響しない/到達できないコード」、未使用コードは「定義されているがどこからも参照されていないコード」を指します。実務では重なる部分も多いですが、削除前に「どの意味で不要か」を区別すると判断ミスが減ります。
Q2. Claude Codeに一括で削除させても大丈夫ですか?
推奨しません。動的参照・公開API・設定経由の呼び出しを巻き込むリスクがあります。範囲と種類を絞り、小さく刻んで、差分を人が確認するのが安全です。
Q3. テストがない領域はどう削除すればよいですか?
削除の前に、現状の振る舞いを固定する特性テスト(characterization test)を足すのが定石です。「正しい仕様」ではなく「今の挙動」を記録し、削除で挙動が変わらないことを検出できるようにします。
Q4. 静的解析が「未使用」と言えば消してよいですか?
そのまま信じるのは危険です。文字列キーやリフレクション、DI経由の呼び出しは静的解析で「未使用」に見えます。静的解析・coverage・Claude Codeのgrepなど複数の根拠を突き合わせてから削除してください。
Q5. 削除して問題が起きたらどう戻しますか?
1コミット1意図で小さく刻んでおけば、該当コミットだけをrevertして切り戻せます。だからこそ、まとめて消さず、種類・範囲ごとにコミットを分ける運用が効きます。
今日からできる3アクション
- 棚卸しから始める:Claude Codeに「削除せず、未使用候補リストだけ作って」と頼み、対象を可視化する。
- 1種類だけ消す:未使用importなど、影響の小さい1種類だけを小さく削除し、テストとdiff確認の流れを体に通す。
- 動的参照の確認を習慣化する:消す前に「文字列参照・DI・設定経由で呼ばれていないか」をClaude Codeとツールの両方で突き合わせる。
不要コードの削除に難しい理論は要りません。難しいのは「本当に不要か」を確認する地味な工程で、Claude Codeはその確認を加速する相棒として使うのが正解です。一括削除を任せきりにせず、洗い出し・小さな削除・テスト・人のレビューを回していきましょう。
著者プロフィール
佐藤傑(さとう・すぐる)。株式会社Uravation代表取締役。X(@SuguruKun_ai)フォロワー約10万人。100社以上の企業向けAI研修・導入支援を展開。著書『AIエージェント仕事術』(SBクリエイティブ)。SoftBank IT連載7回執筆。