code-refiner について
code-refinerは、観察可能な動作を保ちながらコードを整える開発者向けの多段階スキルです。対象範囲の分析、構造の改善、言語別の指針、検証を組み合わせます。
主な機能
- 015段階のリファイン手順
- 02複雑さと構造の分析
- 03言語別のイディオム指針
- 04動作を保つための制約
- 05テストとリンターによる検証
活用シーン
- 01動作を変えずに複雑な関数を整理
- 02最近のGit変更を整理
- 03モジュール全体を詳しくリファイン
- 04リファクタリング後の動作とテストを確認
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ mathews-tom/ armory --skill code-refinerインストール後、Claude Code で/code-refinerを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
CHANGELOG.mdevals/cases.yamlreferences/go.mdpython.mdrust.mdtypescript.mdscripts/complexity_report.py詳細
コードリファイナー
複雑で冗長、または入り組んだコードを、コードの動作を変えずに、すっきりとした慣用的で保守しやすい実装へと変換する、構造化された複数回のコード改善スキルです。
基本理念
目標は、行数を減らすことではありません。疲れたエンジニアが午前2時に読んでも、理解して安全に変更できるコードを目指します。すべての変更は、次の3つの基準を満たす必要があります。
- 動作の同等性 — 同じ入力に対して、同じ出力、副作用、エラーが発生する
- 認知負荷の軽減 — コードに詳しくない読者でも、変更後のほうがより速く理解できる
- 保守性の向上 — 今後の変更がより容易になり、難しくならない
明瞭さと簡潔さが相反する場合は、明瞭さを優先します。慣用的な書き方と明示性が相反する場合は、チームの経験レベルを考慮します。DRY と局所性が相反する場合は、変更するより読むことの多いコードでは局所性を優先します。
前提条件
- git — ユーザーが対象ファイルを指定していない場合、フェーズ1でスコープ検出(
git diff)に使用します - Python 3.10+ — 定量的な複雑度指標を得るために、
scripts/complexity_report.pyの実行に必要です
ワークフロー
次の順序に従ってください。各フェーズは前のフェーズを踏まえて進めます。フェーズを省略せず、依頼の範囲に応じて作業の深さを調整してください(単一の関数には、モジュール全体よりも軽めの確認を行います)。
フェーズ1:事前調査
変更に着手する前に、対象の全体像を把握します。
- 対象範囲を特定する — 対象となるファイルや関数は何か。ユーザーが指定していない場合は、最近の git の変更を確認します。
git diff --name-only HEAD~5またはgit diff --staged --name-only - 言語とエコシステムを検出する — ファイル拡張子、インポート、設定ファイル(package.json、pyproject.toml、go.mod、Cargo.toml)を確認します。必要に応じて
references/から適切な言語リファレンスを読み、慣用的な書き方に関する指針を確認します - プロジェクトの規約を把握する — CLAUDE.md、.editorconfig、リンターの設定(eslint、ruff、golangci-lint、clippy)を確認します。これらは一般的な慣用表現の優先度に優先します
- テストカバレッジを把握する — テストファイルを探します。テストがある場合は、変更後に動作の同等性を検証できるよう、テストランナーを確認します
- 複雑度のベースラインを記録する — 対象となる各関数やメソッドについて、次の点を頭の中で把握します。
- ネストの深さ(インデントの最大レベル)
- 分岐の数(if/else/match/switch の分岐)
- 早期リターンの数と単一出口の数
- パラメーターの数
- コード行数
- 担当する役割の数(複数の処理を行っていないか)
フェーズ2:構造分析
解決策を急いで適用する前に、実際の問題を特定します。問題を重大度別に分類します。
重大(必ず修正する):
- デッドコード(到達不能な分岐、未使用の変数やインポート)
- 冗長な処理(同じ条件の二重チェック、キャッシュ済みの値の再計算)
- 標準ライブラリや言語の組み込み機能で置き換えられるロジック
- 回避可能な共有状態の変更
高(明確な理由がない限り修正する):
- ネストが3階層を超える関数
- パラメーターが5個を超える関数
- 巨大な関数(40行超、または担当する役割が3つ超)
- 繰り返されるコードブロック(類似ロジックが3回以上出現)
- 反転している、または分かりにくいブール値のロジック
- 文字列で表現された列挙型
中(リスクを増やさず明瞭さが向上する場合に修正する):
- 分かりにくい変数名や関数名
- 型注釈の不足や誤解を招く型注釈
- 不要な中間変数
- 過剰な抽象化(価値を加えないラッパー)
- コードの内容を言い換えるだけで、理由を説明していないコメント
低(専用のクリーンアップ作業でのみ修正する):
- 一貫性のないフォーマット(リンターに任せる)
- インポートの順序
- 行末の空白、行の長さ
フェーズ3:リファクタリングの実行
効果とリスクの比が高い順に、次の手法を使って変更を適用します。
3a. 不要なコードを取り除く
構成を見直す前に削除します。コードが少ないほど、考えることも少なくなります。
- 使用されていないインポート、変数、関数を削除する
- 到達不能な分岐を削除する(本当に到達不能かどうかを確認する)
- 明らかな内容を言い換えているだけのコメントを削除する(_理由_を説明するコメントは残す)
- 呼び出しを転送するだけの何もしないラッパー関数を削除する
3b. 構造をフラット化する
ネストと認知負荷を減らします。
- ガード節:深い
ifのネストを早期リターンに置き換える - 条件を抽出する:複雑なブール式に名前を付ける(
is_valid_order = ...) - ループを分解する:フィルタリング、変換、累積を行うループは、処理を分ける (または、リスト内包表記、イテレーター、ストリームなど、言語に適した構文を使う)
- 条件分岐を反転する:
else側が「正常系」の場合は、条件を反転する
3c. 統合して名前を付ける
コードの意図が見えるようにします。
- 繰り返されるロジックや個別の責務を関数として抽出する
- 関数名には、処理の_方法_ではなく、達成する_内容_を付ける
- 関数は、同じ抽象度の範囲で一つのことだけを行う
- マジック値を名前付き定数に置き換える
- 意図が伝わる名前に変更する:
data→user_records、process→validate_and_enqueue - パラメーターが3つを超える場合、関連するパラメーターを config/options 構造体にまとめる
3d. 言語固有の慣用表現を活用する
言語固有のパターンを適用します(詳細は references/<language>.md を参照してください)。
- Python:内包表記、コンテキストマネージャー、データクラス、構造的パターンマッチング
- Go:テーブル駆動テスト、エラーのラップ、関数型オプション、インターフェースの充足
- TypeScript:判別可能なユニオン、ブランド型、const アサーション、satisfies
- Rust:イテレーターチェーン、
?演算子、From/Into、newtype パターン
3e. 型を絞り込む
型は、コンパイラーによって検証されるドキュメントです。
- 公開関数に戻り値の型注釈を追加する
- 文字列で型を表現したパラメーターを、列挙型やユニオン型に置き換える
- 可能な箇所では
any/interface{}を具体的な型に絞り込む - 混同すべきでない識別子には、ブランド型/newtype パターンを使う
フェーズ 4:検証
**このフェーズを決して省略しないでください。**動作を壊す単純化は、単純化ではありません。
- 既存のテストを実行する — テストスイートがある場合は実行し、成功/失敗を報告します。
- リンター/型チェッカーを実行する — 設定されている場合は実行し、変更によって新たに生じた違反を修正します。
- 手動で処理を追跡する — リファクタリングした各関数について、正常系とエラー系の入力をそれぞれ1つ選び、変更前と変更後のコードで処理を頭の中で追跡します。動作が同一であることを確認します。
- 副作用を監査する — 元のコードに副作用(I/O、変更、ログ出力)があった場合、新しいコードでも同じ順序と条件で維持されていることを確認します。
テストが失敗する場合、または動作が異なる場合は、テストを修正しようとせず、該当する変更を元に戻してください。
フェーズ 5:報告
変更内容を構造化して要約します。これは重要です。コミットする前に、開発者が何を変更したのか理解し、信頼できるようにする必要があります。
変更したファイルごとに、次の内容を提示します。
## <filename>
### Changes
- [Critical] Removed unreachable error branch in `parse_config` (dead code after L42 guard)
- [High] Extracted `validate_credentials()` from 60-line `handle_login()` (was 3 responsibilities)
- [Medium] Renamed `d` → `document`, `proc` → `process_batch`
### Complexity Delta
- `handle_login`: 4 levels nesting → 2, 8 branches → 5
- `parse_config`: removed 12 lines of dead code
### Risk Assessment
- Low risk: all changes are structural, no logic modifications
- Tests: 47/47 passing
変更の範囲に応じて、詳しさを調整します。単一関数の整理なら一文で、複数ファイルにわたるリファクタリングなら完全なレポートを作成します。
動作上の制約
これらは厳守すべきルールです。コードがどれほどすっきりするように見えても、違反してはいけません。
- 観測可能な動作を決して変更しないでください — エラーメッセージ、ログ出力、戻り値、副作用の順序、例外の型が含まれます
- エラー処理を決して削除しないでください — 冗長に見える場合も同様です。防御的なコードには、コードだけからは分からない理由があることがよくあります
- 新しい依存関係を決して追加しないでください — 簡素化によって依存関係ツリーに何かが加わることはありません
- 指定された範囲外のコードを決してリファクタリングしないでください — ユーザーが明示的により広い範囲の作業を求めた場合を除きます。「もうひとつ修正しよう」という衝動を抑えてください
- パブリック API の表面を維持してください — 利用者から見える関数シグネチャ、エクスポート名、型定義は、ユーザーの明示的な承認なしに変更してはいけません
- 既存のテストを尊重してください — テストが特定の動作を検証している場合、その動作は要件です。誤っているように見えても、変更せずに報告書で指摘してください
範囲と積極性の設定
ユーザーは異なるモードを指定できます。指定がない場合は、standard がデフォルトです。
| モード | 範囲 | 重大度のしきい値 | テスト要件 |
|---|---|---|---|
quick | 単一ファイルまたは関数 | Critical + High のみ | テストを推奨 |
standard | 最近の Git の変更 | Critical + High + Medium | テストがある場合は実行必須 |
deep | モジュール/パッケージ全体 | すべての重大度 | テスト必須 |
surgical | ユーザー指定の行/関数 | すべての重大度 | 手動での追跡で十分 |
「ざっと確認して」や「このモジュールを徹底的に整理して」のように指定して、モードを選ぶことができます。
整理を行わない場合
次の場合は、丁寧に申し出て、別の対応を提案してください。
- テストがないのに、ユーザーが大規模なリファクタリングを希望している場合 → まずテストを書くことを提案します
- コードが自動生成されたもの(protobuf、OpenAPI、ORM モデル)の場合 → ジェネレーターを変更することを提案します
- 実際には機能変更の依頼を「クリーンアップ」と称している場合 → 意図を確認します
- ホットパスにあり、「簡素化」によって割り当てやコピーが発生する場合 → トレードオフを指摘します
言語別リファレンス
言語固有のイディオムに関するガイダンスについては、該当するリファレンスファイルを読んでください。
references/python.md— Python 固有のパターン、アンチパターン、標準ライブラリの代替手段references/go.md— Go のイディオム、エラー処理パターン、インターフェース設計references/typescript.md— TypeScript/JavaScript のパターン、型の絞り込み、モジュール設計references/rust.md— Rust のイディオム、所有権パターン、イテレーターの使い方
現在の対象範囲に含まれる言語のリファレンスファイルのみを読み込んでください。これらは、上記の一般的な方法論を補足する詳細なパターン集です。
正当化の言い分
| 正当化の言い分 | 実態 |
|---|---|
| 「十分読みやすい」 | 「十分」は基準ではありません。次の開発者が関数を3回読み直す必要があるなら、読みやすいとは言えません |
| 「リファクタリングはリグレッションのリスクがある」 | リファクタリングしないことは技術的負債の蓄積につながります。前後にテストスイートを実行してください。そのためにテストがあります |
| 「このコードベースでは昔からこうしている」 | 悪いパターンに一貫性があっても、それは依然として悪いパターンです。アンチパターンを維持せず、段階的に改善してください |
| 「パフォーマンスが悪化するかもしれない」 | 前後のベンチマークを行ってください。読みやすさを改善するリファクタリングのほとんどはパフォーマンスに影響しません。過度な最適化は諸悪の根源です |
| 「壊れていないなら直すな」 | 整理は修正とは異なります。動作しているコードを、次の人が保守、テスト、理解しやすいものにすることです |
| 「モジュール全体は後でリファクタリングする」 | 段階的な整理は効果的ですが、一度にすべてを書き換える方法は失敗します。今手を加える箇所を改善してください |
注意すべき兆候
- 「単なるリファクタリング」と主張しながら動作を変更すること — 改善では既存の動作をすべて維持する必要があります
- 正当な理由なく、宣言されたスコープ外のコードに手を加えること
- 簡素化の際にエラー処理や検証を削除すること
- 一度しか使わない処理に新たな抽象化を導入すること
- リファクタリングの前後にテストスイートを実行しないこと
- 元のタスクの対象ではなかったコードにスタイル変更を加えること
検証
- 改善の前後で既存のテストがすべて成功する
- 動作に変更がない — すべての入力に対して出力と副作用が同一である
- 変更が宣言されたスコープ内に収まっている — 無関係なコードに場当たり的な編集を加えていない
- 循環的複雑度が低下しているか、変わっていない — 決して増加していない
- 単一用途のケースに新たな抽象化を導入していない
- リンターと型チェッカーが成功する:
ruff check+mypy --strictまたはtsc --noEmit+eslint