mcpField
D
domain-architect

domain-architect

github.com/pproenca開発218239 回インストール11 週間前に更新
リポジトリ

domain-architect について

domain-architectは、ユーザー向けの製品機能からビジネスドメインとアーキテクチャの垂直スライスを整理するスキルです。開発者がTypes、クライアント、Repo、Service、Runtime、UIを追跡し、レイヤーの不足や境界に関する疑問を記録できます。

主な機能

  1. 01機能起点のドメイン発見
  2. 02垂直スライスのレイヤー整理
  3. 03プロバイダーと横断的関心事の分類
  4. 04レイヤー不足と境界の疑問を記録

活用シーン

  1. 01既存のSwiftコードベースのドメイン整理
  2. 02依存クライアントとReducerの追跡
  3. 03チームでのドメイン境界の検討

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/pproenca/dot-skills --skill domain-architect

インストール後、Claude Code で/domain-architectを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

metadata.json
references/
architecture.als
architecture.md
principles.md

詳細

ドメインアーキテクト

ユーザーが何を実行できるか、つまり製品の機能をたどり、各機能をアーキテクチャの垂直スライスに対応づけて、ビジネスドメインを見つけます。

フォルダー名、アーキテクチャドキュメント、ファイル数から始めるのではありません。製品から始めます。

作成するもの

すべての基盤となる、ドメインマップという単一の成果物です。

Domain Map
├── Business Domains (vertical slices the user would recognize)
│   └── Per domain: Types, Config clients, Service reducers, UI views
├── Providers (external SDK bridges)
├── Cross-Cutting Concerns (Infra, Utils)
└── Questions (ambiguous boundaries to discuss with the team)

ドメインマップが正しければ、フォルダー構成、SPM ターゲット、適用ルールの仕様、移行計画はすべて機械的に決まります。ドメインを誤ると、その後のすべてが誤ったものになります。

ドメインの仕組み

レイヤーの詳細な仕様は references/architecture.md をお読みください。 形式検証可能なモデルは references/architecture.als をお読みください。

ドメインとはユーザーの機能です

判定基準:エンジニア以外の人に、一文で説明できますか?

  • 「予約をスケジュールする」— ドメイン(Calendar)
  • 「支払いを受け付ける」— ドメイン(Payments)
  • 「利用可能な施術を閲覧する」— ドメイン(Treatments)
  • 「HTTP リクエストを処理する」— ドメインではありません(インフラストラクチャ)
  • 「日付をフォーマットする」— ドメインではありません(ユーティリティ)
