Unity Refactor について
Unity の C# コードベースを分析し、コードスメルをリスク順に整理して一件ずつリファクタリングするスキルです。変更ごとに参照とコンパイルを確認し、既存の動作を保つことを目指します。
主な機能
- 01Unity のコードスメルを検出
- 02リスク順にリファクタリングを整理
- 03変更前に計画を提示
- 04一度に一件ずつ変更
- 05参照とコンパイルを確認
活用シーン
- 01Unity スクリプトの技術的負債を確認
- 02長いメソッドや管理クラスを分割
- 03マジック文字列を定数に置き換え
- 04システム間の直接依存を削減
MCP 対応
Unity MCP サーバーには依存せず、Read、Write、Edit、Grep、Glob、Bash ツールを使用します。
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ juliankerignard/ unity-skills --skill unity-refactorインストール後、Claude Code で/unity-refactorを入力して読み込まれたか確認します。
同梱ファイルreferences/refactor-recipes.md
詳細
Unity リファクタリング
このスキルでできること
このスキルは Unity の C# コードベースを分析してコードスメルを検出し、リスクレベル順に優先順位を付けたリファクタリング計画を提案した後、変更ごとに検証しながら一つずつ実行します。目的は、既存の動作を決して変更することなく、コードの品質を向上させることです。
前提条件
Assets/Scripts/に既存の C# コードがある Unity プロジェクト- Unity MCP への依存なし:Read、Write、Edit、Grep、Glob、Bash のみを使用
判断フロー
Quel type de dette technique ?
|
+-- Code trop long / illisible ?
| +-- Fichier > 500 lignes --> God class split (risque eleve)
| +-- Methode > 50 lignes --> Extraction de methodes (risque faible)
|
+-- Couplage fort entre classes ?
| +-- References directes cross-systeme --> Event Channel SO (risque moyen)
| +-- Singleton partout --> SO / Service Locator (risque eleve)
|
+-- API obsolete ?
| +-- Old Input --> New Input System (risque moyen, recette 6)
| +-- Coroutines --> async Awaitable (risque moyen, recette 4)
|
+-- Code smells generaux ?
+-- Magic strings --> Constantes / enum (risque faible)
+-- Champs publics --> [SerializeField] private (risque faible)
詳しい手順については、以下のリファクタリングカタログを参照してください。
クイックスタート
- コードベースをスキャンしてコードスメルを検出する
- リファクタリングをリスク別に分類し、優先順位を付ける
- 計画をユーザーに提示する
- 一度に 1 つのリファクタリングを実行する
- 変更ごとにコンパイルと参照を検証する
- 計画が完了するまで繰り返す
ステップバイステップガイド
ステップ 1:コードベースをスキャンしてコードスメルを検出する
Grep、Glob、Bash を使って、すべての検出を並行して実行します。
Glob : Assets/Scripts/**/*.cs # Tous les fichiers C#
Bash : find Assets/Scripts -name "*.cs" -exec wc -l {} + | sort -rn | head -20 # Fichiers volumineux
Grep : "static\s+\w+\s+Instance" dans Assets/Scripts/**/*.cs # Singletons
Grep : "void\s+Update\s*\(\)" dans Assets/Scripts/**/*.cs # Update polling
Grep : "Find\(\"" dans Assets/Scripts/**/*.cs # Magic strings (Find)
Grep : "CompareTag\(\"" dans Assets/Scripts/**/*.cs # Magic strings (Tags)
Grep : "StartCoroutine" dans Assets/Scripts/**/*.cs # Coroutine spaghetti
Grep : "public\s+(?!void|static|override|class)" dans *.cs # Champs publics exposes
Grep : "class\s+\w+\s*:\s*\w+" dans Assets/Scripts/**/*.cs # Heritage (tracer les chaines)
ステップ 2:分類して優先順位を付ける
以下のリファクタリングカタログを使って、検出された各スメルを分類します。
Unity リファクタリングカタログ
| スメル | 検出パターン(Grep) | リファクタリング | リスク |
|---|---|---|---|
| ゴッドマネージャー(500 行超) | "Manager" を含み、500 行を超える .cs ファイル | 責務に特化したサービスに分割 | 高 |
| Singleton MonoBehaviour | MonoBehaviour 内の static.*Instance.*get | SO + Service Locator に置き換え | 高 |
| 深い継承(3 階層超) | 3 階層を超える class X : Y の連鎖 | コンポジション + インターフェースでフラット化 | 高 |
| Update ポーリング | ブール値のチェックを行う Update() | イベント/コールバックに置き換え | 中 |
| ゴッド Update | 5 つを超える責務を持つ Update() | 別々のコンポーネントに分割 | 中 |
| Feature envy | 他のクラスのデータに頻繁にアクセスするメソッド | メソッドをデータの所有者に移動 | 中 |
| プリミティブ型への執着 | int/float/string の繰り返しグループ | 値型/struct に抽出 | 中 |
| マジック文字列 | Find/CompareTag/Animator 内の "string" | const/enum/SO に置き換え | 低 |
| Inspector の public フィールド | 多数の public フィールド | [SerializeField] private + SO 設定 | 低 |
| 巨大なメソッド(50 行超) | 長いメソッド | サブメソッドを抽出 | 低 |
検出のしきい値
| 指標 | しきい値 | 判定 |
|---|---|---|
| クラスあたりの行数 | > 500 | ゴッドクラス |
| メソッドあたりの行数 | > 50 | メソッドが長すぎる |
| クラスあたりのメソッド数 | > 15 | 責務が多すぎる |
| メソッドあたりのパラメーター数 | > 5 | パラメーターオブジェクトが必要 |
| 継承階層の深さ | > 3 | 階層をフラット化 |
優先順位:低(マジック文字列、public フィールド、長いメソッド)、次に 中(Update ポーリング、feature envy、ゴッド Update)、最後に 高(シングルトン、ゴッドクラス、継承)。
ステップ 3:計画をユーザーに提示する
変更を行う前に、次の表を提示します:# | ファイル | スメル | リファクタリング | リスク | 影響を受けるファイル。すべて / 選択 / キャンセル を提案し、開始前に承認を待ちます。
ステップ 4:一度に 1 つのリファクタリングを実行する
承認された計画の各リファクタリングについて、次を行います。
1. Read : Lire le fichier cible completement
2. Grep : Identifier TOUTES les references au code qui va changer
Grep : "NomClasse" dans Assets/Scripts/**/*.cs
Grep : "NomMethode" dans Assets/Scripts/**/*.cs
3. Edit : Effectuer le changement (une seule modification atomique)
4. Edit : Mettre a jour toutes les references trouvees
5. Grep : Verifier qu'aucune reference orpheline ne subsiste
6. Passer au refactoring suivant
ステップ 5:変更ごとに検証する
個々のリファクタリングを行うたびに、次を実行します。
1. Grep pour les anciens noms de classes/methodes : doit retourner 0 resultats
2. Grep pour les references cassees : "using.*OldNamespace" absent
3. Verifier coherence : les nouveaux fichiers sont dans le bon dossier
4. Verifier que les [SerializeField] et references Inspector ne sont pas casses
問題が検出された場合は変更を元に戻し、続行する前にユーザーに通知します。
ステップ 6:完了するまで繰り返す
優先順位(リスクの低いものを先に)に従って計画を進めます。リファクタリングが完了するたびに、進捗を報告します。
[2/8] Termine : EnemyController.cs - Extraction de methodes
Fichiers modifies : 1
References mises a jour : 0
Status : OK
リファクタリングのレシピ
references/refactor-recipes.md に、変更前/変更後のコードを含む6つの詳細なレシピがあります。
| レシピ | リスク | 説明 |
|---|---|---|
| シングルトンから SO サービスへ | 高 | MonoBehaviour のシングルトンを、注入される ScriptableObject に置き換えます |
| 巨大なマネージャーからサービスへ | 高 | モノリシックなマネージャーを、役割に特化したサービスに分割します |
| マジック文字列から定数へ | 低 | 文字列を定数として切り出し、Animator.StringToHash を使用します |
| コルーチンから async Awaitable へ | 中 | IEnumerator を async Awaitable に移行します(Unity 6+) |
| 直接参照から Event Channel へ | 中 | ScriptableObject イベントを使って、発行側と購読側を疎結合にします |
| 旧 Input から新 Input System へ | 中 | UnityEngine.Input から InputSystem に移行します |
厳守事項
- 絶対に同じファイルに対して2つのリファクタリングを同時に行わないでください
- 絶対に観察可能な動作を変更しないでください(リファクタリング ≠ 新機能)
- 絶対にInspector の参照が失われることを警告せずに、
[SerializeField]フィールドの名前を変更しないでください - 絶対にすべての参照を確認せずにコードを削除しないでください(プロジェクト全体を Grep で検索してください)
- 絶対にファイル全体を先に読まずにリファクタリングしないでください
- 必ず変更を1つ加えるごとにコンパイルを確認してください
- 必ず名前を変更した後、Grep で壊れた参照がないか確認してください
- 必ず最初の変更を加える前に、計画全体を提示してください
- 必ず低リスクのリファクタリングから始めてください
- 必ず可能な限り小さな変更を優先してください
- 必ず既存ファイルの変更には Edit を使用してください(Write は使用しないでください)
- 必ずUnity の属性(
[SerializeField]、[Header]、[Tooltip]など)を維持してください
関連スキル
- 新しいコードをきれいに生成しますか?
/unity-code-gen(Unity Code Gen)を使用してください - パフォーマンスを監査しますか(リファクタリングを伴わない検出)?
/perf-audit(Unity Perf Audit)を使用してください - リファクタリング後のコードをテストしますか?
/unity-test(Unity Test)を使用してください - リファクタリング中に見つかったバグを診断しますか?
/unity-debug(Unity Debug)を使用してください
トラブルシューティング
| 問題 | 解決策 |
|---|---|
| フィールド名の変更後にInspectorの参照が壊れた | [SerializeField] フィールドの名前が変更されています。[FormerlySerializedAs("oldName")] を使用して、シリアライズ済みデータを移行してください |
| クラス分割後にコンパイルエラーが発生した | 新しいファイルで using が不足していないか、アセンブリ定義の参照に問題がないか確認してください |
| リファクタリング後に動作が変わった | 変更を元に戻し(Edit で復元)、差分を分析して、より慎重な方法でやり直してください |
| Prefab のオーバーライドが失われた | フィールドの名前または型が変更されています。[FormerlySerializedAs] を追加し、該当する Prefab を再確認してください |
| 分割後に循環依存が発生した | 共有アセンブリにインターフェースを切り出すか、SO イベントチャネルで依存関係を逆転させてください |
| リファクタリング後にテストが失敗する | テストは動作ではなく実装(メソッド名)を検証していました。新しい名前を使うようテストを更新してください |
| AnimatorController の参照が壊れた | 文字列パラメーターがハッシュに置き換えられています。Animator.StringToHash に、コントローラーで使われているものと同じ文字列が渡されていることを確認してください |
| ScriptableObject の参照が null になる | SO アセットがプロジェクト内に作成されていません。Create メニューからアセットを作成し、Inspector で割り当ててください |