デッドコード
実行されることのないコードで、コードベースの可読性と保守性を低下させる
デッドコードとは
デッドコード (Dead Code) は、プログラム内に存在するが実行されることのないコードの総称である。到達不能なコード、使われていない関数や変数、コメントアウトされたコードブロックが該当する。デッドコードは直接的なバグにはならないが、コードベースの可読性と保守性を確実に低下させる。
デッドコードの種類
到達不能コード
function process(value: number) {
if (value < 0) return 'negative';
return 'non-negative';
console.log('集計完了'); // ❌ 到達不能: return より後ろの文は実行されない
}
静的に到達不能と言えるのは、この例のように return・throw・break の後ろに文が続く場合だ。一方「条件で全パターンを網羅したから最後の行には来ない」という判断は危うい。if (value < 0) と if (value >= 0) を並べても、number 型には NaN があり NaN はどちらの比較も false になるため、最後の行に到達する。条件の網羅は型が取り得る値まで確認しないと断定できない。
未使用の宣言
import { format } from 'date-fns'; // ❌ インポートしたが使っていない
const MAX_RETRIES = 5; // ❌ 定義したが参照していない
function calculateTotal(items: Item[]) {
return items.reduce((sum, item) => sum + item.price, 0);
}
function calculateTax(amount: number) { // ❌ 定義したが呼び出していない
return amount * 0.1;
}
コメントアウト
function getUser(id: string) {
// const cache = await redis.get(id);
// if (cache) return JSON.parse(cache);
return db.users.findById(id);
}
「いつか使うかも」と残されたコメントアウトは、最も多いデッドコードだ。Git の履歴に残っているため、本当に必要になれば復元できる。
フィーチャーフラグの残骸
if (FEATURE_NEW_CHECKOUT) {
return renderNewCheckout(); // 常に true → else 節がデッドコード
} else {
return renderLegacyCheckout(); // ❌ 実質的にデッドコード
}
フラグの値は実行時に決まるため、この種の残骸はコンパイラや静的解析では見つからない。フラグの一覧と全面公開した日付を記録し、公開後は期限を決めて分岐ごと削除する運用で防ぐ。
なぜ有害なのか
- 読み手が「このコードは何のためにあるのか」と混乱する
- リファクタリング時に、デッドコードとの整合性を気にして変更を躊躇する
- コードレビューの対象が増え、レビュー効率が下がる
- バンドルサイズが不必要に増加する (Tree Shaking で除去されない場合)
- テストカバレッジの分母が増え、カバレッジ率が実態より低く見える
検出ツール
検出ツールの例を示す。
# ESLint で未使用変数を検出 (未使用インポートも no-unused-vars が報告する)
npx eslint --rule 'no-unused-vars: error' src/
# TypeScript コンパイラで未使用を検出
tsc --noUnusedLocals --noUnusedParameters
# knip: プロジェクト全体の未使用エクスポート、依存関係を検出
npx knip
未使用インポートの自動削除まで行いたい場合は eslint-plugin-unused-imports を入れて unused-imports/no-unused-imports を有効にする。これは no-unused-vars をインポート文とそれ以外に分割し、インポート側に自動修正を付けたプラグインで、ESLint 本体のルールではない。
knip は特に強力で、未使用のエクスポート、未使用の依存関係 (package.json)、未使用のファイルをプロジェクト全体で検出する。
削除の判断基準
削除の判断基準を以下にまとめる。
| 状況 | 判断 |
|---|---|
| 未使用の関数・変数 | 即座に削除 |
| コメントアウトされたコード | 即座に削除 (Git 履歴で復元可能) |
| フィーチャーフラグの残骸 | フラグごと削除 |
| 将来使う予定のコード | 削除。必要になったら書き直す |
| 外部から呼ばれる可能性のある API | 呼び出し元を調査してから判断 |
判断で気をつけたいのは、静的解析が追えない参照があることだ。文字列でのプロパティアクセス、依存性注入の設定ファイル、ビルド後に読み込まれる設定値から呼ばれるコードは「未使用」と報告されがちなので、検索とログの両方で使われていないことを確かめてから消す。
「後で使うかも」は削除しない理由にならない。YAGNI (You Aren't Gonna Need It) の原則に従い、今使われていないコードは削除する。
実践的な知識は関連書籍でも得られる。
この記事は役に立ちましたか?
関連用語
関連する記事
コードレビューが上手い人は何を読んでいるのか
的確なコードレビューができる人は、指摘を裏づける語彙と判断基準を持っています。レビュー力を支える 3 つの読書領域と、レビューに直結する知識の身につけ方を解説します。
IT パスポート参考書の選び方 - 完読できる 1 冊と過去問の組み合わせ
IT パスポート試験の参考書選びを「完読できるか」を軸に整理。イラスト型 / 絞り込み型 / 丁寧解説型などテキストの個性の見分け方、過去問題集との組み合わせ、年度版とシラバス対応の注意点を 2026 年 8 月時点の定番書で解説します。
技術書の読書ログを GitHub で管理する - エンジニアらしい記録法
技術書の読書記録を GitHub リポジトリで管理する方法を紹介します。Markdown で読書ノートを書き、コミット履歴で読書の軌跡を残す、エンジニアならではの読書ログ術です。