mcpField
C
codebase-refactoring

codebase-refactoring

github.com/kucherenko開発6.5k617 回インストール今日更新
リポジトリ

codebase-refactoring について

コードベースの重複コード、デッドコード、複雑度に取り組む、jscpd を使ったガイド付きスキルです。保守や技術的負債の整理に向け、最初の健全性測定をもとに分析、リファクタリング、再確認の順序を示します。

主な機能

  1. 01コードベースの健全性を測定
  2. 02重複コードとデッドコードを調査
  3. 03複雑度に基づいてファイルを順位付け
  4. 04優先順位に沿ったリファクタリング手順
  5. 05変更後の指標を再確認

活用シーン

  1. 01コードベース保守の優先順位付け
  2. 02重複実装の発見と統合
  3. 03未使用ファイル・エクスポート・インポートの確認
  4. 04複雑なファイルを簡素化して結果を検証

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/kucherenko/jscpd --skill codebase-refactoring

インストール後、Claude Code で/codebase-refactoringを入力して読み込まれたか確認します。

詳細

codebase-refactoring

jscpd を使って、コードベースの保守コストのうち特に大きい 3 つ、つまり重複コード、デッドコード、複雑さを調査し、それぞれを見つけて修正する方法を案内します。特定のバグを 1 つ修正するのではなく、コードベースの「クリーンアップ」「改善」「リファクタリング」や「技術的負債の解消」を依頼されたときに、このスキルを使用してください。

まずはここから:測定してから優先順位を付ける

npx jscpd --health --reporters ai <path>
health 74 B (duplication 75, dead-code 72, complexity 76; 93 code lines)

ヘルススコアは、コード行数に占める割合に基づく 3 つのサブスコアを加重して算出されます。スコアは高いほど良く、100 は問題がない状態です。3 つのうち最も低いスコアが、コードベースで最も問題となっている箇所を示します。以下の順序と異なる場合は、そちらの項目を先に対応してください。ある項目が n/a(例:dead code n/a)の場合、jscpd では測定できなかったことを意味します。デッドコード検出をコード全体に占める割合として算出するには、JavaScript、TypeScript、または Python が必要です。その項目は問題がないと見なすのではなく、スキップしてください。

スコアの詳細(重複が最も多い形式、複雑さが最も高いファイル、デッドコードの検出数が最も多いファイルを 1 画面で確認できます)を見るには、代わりに npx jscpd --dashboard を実行してください。ファイルごとの詳細を出力するのは、console 出力(デフォルト)のレポーターだけです。--dashboard で --reporters ai を指定すると、上記と同じ 1 行の要約が表示され、内訳は表示されません。スコア以上の情報を期待して使用しないでください。詳細を解析可能な形式で取得する必要がある場合は、--dashboard で --reporters json を指定してください。

以下の 3 つの手順は、それぞれ独立しており、どの順番でも安全に実行できます。デフォルトでは 重複 → デッドコード → 複雑さ の順に進めます。最初に重複を修正しておけば、後の関数抽出で移動する呼び出し元を追跡する無駄を、ステップ 2 で省けます。また、ステップ 3 の前にデッドコードを削除すれば、簡素化の対象として順位付けされるのは、削除される予定のファイルではなく、実際に簡素化する価値のあるファイルになります。

ステップ 1 — 重複コード

npx jscpd --reporters ai --summary <path>

クローンを 1 つずつ見つけて読み、本当に統合する価値のあるコピーかどうかを判断し、該当するリファクタリング戦略(関数の抽出、パラメーター化、共通モジュールや定数の抽出、または構造上の重複に対する基底クラス/テンプレート)を適用します。クローンの種類ごとの詳しいガイド付きワークフロー、名前を変えたクローンや類似クローンのトリアージルール、実例については、次を参照してください。

→ dry-refactoring — まずこれを実行し、その後ここに戻ってステップ 2 と 3 に進んでください。このスキル独自の --summary によるホットスポットの順位は、ヘルススコアの重複項目が参照するものと同じです。そのため、重複のホットスポットとして示されるファイルは、スコアを下げたファイルと同じです。

ステップ 2 — デッドコード