各ドメインは垂直スライスを所有します
Types    → pure data definitions for this domain's nouns
Config   → @DependencyClient interfaces (what you can ask for)
Repo     → implementations (how it's done — API, persistence, sync)
Service  → @Reducer state machines (business decisions)
Runtime  → dependency wiring (Config interfaces → Repo implementations)
UI       → SwiftUI views (pixels)

すべてのドメインにすべてのレイヤーが必要なわけではありません。小規模なドメインは、Config + Service + UI のみで構成される場合もあります。ただし、Types、Config、Service は、実際のドメインとして成立するために最低限必要です。

ドメイン同士で内部実装をインポートしません

ドメイン間の通信は、次の方法で行います。

  • デリゲートアクションを親リデューサーに渡す
  • Shared Types(共通の語彙)
  • Shared Config インターフェース(2 つのドメインが同じクライアントを使う場合)

別のドメインの Service や Repo をインポートして通信することはありません。

ドメインではないもの
対象内容配置先
エラー処理横断的関心事Infra
ログ記録/テレメトリー横断的関心事Infra
フォーマッター、定数横断的関心事Utils
Sentry、Stripe SDK、APNSプロバイダー(SDK ブリッジ)Providers
HTTP トランスポート、永続化エンジン共通インフラストラクチャRepo
デザインシステムのトークン共通 UIDesignSystem
バックグラウンドタスクのスケジューリングプラットフォーム連携Runtime

プロセス

ステップ 1:ユーザーは何を実行できますか?

エントリーポイントから始めます。@main、ルートリデューサー、タブ構成を読みます。すべての子スコープやタブが、ドメイン候補です。

grep -r "@main" <project-root> --include="*.swift" -l

ルートリデューサーを読みます。Scope と CombineReducers をたどり、すべての子機能を見つけます。タブの列挙型をたどり、トップレベルの機能をすべて見つけます。

複数のアプリで構成される製品(例:患者向けアプリ + クリニック向けアプリ)では、各アプリについてこの作業を行います。同じビジネスドメインが、アプリごとに異なる動詞を使って登場することがよくあります。

ステップ 2:どのような動詞がありますか?

すべての @DependencyClient は動詞、つまりシステムが実行できる機能です。

grep -r "@DependencyClient" <project-root> --include="*.swift" -l

各クライアントファイルを読みます。各クライアントについて、次の点を記録します。

  • 動詞(クロージャ名:fetch、create、cancel、observe)
  • 名詞(受け渡される型:Appointment、Treatment、Patient)
  • 所属するドメイン(名詞から推測します)

クライアントをドメインごとにグループ化します。これにより、Config レイヤーのマップが作成できます。

ステップ 3:どのような名詞がありますか?

名詞は Types レイヤーにあります。Types は共通の語彙です。

find <project-root> -name "Package.swift" -not -path "*/.build/*"

Package.swift ファイルを読み、Types ターゲットを見つけます。そのソースファイルを読み、ドメインの言語を理解します。どのようなエンティティが存在するか、どの ID に型が付いているか、どのような操作が定義されているかを確認します。

ステップ 4:各ドメインの垂直スライスをマッピングする

ステップ 1~2 で見つかった各ドメインについて、垂直構造全体をたどります。

レイヤー確認すること調べ方
Typesこのドメインではどのような名詞が使われていますか?Types パッケージでドメインの名詞を検索します
Configどのような要求ができますか?ステップ 2 の @DependencyClient ファイルを確認します
Repoデータはどのように取得・保存されていますか?DataService、Repository、Store とドメインの名詞を検索します
Serviceどのような判断が行われていますか?@Reducer とドメイン名を検索します
Runtimeどこで接続されていますか?Registration とドメイン名を検索します
UIユーザーには何が表示されますか?View とドメイン名を検索します

各ドメインの各レイヤーについて、少なくとも 1 つのファイルを読みます。 名前から推測しないでください。

ステップ 5:プロバイダーを特定する

プロバイダーは外部 SDK をラップします。ドメインではなく、ブリッジです。

以下を探します。

  • サードパーティ製フレームワークのインポート(Stripe、Firebase、Sentry、Amplitude)
  • SDK の初期化コード
  • 外部の型をドメインの型に橋渡しするプロトコル準拠
grep -r "import Stripe\|import Firebase\|import Sentry\|import Amplitude" <project-root> --include="*.swift" -l
ステップ 6:横断的関心事を特定する

ドメインとプロバイダー以外に残るものは何でしょうか?それが横断的関心事です。

  • Infra:エラー型、テレメトリープロトコル、ロギングの抽象化
  • Utils:純粋なフォーマッター、定数、アクセシビリティ ID
  • DesignSystem:トークン、スタイル、共有 UI コンポーネント

これらはどのドメインからもインポートできますが、ドメインの知識は含みません。

ステップ 7:曖昧な点を明示する

本当に曖昧なものもあります。質問として明示してください。

  • 「Profile はドメインですか、それとも Auth の一部ですか?」— Profile には独自のクライアントと UI がありますが、アバターのアップロードは Auth を経由します。チームと相談してください。
  • 「Booking は Calendar の一部ですか、それとも独立したドメインですか?」— 独自のクライアントがありますが、Calendar タブ内にあります。複雑さによって異なります。
  • 「Notifications はドメインですか、それとも横断的関心事ですか?」— 独自の UI とクライアントがありますが、Types はごくわずかです。判断が分かれるところです。

決定事項ではなく、質問として提示してください。チームにはあなたの知らない背景情報があります。


出力形式

ドメインマップ

各ドメインについて:

### [Domain Name] — "[one-sentence description]"

**Nouns**: [Types this domain speaks — Appointment, Treatment, etc.]
**Verbs**: [Client capabilities — fetch, create, cancel, observe]

| Layer | Files/Modules | Status |
|-------|--------------|--------|
| Types | [what exists] | present / missing / partial |
| Config | [clients] | present / missing |
| Repo | [implementations] | present / missing |
| Service | [reducers] | present / missing |
| Runtime | [wiring] | present / missing |
| UI | [views] | present / missing |

**Cross-app**: Patient app: [verbs]. Clinic app: [verbs].
プロバイダー
| Provider | SDK | Used by domains |
|----------|-----|----------------|
| Sentry | Error monitoring | All (Infra) |
| Stripe Terminal | In-person payments | Payments |
横断的関心事
| Concern | Layer | Purpose |
|---------|-------|---------|
| AppDomainError | Infra | Error vocabulary |
| Telemetry | Infra | Monitoring |
| AccessibilityId | Utils | UI testing |
質問
1. Is Profile a domain or part of Auth? [evidence for each]
2. Should Booking be extracted from Calendar? [evidence]

近道を避けるルール

  1. ファイルではなく、プロダクトから始めます。「ユーザーには何ができますか?」を「どのようなファイルがありますか?」より先に考えます。

  2. フォルダーパスで分類しないでください。 Services/ 内のファイルが UI コードである場合もあります。分類する前に読みましょう。

  3. 自分なりの見解をまとめる前に、アーキテクチャのドキュメントを読まないでください。 harness-spec.yml や ARCHITECTURE.md がある場合は、ドメインのマッピングを終えてから読みます。自分のマップと照らし合わせてください。不一致こそ、最も価値のある発見です。

  4. 似ているように見えるからといって、ドメインを省略しないでください。 各ドメインについて、それぞれ独自に垂直構造をたどります。Auth は Profile ではありません。

  5. 200 ファイルを超えるコードベースでは、サブエージェントを使います。 ドメインごとにエージェントを 1 つ割り当て、それぞれが垂直構造全体をたどります。これにより、コンテキストの制約による近道を防げます。

  6. 判断するのではなく、曖昧な点を明示します。 チームの背景情報をあなたは持っていません。両方の見解を裏付ける根拠を提示し、チームに判断を委ねてください。


深度の要件

  1. クライアントの 100% を把握する — 見つかったすべての @DependencyClient をドメインに割り当てます
  2. リデューサーの 100% を把握する — 見つかったすべての @Reducer をドメインに割り当てます
  3. ドメインごとに垂直構造をたどる — 各ドメインの各レイヤーについて、少なくとも 1 つのファイルを読みます
  4. 境界の根拠を示す — 各ドメイン境界を正当化する名詞・動詞を挙げます
  5. 不足を明示する — 欠けているレイヤーを報告します(Service はあるが Config がないドメインなども、発見事項です)
  6. 推測より質問を優先する — 確信が持てない場合は推測せず、質問します

コメント