不要なコードの除去方法は?デッドコード削除の方法とツール選定

不要なコードの除去とは?なぜ重要なのか

ソフトウェア開発を続けていくと、コードベースには必ず「使われていないコード」が蓄積されていきます。これらはデッドコード不要コードと呼ばれ、放置すると深刻な技術的負債となります。

不要なコードとは、プログラムの実行時に決して呼び出されることのないコード、または実行されても何の意味も持たないコードのことです。具体的には、未使用の関数、到達不能な条件分岐、コメントアウトされた古いコード、廃止された機能の残骸などが該当します。

なぜ不要なコードの除去が重要なのか

実際の開発現場では、大規模プロジェクトの20〜30%のコードが未使用というデータもあります。

これは決して小さな問題ではありません。不要なコードは目に見えない形で開発チームの生産性を奪い、バグの温床となり、新規メンバーのオンボーディングを困難にします。

ある企業では、継続的な不要コード削除プロセスを導入し、18万行のコードを削除することに成功しました。その結果、ビルド時間が30%短縮され、新機能開発のスピードが大幅に向上したという報告があります。

この記事では、不要なコードを安全に検出し、削除し、予防するための実践的な方法を、具体的なツールやコード例とともに徹底解説します。JavaScript、Python、PHP、Rubyなど主要言語に対応した内容で、明日からすぐに実践できる知識を提供します。

どんなコードが「不要」なのか?7つのパターン

不要なコードを削除する前に、まず「どのようなコードが不要なのか」を正確に理解する必要があります。ここでは7つの典型的なパターンを紹介します。

1. 未使用の変数・定数・関数・クラス

最も分かりやすい不要コードです。定義されているものの、プログラムのどこからも呼び出されていないコードが該当します。

悪い例(JavaScript)

// この関数は定義されているが、どこからも呼ばれていない
function calculateDiscount(price, rate) {
  return price * (1 - rate);
}

// 未使用の定数
const MAX_RETRIES = 5;

function processOrder(order) {
  // calculateDiscount は使われず、直接計算している
  const finalPrice = order.price * 0.9;
  return finalPrice;
}

改善後

function processOrder(order) {
  const finalPrice = order.price * 0.9;
  return finalPrice;
}
// 未使用のcalculateDiscount関数とMAX_RETRIES定数を削除

2. デッドコード(到達不能コード)

プログラムのロジック上、決して実行されることのないコードです。これには到達不能コード冗長コードの2種類があります。

到達不能コードの例(Python)

def process_data(value: int) -> int:
    if value < 0:
        return 0
    return value + 10
    print("処理完了")  # この行は決して実行されない(到達不能)

冗長コードの例(PHP)

function plusOne(int $a): int 
{
    // int型指定があるため、nullチェックは冗長
    if (is_null($a)) {
        return 0;
    }
    return $a + 1; 
}

3. コメントアウトされたコード

バージョン管理システム(Git等)があれば、コメントアウトされたコードは完全に不要です。履歴はすべてGitが管理しています。

悪い例

function updateUser(userId, data) {
  // 旧実装(2023年まで使用)
  // const user = database.findById(userId);
  // user.name = data.name;
  // user.save();
  
  // 新実装(2024年から)
  return database.update(userId, data);
}

改善後

function updateUser(userId, data) {
  return database.update(userId, data);
}
// コメントアウトされた旧実装を完全に削除
// 必要なら git log で履歴を確認できる

4. 廃止された機能のコード

サービスの成長に伴い、使われなくなった機能のコードが残り続けることがあります。例えば、ガラケー対応コード、旧バージョンのAPI、削除されたページへのルーティングなどです。

// 2020年に廃止されたガラケー判定機能
function isMobilePhone(userAgent) {
  return /DoCoMo|KDDI|SoftBank/.test(userAgent);
}

// この関数を呼び出すコードはもう存在しない
// しかしコードベースには残り続けている

5. 重複コード(DRY原則違反)

同じロジックが複数箇所にコピー&ペーストされているケースです。厳密には「不要」ではありませんが、保守性を著しく低下させます。

6. 使われていないimport/export/依存パッケージ

特にJavaScript/TypeScriptプロジェクトで問題になります。未使用のimportはバンドルサイズを肥大化させ、パフォーマンスに悪影響を与えます。

悪い例(TypeScript)

import { useState, useEffect, useCallback, useMemo } from 'react';
import lodash from 'lodash';  // 未使用
import axios from 'axios';    // 未使用

