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识别 Provider 与横切关注点
  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 是构成真正领域的最低要求。

领域之间不会导入彼此的内部实现

跨领域通信通过以下方式进行:

  • 将代理操作委托给父级 reducer
  • 共享 Types(通用词汇)
  • 共享 Config 接口(两个领域使用同一个客户端时)

绝不通过导入其他领域的 Service 或 Repo 来通信。

什么不是领域
事物类型所在位置
错误处理横切关注点Infra
日志/遥测横切关注点Infra
格式化器、常量横切关注点Utils
Sentry、Stripe SDK、APNS提供方(SDK 桥接)Providers
HTTP 传输、持久化引擎共享基础设施Repo
设计系统令牌共享 UIDesignSystem
后台任务调度平台集成Runtime

流程

第 1 步:用户能做什么?

从入口点入手。阅读 @main、根 reducer 和标签页结构。每个子作用域或标签页都可能是一个领域。

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

阅读根 reducer。追踪其 Scope 和 CombineReducers,找出所有子功能。追踪标签页枚举,找出所有顶层功能。

对于多应用产品(例如患者应用 + 诊所应用),对每个应用都执行此操作。同一个业务领域通常会出现在两个应用中,但动词不同。

第 2 步:有哪些动词?

每个 @DependencyClient 都是一个动词——系统能够执行的一项功能。

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

阅读每个客户端文件。对每个客户端,记录:

  • 动词(闭包名称:fetch、create、cancel、observe)
  • 名词(流转的类型:Appointment、Treatment、Patient)
  • 所属的领域(根据名词推断)

按领域对客户端分组。这就是 Config 层映射。

第 3 步:有哪些名词?

名词位于 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 和领域名称

每个领域的每一层至少阅读一个文件。 不要凭名称猜测。

第 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 个文件的代码库,使用子 Agent。 每个领域分配一个 Agent, 分别追踪完整垂直链路。这样可以避免在上下文压力下走捷径。

  6. 标记模糊之处,而不是自行决定。 你不了解团队的 背景信息。请列出双方的依据,让团队决定。


深度要求

  1. 100% 客户端发现率——找到每个 @DependencyClient 并将其归入某个领域
  2. 100% Reducer 发现率——找到每个 @Reducer 并将其归入某个领域
  3. 每个领域追踪垂直链路——每个领域的每一层至少阅读一个文件
  4. 为边界提供依据——引用用于论证每个领域边界的名词/动词
  5. 明确指出缺口——报告缺失的层(例如:领域有 Service,但没有 Config,这就是一项发现)
  6. 有疑问就提问,不要假设——不确定时,提问而不是猜测

评论

支持 Markdown