swift-ui-architect について
swift-ui-architectは、iOS 26とSwift 6.2を使うクリニック向けSwiftUIアプリのモジュラーMVVM-C指針をまとめたスキルです。レイヤー、状態、ナビゲーション、依存性注入、データフローの規則を示し、機能の開発やレビューに役立ちます。
主な機能
- 01モジュラーMVVM-Cのレイヤー規則
- 02ビュー識別と状態の指針
- 03コーディネーターによるナビゲーション規則
- 04依存性注入のパターン
- 05非同期データフローの推奨事項
活用シーン
- 01ローカルSPM機能モジュールの設計
- 02コーディネーターとルートシェルの接続
- 03データとエラー処理の境界のレビュー
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ pproenca/ dot-skills --skill swift-ui-architectインストール後、Claude Code で/swift-ui-architectを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
metadata.jsonassets/templates/_template.mdreferences/_sections.mddata-async-init.mddata-cancellation.mddata-combine-avoid.mddata-error-loadable.mddata-task-modifier.mddi-container-composition.mddi-environment-injection.mddi-mock-testing.mddi-protocol-abstraction.mddiff-avoid-anyview.mddiff-closure-skip.mddiff-equatable-views.mddiff-identity-stability.mddiff-printchanges-debug.mddiff-reference-types.mdlayer-dependency-rule.mdlayer-model-value-types.mdlayer-no-view-repository.mdlayer-repository-protocol.mdlayer-usecase-protocol.mdlayer-viewmodel-boundary.mdlist-constant-viewcount.mdlist-filter-in-model.mdlist-id-keypath.mdlist-lazy-stacks.mdnav-coordinator-pattern.mdnav-deeplink-support.md詳細
SwiftUI Modular MVVM-C Architecture
SwiftUI のクリニック形式アプリ向けに、アーキテクチャを適用するための指針です。このスキルは、iOS 26/Swift 6.2 のクリニックアーキテクチャに沿っています。ローカルの SPM パッケージによるモジュール化された MVVM-C、App ターゲットに配置する具象コーディネーターとルートシェル、純粋な Domain プロトコル、唯一の I/O レイヤーである Data で構成されます。
必須のアーキテクチャスタック
┌───────────────────────────────────────────────────────────────┐
│ App target: DependencyContainer, Coordinators, Route Shells │
├───────────────┬───────────────┬───────────────┬──────────────┤
│ Feature* SPM │ Feature* SPM │ Feature* SPM │ Feature* SPM │
│ View + VM │ View + VM │ View + VM │ View + VM │
├───────────────────────────────────────────────────────────────┤
│ Data SPM: repository impls, remote/local, retry, sync queue │
├───────────────────────────────────────────────────────────────┤
│ Domain SPM: models, repository protocols, coordinator protocols│
│ and ErrorRouting/AppError │
├───────────────────────────────────────────────────────────────┤
│ Shared SPMs: DesignSystem, SharedKit │
└───────────────────────────────────────────────────────────────┘
依存関係のルール:Feature モジュールがインポートできるのは Domain と DesignSystem のみです。Feature は Data や他の Feature をインポートしてはなりません。App ターゲットのみが依存関係の合流点となります。
クリニックアーキテクチャの契約(iOS 26/Swift 6.2)
このスキルのすべてのガイダンスは、クリニックのモジュール化された MVVM-C アーキテクチャを前提としています。
- Feature モジュールがインポートできるのは
DomainとDesignSystemのみです(Dataや兄弟 Feature はインポートしません)。 - App ターゲットが合流点となり、
DependencyContainer、具象コーディネーター、Route Shell の配線を所有します。 Domainは純粋な Swift を維持し、モデルに加えて、リポジトリ、*Coordinating、ErrorRouting、AppErrorの契約を定義します。Dataは SwiftData/ネットワーク/同期/リトライ/バックグラウンド I/O を所有し、Domain プロトコルを実装します。- 読み取り/書き込みフローでは、古いデータを表示しながら再検証する読み取りと、キューに入れて楽観的に処理する書き込みをデフォルトとします。
- ViewModel はリポジトリプロトコルを直接呼び出します(ユースケース/インタラクター層はデフォルトでは設けません)。
適用する場面
次のような場合に、これらのガイドラインを参照してください。
- ローカルの SPM パッケージにある Feature モジュールを構築またはリファクタリングするとき
- コーディネーター、ルートシェル、依存関係コンテナのファクトリーを接続するとき
- リポジトリ、コーディネーター、エラー処理の Domain プロトコルを定義するとき
- ネットワーク通信、永続化、同期の所有範囲を Data のみに限定するとき
- 古いデータを表示しながら再検証する読み取りと、キューに入れて楽観的に処理する書き込みをレビューするとき
必須制約(iOS 26/Swift 6.2)
- ViewModel/コーディネーターには
@Observableを使用し、ObservableObject/@Publishedは使用しません。 - 専用のユースケース/インタラクター層は設けません。ViewModel が Domain のリポジトリプロトコルを直接呼び出します。
- コーディネータープロトコルは Domain に配置し、具象コーディネーターは App ターゲットで
NavigationPathを所有します。 - ルートシェルは App ターゲットに配置し、
.navigationDestinationのマッピングを所有します。 - 表示ポリシーは
AppErrorとErrorRoutingによって制御します。ViewModel にグローバルなエラー UI をハードコードしません。 - SwiftData/URLSession/リトライ/同期キューのロジックは Data パッケージのみに配置します。
優先度別のルールカテゴリ
| 優先度 | カテゴリ | 影響度 | プレフィックス | ルール |
|---|---|---|---|---|
| 1 | View のアイデンティティと差分検出 | 重大 | diff- | 6 |
| 2 | 状態アーキテクチャ | 重大 | state- | 7 |
| 3 | View の構成 | 高 | view- | 6 |
| 4 | ナビゲーションとコーディネーション | 高 | nav- | 5 |
| 5 | レイヤーアーキテクチャ | 高 | layer- | 6 |
| 6 | 依存性注入 | 中〜高 | di- | 4 |
| 7 | リストとコレクションのパフォーマンス | 中 | list- | 4 |
| 8 | 非同期処理とデータフロー | 中 | data- | 5 |
クイックリファレンス
1. View のアイデンティティと差分検出(重大)
diff-equatable-views- すべての SwiftUI View に @Equatable マクロを適用するdiff-closure-skip- クロージャ/ハンドラープロパティには @SkipEquatable を使用するdiff-reference-types- Equatable 準拠なしに参照型を保存しないdiff-identity-stability- ForEach では安定した O(1) の識別子を使用するdiff-avoid-anyview- AnyView は使用せず、@ViewBuilder またはジェネリクスを使用するdiff-printchanges-debug- 不要な再描画の原因を調べるには _printChanges() を使用する
2. 状態アーキテクチャ(重大)
state-observable-class- すべての ViewModel に @Observable クラスを使用しますstate-ownership- 所有するデータには @State を、注入されるデータには通常のプロパティを使用しますstate-single-source- 状態の各要素につき、信頼できる情報源を 1 つにしますstate-scoped-observation- @Observable のプロパティ単位の追跡を活用しますstate-binding-minimal- 双方向のデータフローに限り、@Binding を渡しますstate-environment-global- アプリ全体で共有する依存関係には @Environment を使用しますstate-no-published- @Published や ObservableObject は決して使用しません
3. View の構成(高)
view-body-complexity- view body 内のノードは最大 10 個にしますview-extract-subviews- 算出プロパティやヘルパーを個別の View 構造体に切り出しますview-no-logic-in-body- body にビジネスロジックを含めませんview-minimal-dependencies- モデル全体ではなく、必要なプロパティのみを渡しますview-viewbuilder-composition- 条件付きの構成には @ViewBuilder を使用しますview-no-init-sideeffects- View の init で処理を実行してはいけません
4. ナビゲーションと調整(高)
nav-coordinator-pattern- すべての機能に、NavigationStack を所有するコーディネーターを設けますnav-routes-enum- すべてのルートを Hashable な enum として定義しますnav-deeplink-support- コーディネーターは URL ベースのディープリンクに対応する必要がありますnav-modal-sheets- モーダルはインラインではなく、コーディネーター経由で表示しますnav-no-navigationlink- NavigationLink(destination:) は使用せず、navigationDestination(for:) を使用します
5. レイヤーアーキテクチャ(高)
layer-dependency-rule- Domain レイヤーではフレームワークを一切インポートしませんlayer-usecase-protocol- ユースケースレイヤーを追加せず、ViewModel とリポジトリプロトコルにオーケストレーションを保持しますlayer-repository-protocol- リポジトリプロトコルは Domain に、実装は Data に配置しますlayer-model-value-types- Domain モデルは構造体とし、クラスは使用しませんlayer-no-view-repository- View からリポジトリに直接アクセスせず、ViewModel からリポジトリプロトコルを呼び出しますlayer-viewmodel-boundary- ViewModel が公開する状態は、表示用に整えたものだけにします
6. 依存性注入(中〜高)
di-environment-injection- コンテナが管理するプロトコル依存関係は @Environment 経由で注入しますdi-protocol-abstraction- 注入する依存関係はすべてプロトコル型にしますdi-container-composition- App ターゲットでDependencyContainerを構成し、VM ファクトリーを公開しますdi-mock-testing- すべてのプロトコル依存関係に、テスト用のモックを用意します
7. リストとコレクションのパフォーマンス(中)
list-constant-viewcount- ForEach は要素ごとに一定数の View を生成する必要がありますlist-filter-in-model- フィルタリングやソートは ViewModel で行い、ForEach 内では行いませんlist-lazy-stacks- 上限のないコンテンツには LazyVStack/LazyHStack を使用しますlist-id-keypath- 明示的な id keyPath を指定し、暗黙の識別性に依存しません
8. 非同期処理とデータフロー(中)
data-task-modifier-.task(id:)を機能のデータ読み込みの主なトリガーとして使用しますdata-async-init- init 内で非同期処理を実行しないでくださいdata-error-loadable- 読み込み状態はブール値ではなく enum としてモデル化しますdata-combine-avoid- 新しいコードでは Combine より async/await を優先しますdata-cancellation-.taskによる自動キャンセルを使用し、Task を手動で管理しないでください
使用方法
詳しい説明とコード例については、個別のリファレンスファイルをお読みください。
- セクションの定義 - カテゴリーの構成と影響レベル
- ルールのテンプレート - 新しいルールを追加するためのテンプレート
リファレンスファイル
| ファイル | 説明 |
|---|---|
| references/_sections.md | カテゴリーの定義と順序 |
| assets/templates/_template.md | 新しいルールのテンプレート |
| metadata.json | バージョンとリファレンス情報 |
コメント
Markdown 対応