npx jscpd --dead-code --reporters ai <path>
basta dead code report — 18 findings across 30 files (22.1% of 272 lines)
Confidence is 0-100; anything below 90 has a listed reason it may be wrong. Verify a finding before deleting the code.
unused-file typescript/src/legacy-export.ts:1:1 confidence=95 typescript/src/legacy-export.ts is never imported and is not an entry point
unused-export typescript/src/invoice.ts:21:17 confidence=85 exported function `renderReceipt` is never imported
unused-symbol typescript/src/invoice.ts:29:10 confidence=90 function `describeTotal` is never used in typescript/src/invoice.ts
unused-import typescript/src/invoice.ts:2:10 confidence=100 `roundToCents` is imported but never used

これは参照数の集計ではなく、プロジェクトのエントリーポイント(package.json の main/bin/exports/scripts、pyproject.toml の scripts、フレームワークの規約、または --entry <glob>)からのグラフ探索です。唯一の呼び出し元がデッドコードであるヘルパーも報告されるため、ある検出箇所を削除すると、まだ報告されていなかった別の箇所が新たに該当する場合があります。対応言語は JavaScript、TypeScript、JSX、TSX、Vue、Svelte、Astro、Python です。

4 つのカテゴリと、それぞれの対処方法
カテゴリ意味一般的な修正方法
unused-fileどこからもインポートされておらず、エントリーポイントでもないファイルを削除する
unused-exportエクスポートされているが、他のファイルからインポートされていない削除するか、同じファイル内で引き続き使用されている場合は export キーワードを削除する
unused-symbolモジュール内に限定された宣言で、同じファイル内から参照されていない削除する
unused-importインポートされているが、ファイル内で参照されていないインポート行を削除する
ワークフロー
  1. --reporters ai を指定して実行します(特定のカテゴリに絞るには --dead-code-categories を追加します。テスト内でのみ使われるコードを「使用済み」として扱わない場合は --include-tests を、エントリーファイル自体の未使用エクスポートも検出するには --include-entry-exports を追加します。通常、エントリーファイル全体がパブリック API であるため、後者は対象外です)
  2. 信頼度の高い順に並べ替えます。値はすべて 0〜100 です。90 未満の検出結果には、誤検出の可能性がある理由が記載されます。たとえば、eval/getattr 呼び出し、アナライザーが認識しないデコレーター、ワイルドカード再エクスポート、文字列リテラル内にしか現れない名前、または解析に失敗した別のファイルなどです(JSON レポートの statistics.unparsedFiles を参照)。削除する前に理由を確認してください。--min-confidence(デフォルトは 60)は報告対象の下限を設定するだけで、信頼度の低い検出結果が安全であることを意味しません
  3. 納得できるしきい値を超える検出結果は、ひとつずつ手作業で確認します。リポジトリ全体からシンボル名を grep します(動的アクセス、文字列ベースのルーター、jscpd が解析しないテンプレートファイルなどにより、実際の使用が隠れていることがあります)。その後、上の表にある修正を適用します
  4. 削除をまとめて行うたびに、jscpd の再実行だけでなく、プロジェクト独自のテストスイートとビルドも実行します。デッドコード分析でわかるのは、エントリーポイントからコードに到達できないことだけであり、そのコードを削除してビルド手順が壊れないことまでは証明できません
  5. 削除をまとめて行った後は --dead-code を再実行します。インポートをひとつだけ持つファイルを削除すると、そのインポート元のファイル自体もデッドになることがあります。この連鎖は想定内です。一度だけで済ませず、結果がクリーンになるまで続けてください
  6. 実際に削除したものとは分けて、スキップした項目とその理由(信頼度の低さ、否定できなかった理由、パブリックライブラリエクスポートなど意図的に残したデッドコード)を報告します

ステップ 3 — 大きく複雑なファイル

npx jscpd --complexity --reporters ai --summary-top 10 <path>
# or, ranked alongside duplication and size:
npx jscpd --reporters ai --summary --summary-by complexity <path>
Complexity by complexity (6 files, 6 folders):
files (tokens/lines/size/cx):
c/checkout.c 176/32/710/13
rust/status.rs 112/24/481/9
swift/Profile.swift 88/21/446/8

