antfu-simplify について
現在の PR または作業ツリーの差分を、動作を変えずに最小限の正しい変更へ整理するコードレビュー用スキルです。削除を小分けに検証し、残した箇所と除いた箇所、差分量、チェック結果を報告します。
主な機能
- 01現在の変更差分をレビュー
- 02冗長または推測的な要素を削除
- 03動作と対象範囲を維持
- 04各バッチ後にチェックを実行
- 05判断内容と差分量を報告
活用シーン
- 01PR の抽象化を減らす
- 02追加した分岐やヘルパーの必要性を確認
- 03レビュー前に作業ツリーの変更を縮小
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ antfu/ skills --skill antfu-simplifyインストール後、Claude Code で/antfu-simplifyを入力して読み込まれたか確認します。
詳細
変更を簡素化する
現在の変更(PR ブランチまたは作業ツリー)を確認し、熟練した開発者のように、正しさを保ちながら差分を最小限に絞り込みます。手法はアブレーションスタディです。各要素を取り除き、重要なものが壊れないかを確かめ、残す価値のあるものだけを残します。
目標は、ちょうどよい抽象化を備え、堅牢(実際に起こり得るエッジケースに対応)で、汎用的(変更のきっかけとなったケースだけでなく、一般的なケースを解決)な、クリーンで最小限のコードです。
厳守事項
- 動作は変えません。 簡素化のみを行います。機能の追加、公開 API の変更、無関係な問題の修正はしないでください。無関係な指摘事項は別途報告してください。
- 対象は差分です。 変更で追加または修正されたコードと、それを削除するために変更が必要なコードのみを編集してください。周辺のコードベースをリファクタリングしないでください。
- 削除はすべて検証します。 各まとまりの変更後に、リポジトリのテスト、型チェック、リンターを実行してください。削除した部分がチェックの対象になっていない場合は、明示的に検討するか、その部分を残してください。
- 周囲のコードのスタイル、命名、コメントの密度に合わせてください。
ワークフロー
- 差分を取得します。 基点を選びます。PR の場合は対象ブランチとのマージベース(
git merge-base HEAD origin/<default>)、未コミットの作業の場合はgit diff HEADを使います。差分全体と、その周辺のファイルを読みます。変更の目的を一文で記します。以降のすべての判断基準にします。 - 要素を洗い出します。 差分で追加された各要素を列挙します。関数、パラメーター、オプション、分岐、型、ファイル、依存関係、抽象化レイヤー、コメント、テストを確認します。アブレーションスタディを参照してください。
- アブレーションします。 各要素について、削除、インライン化、統合を試します。残すか削るかに基づいて判断します。
- 変更を適用します。 小さなまとまりごとに削除し、そのつど対象を絞ったチェック(テスト、型チェック、リンター)を実行します。動作に問題が生じたら削除を元に戻します。その要素には必要性があると確認できたことになります。
- 結果を確認します。 レビュアーの視点で最終差分を読み直します。残した各行は、一文で示した目的によって説明できますか? 堅牢性と汎用性は保たれていますか?
- 報告します。 削除または維持した内容とその理由を短い表にまとめ、変更前と変更後の差分サイズ(
git diff --stat)も示します。依頼がない限り、コミットはしないでください。
アブレーションスタディ
差分に含まれる各要素について、次のように問いかけます。これを削除すると、具体的に何が壊れますか?
| 要素 | アブレーション | 維持する条件 |
|---|---|---|
| 新しい関数/ヘルパー | 呼び出し元にインライン化する | 2 か所以上から呼び出されている、または名前が自明でない処理を説明している |
| ラッパー/抽象化レイヤー | 内部の処理を直接呼び出す | 実際の複雑さを隠している、または変更される可能性の高い境界を分離している |
| パラメーター/オプション/設定 | 唯一使用されている値をハードコードする | 現在、異なる値を必要とする実際の呼び出し元がある |
| 型/インターフェース/ジェネリック | 推論された型または既存の型を使う | エクスポートされている、または型推論では型が悪化するか誤った型になる |
| 分岐/ガード/try-catch | 削除してテストを実行する | 到達可能なケース(実際の入力、実際の失敗)を防いでいる。起こり得ないケースではない |
| 新しいファイル/モジュール | 唯一の利用元に統合する | 利用元が複数ある、または独立した責務がある |
| 依存関係 | 数行のコードまたは既存の依存関係で置き換える | ほかの方法では誤りやすい難しいエッジケースに対応している |
| 重複したロジック | リポジトリ内の既存ユーティリティを再利用する | 同等のものがない(先に検索する) |
| コメント | 削除する | 「何を」ではなく「なぜ」を説明している(制約、回避策、意外な選択など) |
| テスト | 削除して、何が保護されなくなるかを確認する | ほかのテストではカバーされない動作またはリグレッションを検証している |
| 目的に無関係な変更行 | 元に戻す | ついでに行った変更は残さない |
残すものと削るもの
次のような要素は削除します。
- 推測に基づくもの:誰も必要としていない将来のニーズに備えて作られたもの(余分なオプション、フック、プラグイン用の拡張ポイント、「念のため」のジェネリクスなど)。
- 重複するもの:言語、フレームワーク、型、既存のユーティリティがすでに提供している機能を繰り返すもの。
- 起こり得ない事態への防御:型や呼び出し元によって保証されている値への null チェック、実行されないフォールバック、エラーを握りつぶす catch ブロック。
- 効果のない間接化:一度しか使わないヘルパー、単に処理を受け渡すだけのラッパー、関数で済むのにクラスを使うこと、一つのものだけを構築するファクトリー。
- ノイズ:コメントアウトされたコード、内容を説明するだけのコメント、未使用のインポートやエクスポート、書式だけを変更する差分。
次のような要素は残します(必要であれば追加します)。
- 堅牢性: 現実に起こり得るエッジケースに対応するもの(空の入力、並行処理、クリーンアップ、クロスプラットフォームのパス、コンテキストを伴うエラーの伝播)。
- 汎用性: 報告された問題だけに特化せず、一般的な問題を解決するもの。修正でバグ報告にある名前、パス、値をハードコードしている場合は、汎用化します。
- 適切な規模の抽象化: 同じ処理が3回目に現れたら抽出します。通常、1回目と2回目では抽出しません。良い抽象化は、追加するコードより多くのコードを削減します。
抽象化が小さすぎる場合は統合し、一つの関数が無関係な処理を複数行う場合は分割します。目指すのは、行数を最小にすることでも、レイヤーを最大にすることでもなく、読者が把握しなければならない概念を最小限にすることです。
注意すべきコードの兆候
- 原因ではなく、呼び出し箇所で症状を修正するパッチ。
- 一般的なルールで対応できる特殊ケース(
if (name === 'foo'))。 - わずかな違いで同じ処理を行う2つのコードパス。統合します。
- 既存のデータから導出できる状態、フラグ、キャッシュ。
- 長いパラメーターリストやオプションの詰め合わせ。ほとんどの値が変更されないもの。
typeof、ReturnType、Parameters、ユーティリティ型で導出できるのに、手作業で重複して定義された型。- リポジトリ、ランタイム、既存の依存関係がすでに提供しているのに、独自に実装したユーティリティ。
- 実装の詳細を検証するテストや、コードを一行ずつそのままなぞるテスト。
レポート形式
| # | Piece | Action | Why |
|---|-------|--------|-----|
| 1 | `parseOptions()` in src/cli.ts | inlined | one caller, 3 lines |
| 2 | `retry` option | removed | no caller passes it; default is enough |
| 3 | `try/catch` in fetchData | kept | network errors reach users; test covers it |
Diff: +142 -8 -> +61 -8. Tests, typecheck, lint pass.
範囲外の気づいた点(無関係なバグ、より広範なリファクタリングなど)は分けて記載し、手を加えないでください。
コメント
Markdown 対応