swift-refactor について
Swift/SwiftUIアプリを、Domain・Data・Feature・Appに分けたモジュール型MVVM-Cへリファクタリングするためのガイドです。iOS 26/Swift 6.2の設計契約に基づき、API、状態管理、ナビゲーション、パフォーマンスの改善を扱います。
主な機能
- 01モジュール型MVVM-Cの構成指針
- 02SwiftUI APIのモダナイズ規則
- 03Observable ViewModelと状態設計
- 04Coordinatorによるナビゲーション
- 05ビュー識別とリスト性能の規則
活用シーン
- 01旧式SwiftUIのナビゲーションと状態APIの移行
- 02アプリをDomain、Data、Feature、Appに分割
- 03差分計算を改善するビューとリストのリファクタリング
- 04手動のタスク管理をキャンセル可能な読み込みに置き換え
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ pproenca/ dot-skills --skill swift-refactorインストール後、Claude Code で/swift-refactorを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
metadata.jsonassets/templates/_template.mdreferences/_sections.mdapi-alert-confirmation-dialog.mdapi-environment-object-removal.mdapi-list-foreach-identifiable.mdapi-navigationstack-migration.mdapi-observable-macro.mdapi-onchange-signature.mdapi-toolbar-migration.mdarch-environment-key-injection.mdarch-feature-module-extraction.mdarch-model-view-separation.mdarch-protocol-dependencies.mdarch-viewmodel-elimination.mddata-cancellation.mddata-error-loadable.mddata-task-modifier.mddi-container-composition.mddi-mock-testing.mddiff-closure-skip.mddiff-equatable-views.mddiff-identity-stability.mddiff-printchanges-debug.mdlayer-dependency-rule.mdlayer-no-view-repository.mdlayer-repository-protocol.mdlayer-usecase-protocol.mdlayer-viewmodel-boundary.mdlist-constant-viewcount.md詳細
Swift/SwiftUI のリファクタリング(モジュール化された MVVM-C)
Swift/SwiftUI のコードを、ローカルの SPM パッケージ境界と App ターゲットのコンポジションルート配線を備えたモジュール化 MVVM-C に移行するための包括的なリファクタリングガイドです。
必須のアーキテクチャスタック
┌───────────────────────────────────────────────────────────────┐
│ App target: DependencyContainer, Coordinators, Route Shells │
├───────────────────────────────────────────────────────────────┤
│ Feature modules: View + ViewModel (Domain + DesignSystem deps)│
├───────────────────────────────────────────────────────────────┤
│ Data package: repositories, remote/local stores, sync, retry │
├───────────────────────────────────────────────────────────────┤
│ Domain package: models, repository/coordinator/error protocols │
└───────────────────────────────────────────────────────────────┘
依存関係のルール:Feature モジュールは Data をインポートせず、兄弟 Feature もインポートしません。
Clinic アーキテクチャ契約(iOS 26 / Swift 6.2)
このスキルのガイダンスはすべて、Clinic のモジュール化 MVVM-C アーキテクチャを前提としています。
- Feature モジュールがインポートするのは
DomainとDesignSystemのみです(Dataおよび兄弟 Feature はインポートしません)。 - App ターゲットが集約地点となり、
DependencyContainer、具象コーディネーター、Route Shell の配線を所有します。 Domainは純粋な Swift を保ち、モデルに加えて、リポジトリ、*Coordinating、ErrorRouting、AppErrorの各コントラクトを定義します。Dataは SwiftData/ネットワーク/同期/再試行/バックグラウンド I/O を所有し、Domain プロトコルを実装します。- 読み書きのフローでは、デフォルトで stale-while-revalidate による読み取りと、楽観的なキュー書き込みを使用します。
- ViewModel はリポジトリプロトコルを直接呼び出します(デフォルトのユースケース/インタラクターレイヤーはありません)。
適用する場面
次の場合に、これらのガイドラインを参照してください。
- 非推奨の SwiftUI API(ObservableObject、NavigationView、古い onChange)から移行する
- @Observable ViewModel を使用する状態管理に再構成する
- パフォーマンス向上のため、ビューに @Equatable による差分検出を追加する
- 大きなビューを、本文が最大 10 ノードになるように分割する
- ナビゲーションをコーディネーター + Route Shell パターンにリファクタリングする
- Domain/Data/Feature/App のパッケージ境界に沿ってリファクタリングする
DependencyContainerによる依存性注入を設定する- リスト/コレクションのスクロールパフォーマンスを改善する
- 手動の Task 管理を
.task(id:)とキャンセル可能な読み込みに置き換える
必ず守る制約(iOS 26 / Swift 6.2)
- ViewModel/コーディネーターには
@Observableを使用し、ObservableObject/@Publishedは使用しません。 NavigationStackは App ターゲットの Route Shell とコーディネーターが所有します。- すべてのビューに
@Equatableマクロを付け、AnyViewは使用しません。 - Domain がリポジトリ/コーディネーター/エラールーティングのプロトコルを定義し、フレームワークに依存する I/O は行いません。
- 専用のユースケース/インタラクターレイヤーは設けません。ViewModel がリポジトリプロトコルを直接呼び出します。
- ビューからリポジトリに直接アクセスしません。
優先度別ルールカテゴリ
| 優先度 | カテゴリ | 影響 | プレフィックス | ルール数 |
|---|---|---|---|---|
| 1 | ビューのアイデンティティと差分検出 | CRITICAL | diff- | 4 |
| 2 | API の最新化 | CRITICAL | api- | 7 |
| 3 | 状態アーキテクチャ | CRITICAL | state- | 6 |
| 4 | ビューの構成 | HIGH | view- | 7 |
| 5 | ナビゲーションと調整 | HIGH | nav- | 5 |
| 6 | レイヤーアーキテクチャ | HIGH | layer- | 5 |
| 7 | アーキテクチャパターン | HIGH | arch- | 5 |
| 8 | 依存性注入 | MEDIUM-HIGH | di- | 2 |
| 9 | 型安全性とプロトコル | MEDIUM-HIGH | type- | 4 |
| 10 | リストとコレクションのパフォーマンス | MEDIUM | list- | 4 |
| 11 | 非同期処理とデータフロー | MEDIUM | data- | 3 |
| 12 | Swift 言語の基礎 | MEDIUM | swift- | 8 |
クイックリファレンス
1. ビューのアイデンティティと差分検出(CRITICAL)
diff-equatable-views- すべての SwiftUI ビューに @Equatable マクロを追加しますdiff-closure-skip- クロージャープロパティには @EquatableIgnored を使用しますdiff-identity-stability- ForEach では安定した O(1) 識別子を使用しますdiff-printchanges-debug- 再レンダリングの原因を特定するには _printChanges() を使用します
2. API のモダナイズ(CRITICAL)
api-observable-macro- ObservableObject を @Observable マクロに移行するapi-navigationstack-migration- NavigationView を NavigationStack に置き換えるapi-onchange-signature- 新しい onChange シグネチャに移行するapi-environment-object-removal- @EnvironmentObject を @Environment に置き換えるapi-alert-confirmation-dialog- Alert を confirmationDialog API に移行するapi-list-foreach-identifiable- id: .self を Identifiable への準拠に置き換えるapi-toolbar-migration- navigationBarItems を toolbar モディファイアに置き換える
3. 状態アーキテクチャ(CRITICAL)
state-scope-minimization- 状態のスコープを最も近い利用箇所まで最小化するstate-derived-over-stored- 冗長な @State の代わりに計算プロパティを使用するstate-binding-extraction- @Binding を切り出して、子ビューの再描画を分離するstate-remove-observation- @ObservedObject を @Observable によるトラッキングに移行するstate-onappear-to-task- onAppear クロージャを .task モディファイアに置き換えるstate-stateobject-placement- @StateObject を @Observable を使用した @State に移行する
4. ビューの構成(HIGH)
view-extract-subviews- 差分確認のチェックポイントとしてサブビューを切り出すview-eliminate-anyview- AnyView を @ViewBuilder またはジェネリクスに置き換えるview-computed-to-struct- 計算ビューのプロパティを struct ビューに変換するview-modifier-extraction- 繰り返し使用するモディファイアをカスタム ViewModifiers に切り出すview-conditional-content- 条件付きビューの代わりに Group または条件付きモディファイアを使用するview-preference-keys- コールバッククロージャを PreferenceKey に置き換えるview-body-complexity- ビューの body を最大 10 ノードに抑える
5. ナビゲーションと調整(HIGH)
nav-centralize-destinations- ナビゲーションをコーディネーターパターンにリファクタリングするnav-value-based-links- NavigationLink をコーディネーターのルートに置き換えるnav-path-state-management- プログラムによるナビゲーションに NavigationPath を使用するnav-split-view-adoption- 複数列レイアウトに NavigationSplitView を使用するnav-sheet-item-pattern- シートのブール値トリガーをアイテムバインディングに置き換える
6. レイヤーアーキテクチャ(HIGH)
layer-dependency-rule- フレームワークのインポートがないドメインレイヤーを切り出すlayer-usecase-protocol- ユースケース/インタラクターレイヤーを削除し、ViewModel とリポジトリプロトコルでオーケストレーションを行うlayer-repository-protocol- リポジトリプロトコルは Domain に、実装は Data に配置するlayer-no-view-repository- ビューからのリポジトリへの直接アクセスを削除するlayer-viewmodel-boundary- ViewModel を、表示用に整えた状態のみを公開するようリファクタリングする
7. アーキテクチャパターン(高)
arch-viewmodel-elimination- インラインの状態を@Observable ViewModelに再構成しますarch-protocol-dependencies- ViewModelレイヤーを通じてプロトコル依存関係を抽出しますarch-environment-key-injection- サービスの注入にEnvironmentキーを使用しますarch-feature-module-extraction- 機能を独立したモジュールに抽出しますarch-model-view-separation- ビジネスロジックをDomainモデルとリポジトリに基づくViewModelに抽出します
8. 依存性注入(中〜高)
di-container-composition- アプリのルートで依存関係コンテナを構成しますdi-mock-testing- プロトコル依存関係ごとにモック実装を追加します
9. 型安全性とプロトコル(中〜高)
type-tagged-identifiers- String IDをタグ付き型に置き換えますtype-result-over-optionals- エラーフラグ付きのOptionalではなくResult型を使用しますtype-phantom-types- コンパイル時の状態マシンにファントム型を使用しますtype-force-unwrap-elimination- 安全な代替手段を使って強制アンラップを排除します
10. リストとコレクションのパフォーマンス(中)
list-constant-viewcount- ForEachが要素ごとに一定のビュー数を生成するようにしますlist-filter-in-model- フィルター/ソートのロジックをForEachからViewModelに移しますlist-lazy-stacks- 内容が無制限の場合はVStack/HStackをLazy版に置き換えますlist-id-keypath- 明示的なid keyPathを指定し、暗黙の識別性に依存しないようにします
11. 非同期処理とデータフロー(中)
data-task-modifier- onAppearでの非同期処理を.taskモディファイアに置き換えますdata-error-loadable- 読み込み状態をブール値フラグではなく列挙型で表しますdata-cancellation- .taskの自動キャンセルを使用し、Taskを手動で管理しないようにします
12. Swift言語の基礎(中)
swift-let-vs-var- 定数にはlet、変数にはvarを使用しますswift-structs-vs-classes- classよりstructを優先しますswift-camel-case-naming- camelCaseの命名規則を使用しますswift-string-interpolation- 動的テキストには文字列補間を使用しますswift-functions-clear-names- 関数とパラメーターに明確な名前を付けますswift-for-in-loops- コレクションにはfor-inループを使用しますswift-optionals- アンラップを使ってOptionalを安全に処理しますswift-closures- インライン関数にはクロージャを使用します
使用方法
詳しい説明とコード例については、個々のリファレンスファイルをお読みください。
リファレンスファイル
| ファイル | 説明 |
|---|---|
| references/_sections.md | カテゴリーの定義と順序 |
| assets/templates/_template.md | 新しいルール用のテンプレート |
コメント
Markdown 対応