cx は、循環的複雑度を言語を考慮して推定した値です。おおむね、関数ごとに 1 経路、分岐ごとに 1 経路(if、ループ、&&/||、match/switch の各アーム、三項演算子、Elvis 演算子を、言語での実際の記述方法に沿ってカウント)として数えます。正確な指標ではなく、順位付けの目安として見てください。文章やデータのファイル(Markdown、JSON、YAML、ロックファイルなど)のスコアは常に 0 です。大きな README はリファクタリングの対象ではありません。jscpd 独自のヘルススコアでは、複雑度が50 以上のファイルを「複雑」とみなします(「デッドコード」形式の半減曲線が基準にしているしきい値です)。サマリーから明らかな候補がわからない場合は、「確認する価値がある」ファイルを選ぶ妥当なデフォルトのカットオフです。

ワークフロー
  1. 複雑度が高い順に上位 N 件のファイルを確認します(--summary 形式ではサイズ順も確認します。たとえば、大きなデータテーブルのような複雑度の低い巨大ファイルは、複雑度の高い小さなファイルとは別の問題です)
  2. 各ファイルを読み、実際の要因を特定します。深いネスト、複数の無関係な処理を行う長い関数、型や状態に対する大きな switch/if 連鎖、または複数のモジュールを無理にひとつにまとめたようなファイルなどです
  3. 要因に合った方針を選びます。
    • 深いネスト → ガード節/早期リターンを使い、通常の処理経路を平坦化します
    • 複数の責務を持つ長い関数 → 責務ごとに関数を抽出し、処理内容を表す名前を付けます
    • 固定されたケースの集合(型、列挙型、ステータス)に対する分岐 → ルックアップテーブル/マップに置き換えるか、各ケースにすでに専用の型がある場合はポリモーフィズムを使います
    • 処理を詰め込みすぎたファイル → 任意の行数で区切るのではなく、実際の境界に沿って分割します(ファイルごとにエクスポートのグループをひとつにします)
  4. 一度に 1 ファイルずつリファクタリングし、動作を同一に保ちます。これは複雑度を改善する作業であり、書き換えではありません。読み進める中で重複コードのクローン(ステップ 1)やデッドな分岐(ステップ 2)が見つかった場合も、それぞれの変更理由を追跡できるよう、該当するステップで個別に対処します
  5. 変更したファイルに対して --complexity を再実行し、cx が実際に低下したことを確認します。関数ごとの分岐を減らさずにコードを移動しただけの分割では、何も解決しておらず、問題の名前を変えただけです

ステップ 4 — 改善を確認する

npx jscpd --health --reporters ai <path>

スコアと評価をステップ 0 の測定結果と比較します。ある指標が悪化している場合(たとえば、複雑さを解消する修正を共通化する過程で重複が再発した場合)は、そのステップを見直すべきという合図です。単に記録するだけではなく、該当するパス(--summary、--dead-code、--complexity)を再実行してください。集計値だけを頼りにしないでください。

ヒント

  • 初めて見るコードベースで --dashboard を先に確認せずに 3 つのパスすべてを実行しないでください。実際に問題があるのが 1 つの指標だけのプロジェクトで、3 つすべてに同じだけ労力をかけると、すでに問題のない 2 つに時間を浪費します
  • プロジェクトですでに追跡している場合は、カバレッジやセキュリティスキャン結果を含む --health-input ファイルを同じスコアに追加できます。これはこのワークフロー自体には影響せず、ステップ 0 に指標を追加するだけです
  • 2 回の実行で得られたヘルススコアを比較できるのは、同じ指標を使って算出した場合に限ります。ファイル構成の変更によって、ある指標が n/a から測定対象になった(またはその逆になった)場合は、そのことを明記し、スコアの生の差分を改善や悪化と解釈しないでください
  • 各ステップ(重複の修正、デッドコードの削除、複雑さの簡素化)は個別にコミットしてください。「これによって X が実際に減ったか」を確認するレビュー担当者は、X に絞った差分を必要とします

コメント