デッドコード

実行されることのないコードで、コードベースの可読性と保守性を低下させる

リファクタリング品質

デッドコードとは

デッドコード (Dead Code) は、プログラム内に存在するが実行されることのないコードの総称である。到達不能なコード、使われていない関数や変数、コメントアウトされたコードブロックが該当する。デッドコードは直接的なバグにはならないが、コードベースの可読性と保守性を確実に低下させる。

デッドコードの種類

到達不能コード

function process(value: number) {
  if (value < 0) return 'negative';
  if (value >= 0) return 'non-negative';
  return 'unreachable'; // ❌ 到達不能: 上の条件で全パターンをカバー済み
}

未使用の宣言

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 で未使用変数・インポートを検出
npx eslint --rule 'no-unused-vars: error' --rule 'no-unused-imports: error' src/

# TypeScript コンパイラで未使用を検出
tsc --noUnusedLocals --noUnusedParameters

# knip: プロジェクト全体の未使用エクスポート、依存関係を検出
npx knip

knip は特に強力で、未使用のエクスポート、未使用の依存関係 (package.json)、未使用のファイルをプロジェクト全体で検出する。

削除の判断基準

削除の判断基準を以下にまとめる。

状況判断
未使用の関数・変数即座に削除
コメントアウトされたコード即座に削除 (Git 履歴で復元可能)
フィーチャーフラグの残骸フラグごと削除
将来使う予定のコード削除。必要になったら書き直す
外部から呼ばれる可能性のある API呼び出し元を調査してから判断

「後で使うかも」は削除しない理由にならない。YAGNI (You Aren't Gonna Need It) の原則に従い、今使われていないコードは削除する。

実践的な知識は関連書籍でも得られる。

この記事は役に立ちましたか?

関連用語

関連する記事