function UserProfile() {
  const [name, setName] = useState('');
  // useEffect, useCallback, useMemo, lodash, axios は使われていない
  return <div>{name}</div>;
}

7. 意味不明なコメント・古いドキュメント

コード修正時にコメントの更新を忘れると、コメントとコードが矛盾し、読者を混乱させます。

悪い例

// 2つの変数を足す
const result = a - b;  // 実際は引き算している!

不要なコードが生まれる5つの原因

不要なコードは誰も意図して作っているわけではありません。しかし開発プロセスの中で自然発生的に生まれてしまいます。

1. 仕様変更による実装の廃止

開発中にA、B、C機能を予定していたが、AとBのリリース後にC機能の開発が中止された場合、先行して実装されたCの処理が不要コードとして残ります。

2. リファクタリング時の削除漏れ

不具合修正や機能改善で処理を書き換えた際、古い実装を削除し忘れることがよくあります。修正に集中しているため、周辺のクリーンアップまで意識が向きません。

3. 機能追加時の先行実装の放置

「将来使うかもしれない」という理由で実装された機能が、結局使われないまま残り続けるパターンです。YAGNI(You Aren't Gonna Need It)原則に反しています。

4. チーム間のコミュニケーション不足

フロントエンドチームがAPIエンドポイントを使わなくなったのに、バックエンドチームにその情報が伝わらず、エンドポイントが残り続けるケースです。

5. 削除に対する心理的障壁

「怖い」という感情が最大の原因です。削除することで何かが壊れるのではないか、誰かがまだ使っているのではないか、という不安から削除を躊躇します。

不要なコードを削除しないとどうなる?6つのデメリット

1. コード可読性の低下

不要なコードが混在すると、「このコードは今も使われているのか?」という疑問が常につきまといます。grepで検索した際に無関係な結果が大量に表示され、本当に必要な情報を見つけるのに時間がかかります。

2. 開発効率の悪化

新機能を追加する際、既存コードを理解する必要がありますが、不要なコードまで読み解く必要が生じます。これは認知的負荷を増大させ、開発者の貴重な時間とエネルギーを奪います。

3. バグの温床

デッドコードは直接実行されないため無害に見えますが、リファクタリングの際に誤って呼び出されたり、誤解を招いて新しいバグを生む原因になります。

4. パフォーマンスへの悪影響

廃止された機能のコードが裏で動き続けると、不要な処理が実行され、パフォーマンスを「じわじわと悪化」させます。JavaScriptではバンドルサイズの肥大化により、初期ロード時間が増加します。

5. メンテナンスコストの増加

言語やフレームワークのバージョンアップ時、使われていないコードまで修正対象になります。例えばPHP 7から8への移行時、未使用の関数の非推奨警告にも対応しなければなりません。

6. 新規メンバーのオンボーディング困難

新しく参加したメンバーが「このコードは何のためにあるのか?」と質問しても、誰も答えられないという事態が発生します。これは組織的な知識の損失を意味します。

不要なコードを削除する5つのメリット

一方で、不要なコードを削除することで得られるメリットは計り知れません。

1. コードベースの明瞭化

本当に必要なコードだけが残るため、システム全体の見通しが良くなります。新規メンバーも迅速にキャッチアップできます。

2. 開発速度の向上

既存コードの理解に費やす時間が減少し、新機能開発やバグ修正のスピードが上がります。ある企業では削除後に開発速度が40%向上した事例もあります。

3. バグの減少

コード量が減れば、バグが潜む場所も減ります。シンプルなコードは理解しやすく、修正もしやすくなります。

4. ビルド時間・実行速度の改善

JavaScriptプロジェクトでは、Tree Shakingと組み合わせることでバンドルサイズが大幅に削減されます。これにより初期ロード時間が短縮され、ユーザー体験が向上します。

5. チーム全体の生産性向上

クリーンなコードベースはチームの士気を高めます。「美しく整理された工場」で働くことは、開発者のモチベーション向上にもつながります。

不要なコードを見つける8つの方法【実践編】

ここからは具体的な検出方法を紹介します。複数の手法を組み合わせることで、より確実に不要コードを発見できます。

方法1:静的解析ツールを使う

静的解析ツールは、コードを実行せずに構造を分析し、未使用コードを検出します。

言語別推奨ツール一覧

言語

ツール名

特徴

インストール

JavaScript/TypeScript

Knip

未使用export/依存関係検出に特化

npm install -D knip

JavaScript/TypeScript

ESLint

no-unused-vars ルール

npm install -D eslint

Python

vulture

デッドコード検出専用

pip install vulture

Python

Ruff

高速で包括的なリンター

pip install ruff

PHP

PHPStan

レベル4以上でデッドコード検出

composer require --dev phpstan/phpstan

Ruby

unused

未使用メソッド・定数検出

gem install unused

Java

UCDetector

Eclipse plugin

-

Knipの使い方(JavaScript/TypeScript)

Knipは2023年から急速に普及している、JavaScriptプロジェクト向けの強力なツールです。

# インストール
npm install -D knip

# 実行
npx knip

# 自動修正(削除可能なimportを削除)
npx knip --fix

# ファイルも削除する場合
npx knip --fix --allow-remove-files

knip.json設定例

{
  "entry": ["src/index.ts"],
  "project": ["src/**/*.ts"],
  "ignore": ["src/**/*.test.ts"],
  "ignoreDependencies": ["@types/*"]
}

vultureの使い方(Python)

# インストール
pip install vulture

# プロジェクト全体をスキャン
vulture myproject/

# 信頼度60%以上のみ表示
vulture myproject/ --min-confidence 60

# レポートをファイル出力
vulture myproject/ > dead_code_report.txt

実行結果例

myproject/utils.py:15: unused function 'old_calculate' (60% confidence)
myproject/models.py:42: unused variable 'TEMP_CONSTANT' (100% confidence)
myproject/views.py:88: unused import 'datetime' (90% confidence)

方法2:コードカバレッジ分析

テストコードがあるプロジェクトでは、コードカバレッジを計測することで未使用コードを発見できます。

カバレッジ0%のコードは以下のいずれかです。

  • 本当に使われていない(削除候補)
  • テストが書かれていない(テスト追加が必要)

JavaScript(Istanbul/NYC)での計測

# インストール
npm install -D nyc

# テスト実行とカバレッジ計測
npx nyc npm test

# HTMLレポート生成
npx nyc --reporter=html npm test

Python(Coverage.py)での計測

# インストール
pip install coverage

# テスト実行とカバレッジ計測
coverage run -m pytest

# レポート表示
coverage report

# HTML詳細レポート
coverage html

方法3:アクセスログ解析

Webアプリケーションの場合、一定期間アクセスのないエンドポイントは削除候補です。

手順:

  1. 過去3〜6ヶ月のアクセスログを収集
  2. エンドポイント別のアクセス数を集計
  3. アクセス0のエンドポイントをリストアップ
  4. 該当コードを特定して検証

ログ解析の簡単な例(Linux)

# Nginxアクセスログから、アクセスのないURLを特定
cat access.log | awk '{print $7}' | sort | uniq -c | sort -n

方法4:コミット履歴分析

長期間変更されていないファイルは、不要コードの可能性があります。

# 過去1年間変更されていないファイルを探す
git log --since="1 year ago" --name-only --pretty=format: | sort -u > changed_files.txt
git ls-files | grep -vxF -f changed_files.txt

方法5:依存関係グラフの可視化

モジュール間の依存関係を可視化し、孤立したモジュールを発見します。

Madge(JavaScript)

npm install -g madge

# 依存関係グラフを画像出力
madge --image graph.svg src/

# 循環依存を検出
madge --circular src/

方法6:IDE・エディタの機能活用

現代のIDEは未使用コードを自動でハイライトします。

VSCodeの場合

  • グレーアウトされた変数・関数 = 未使用
  • "Find All References"(Shift+F12)で参照箇所を確認
  • 0件なら削除候補

IntelliJ IDEA/PyCharmの場合

  • "Inspect Code" → "Unused declaration" で一括検出
  • "Safe Delete" で安全に削除

方法7:動的解析・本番環境でのカバレッジ取得

最も確実な方法は、本番環境で実際に実行されたコードを記録することです。

Rubyでの実装例(Coverageライブラリ使用)

require 'coverage'

Coverage.start(lines: true, branches: true, methods: true)

# アプリケーション実行

result = Coverage.result
# 実行されなかった行を特定

この手法を用いて、ある企業ではRailsアプリで3人×6日で不要コードの1/4を削除することに成功しました。

方法8:手動レビューとコードウォークスルー

ツールで検出できないものもあります

  • コメントアウトされたコード
  • 意味不明なコメント
  • 複雑な動的呼び出し

これらは目視とチームレビューで発見します。発見時はTODOコメントを残し、後でまとめて削除します。

Copy// TODO: この関数は2024年から未使用。次回リファクタリング時に削除
// function oldProcessing() { ... }

安全に削除する7ステップ【ステップバイステップ】

不要なコードを発見しても、いきなり削除するのは危険です。以下の手順で安全に進めましょう。

ステップ1:削除候補の特定とリスト化

検出ツールの結果をまとめ、優先順位をつけます。

削除しやすい順

  1. コメントアウトされたコード
  2. 明らかに未使用のimport
  3. テストカバレッジ0%の関数
  4. 長期間変更がないファイル
  5. 廃止された機能全体

ステップ2:影響範囲の調査

削除前に必ず影響範囲を確認します。

チェック項目

  • 全ファイルでのgrep検索
  • IDEの"Find Usages"機能
  • 動的呼び出し(リフレクション等)の可能性
  • 外部システムからの参照(API等)
# 関数名で全ファイルを検索
grep -r "functionName" src/

# より厳密に検索(単語境界を考慮)
grep -rw "functionName" src/

ステップ3:チームへの共有と合意形成

大規模な削除の場合、事前にチームに共有します。

共有方法

  • Slack/チャットでの告知
  • ミーティングでの説明
  • Pull Request/Merge Requestでのレビュー依頼
  • ドメイン知識を持つメンバーへの確認

ステップ4:削除の実行

推奨:完全削除

Gitがあれば履歴は完全に保存されるため、迷わず削除します。

git rm src/old_module.py
git commit -m "Remove unused old_module (unused since 2023)"

非推奨:コメントアウト

コメントアウトは新たな不要コードを生むため避けます。どうしても不安な場合のみ、フィーチャーフラグで無効化する方法を検討します。

ステップ5:テストの実施

削除後は必ずテストを実行します。

テストレベル

  1. ユニットテスト(全件)
  2. 統合テスト
  3. E2Eテスト
  4. 手動での動作確認(重要機能)
  5. ステージング環境での検証
# 全テスト実行
npm test
# または
pytest
# または
./vendor/bin/phpunit

ステップ6:コードレビュー

有識者によるレビューで、見落としを防ぎます。

レビューポイント

  • 本当に未使用か
  • 動的呼び出しの可能性はないか
  • 追加で削除できるコードはないか
  • テストは十分か

ステップ7:デプロイと監視

段階的デプロイ

  1. ステージング環境での検証(1〜2日)
  2. カナリアリリース(本番の一部ユーザー)
  3. 全体ロールアウト

監視項目

  • エラーログ(404、500エラー)
  • アプリケーションメトリクス
  • ユーザーからの問い合わせ

問題があればすぐにロールバックできる体制を整えます。

# Gitで前のコミットに戻す
git revert HEAD

まとめ:今日から始める不要コード削除

不要なコードの除去は、一見地味な作業に見えますが、開発チームの生産性を大きく向上させる重要な活動です。18万行の削除に成功した事例が示すように、継続的に取り組むことで劇的な改善が期待できます。

今日からできるアクション

  1. 静的解析ツールを導入する
    • JavaScript → Knip
    • Python → vulture
    • PHP → PHPStan
  2. コードカバレッジを計測する
    • カバレッジ0%のコードをリストアップ
  3. コメントアウトされたコードを削除する
    • これは確実に不要
  4. チームで削除文化を醸成する
    • 「削除も開発」という意識の共有
    • 定期的なクリーンアップデーの設定

継続的改善のために

不要コードの削除は一度やれば終わりではありません。**Continuous Deleting(継続的削除)**として、開発プロセスに組み込むことが重要です。

  • 月1回のコードクリーンアップデー
  • CI/CDパイプラインでの自動検出
  • コードレビューでの削除視点の追加

不要なコードのない、クリーンで見通しの良いコードベースで、より生産的な開発を実現しましょう。まずは小さな一歩として、今日1つの未使用関数を削除することから始めてみてください。

記事を書いた人

LandingHub 編集部

LandingHub 編集部

LandingHub編集部です。 知見を持ったLandingHubスタッフが情報を発信しています。 表示速度に関する価値のある再現性の高いノウハウに関して、技術的な知識の少ない担当者の方でもわかりやすく解説していきます。
コラム一覧に戻る