| name | architecture-design |
| description | 在用户要求设计软件架构、撰写架构设计文档、做架构评审,或讨论模块划分/层间依赖/对外API设计时使用此skill。引导按照"整体先行、模块职责明确、易用性优先、模块隔离、依赖倒置"等设计原则自顶向下展开设计,并产出结构化的架构文档。触发场景包括但不限于:"帮我设计一下这个SDK/模块的架构"、"写一份架构设计文档"、"这个架构合理吗,帮我评审一下"、"这几个模块该怎么划分职责"、"这个功能该放在哪一层"。既适用于通用软件架构,也适用于iOS/移动端SDK架构(此时会给出更具体的模式建议)。即使用户没有直接说"架构"两个字,只要讨论的是顶层模块拆分、对外接口设计、层间依赖关系,也应主动使用此skill。 |
架构设计
帮助以自顶向下、原则驱动的方式设计软件架构,并产出结构化的架构文档。这不是一个"填模板"的机械流程——每一步都是为了让最终的架构对使用它的人(无论是调用你API的其他工程师,还是未来维护这段代码的自己)尽可能友好、稳固、不易腐化。
硬性要求:架构图和类图不能省略
任何一份架构文档,必须包含一张整体架构图(第 2 步产出)和至少一张核心模块的类图(第 4 步产出),用 mermaid 的 graph/flowchart 和 classDiagram 表示。文字描述模块关系或类关系时非常容易含糊带过——"A 依赖 B 的抽象接口"这句话读起来通顺,但只有画出图才能立刻暴露出这句话背后到底有没有想清楚。
这两张图是产出物的一部分,不是"如果篇幅允许就加上"的锦上添花。写完文档后,在交付前自查一遍:这份文档里有没有整体架构图?关键模块有没有类图? 如果没有,说明设计流程还没走完,不要跳过图直接把文字部分交出去。做架构评审(而非从零设计)时同样适用——评审意见里如果指出了模块关系问题,也应该用图把问题点画出来,而不是只用文字描述。
为什么要自顶向下
架构设计最容易踩的坑,是过早陷入某个模块内部的实现细节,还没想清楚模块之间该怎么划分职责,就已经在纠结某个类该用什么设计模式了。这样做出来的架构往往是"拼凑"出来的——模块边界模糊、职责重叠、后期改一个模块要牵连一堆其他模块。
所以设计顺序应该是:先定整体骨架,再填模块细节。具体来说,遵循下面四步,不要跳步:
- 明确整体架构范围与约束 —— 不了解使用场景和边界,任何架构决策都是猜测
- 整体架构总览 —— 划分模块、明确每个模块"是干什么的"(一句话概括职责,不涉及内部实现)
- 模块间依赖关系 —— 谁依赖谁,是否存在循环依赖或不合理的耦合
- 关键模块详细设计 —— 只对核心/复杂模块展开内部设计,边缘模块无需展开
第一步:明确设计范围(先问,别猜)
在动笔画架构之前,向用户确认(如果对话里已经提到了,就不用重复问):
- 这个架构服务于谁?上层调用者是谁(是应用层开发者?是SDK的接入方?还是团队内其他模块)?
- 现有的技术约束是什么(语言、平台、必须复用的现有模块、性能/包体积限制)?
- 大概的功能边界在哪里?哪些明确不做?
- 是全新设计,还是在现有架构上做调整/评审?
如果用户已经在需求里给出了这些信息,不要机械地重复提问——直接进入设计,把你的理解简要复述一遍作为确认即可。
第二步:整体架构总览
先不要展开任何模块的内部实现,只做三件事:
- 划分模块:按职责边界拆出顶层模块(不是按"文件"或"类"拆,而是按"这块东西负责做什么事"拆)
- 给每个模块一句话职责描述:如果一句话说不清楚,说明这个模块的边界还不够清晰,需要重新划分
- 画出整体架构图:用 mermaid(
graph TD 或 flowchart)把模块和它们之间的调用/依赖方向画出来。纯文字描述模块关系很容易含糊带过,图能立刻暴露出"这两个模块到底谁依赖谁"没想清楚的地方。这张图是文档里必须有的产出,不是可选项。
判断模块划分是否合理的一个简单测试:能不能把某个模块的实现完全换掉,而不影响其他模块? 如果答案是"不能,因为其他模块依赖了它的具体实现细节",说明耦合过紧,需要重新考虑边界或引入抽象层。
第三步:模块间依赖关系与隔离性检查
基于第二步画出的整体架构图,逐条检查依赖关系(如果依赖关系比整体架构图更细,可以单独再画一张更细的 mermaid 依赖图):
- 是否存在循环依赖?A 依赖 B,B 又依赖 A,这是明确的坏味道,需要重新设计(通常是把共享部分抽出到更底层的模块,或引入接口层打破环)
- 依赖方向是否合理?稳定的、通用的模块应该在下层,容易变化的、业务相关的模块应该在上层依赖下层,而不是反过来
- 模块之间是否通过接口/协议通信,而不是直接依赖具体实现?这是实现"模块隔离"的关键——上层模块拿到的应该是一个抽象(协议/接口/协议缓冲区定义的服务契约),而不是另一个模块的具体类。这样做的好处是:任何一个模块的内部实现可以被替换、mock、独立测试,而不会波及使用它的其他模块。
这一步对应用户提到的核心原则之一:不同模块之间要能实现软件隔离。
第四步:关键模块详细设计
只对核心、复杂、或未来可能频繁变化的模块展开内部设计,不需要每个模块都展开到类级别。对每个展开的模块,明确:
- 内部子职责划分(这个模块内部又分成了哪几块)
- 对外暴露的接口/API 长什么样
- 关键的数据流转和状态管理方式
- 用 mermaid
classDiagram 画出该模块的核心类型/协议及其关系(继承、实现、组合、依赖)。类图要能直接看出:对外暴露的协议是什么、具体实现类有哪些、谁依赖谁——这也是复查"依赖倒置"和"接口隔离"是否落地的最直观方式。只对本步骤展开的关键模块画类图,不需要覆盖全部模块。
第五步:设计原则自查表
架构草稿画完后,逐条自查,而不是设计完就完事。用户提到的几个核心原则,具体检查方式如下:
| 原则 | 含义 | 自查问题 |
|---|
| 易用性优先(对上层API使用者友好) | 上层调用者应该用最少的心智负担完成任务 | 调用一个功能需要几步?有没有强制上层理解内部实现细节才能正确使用?默认行为是否符合直觉(最小惊讶原则)? |
| 模块隔离 | 模块间通过抽象通信,内部实现可独立替换 | 能否单独 mock/替换某个模块而不改动调用方代码?模块间是否只暴露协议/接口,而不是具体类? |
| 依赖倒置(DIP) | 高层模块不应依赖低层模块的具体实现,两者都应依赖抽象 | 高层业务逻辑里有没有直接 new 一个底层实现类?还是依赖的是一个协议/接口? |
| 单一职责(SRP) | 一个模块/类只应该有一个变更的理由 | 这个模块的职责描述里有没有用"和"字连接两件不相关的事? |
| 开闭原则(OCP) | 对扩展开放,对修改关闭 | 增加一个新的实现/新的能力,是否需要改动已有模块的代码,还是只需新增一个符合协议的实现? |
| 接口隔离(ISP) | 不应强迫调用方依赖它用不到的接口 | 有没有某个模块的接口很臃肿,调用方只用得到其中一小部分? |
不是每条原则都要生搬硬套——如果某条原则在当前场景下明显不适用(比如项目规模很小,过度抽象反而增加复杂度),要在文档里说明取舍理由,而不是为了合规而合规。
输出:架构文档模板
设计走完以上几步后,产出如下结构的架构文档(章节标题可以按项目情况微调措辞,但顺序和覆盖范围建议保持):
# [项目/模块名] 架构设计文档
## 1. 整体架构总览
- 设计背景与目标(服务谁、解决什么问题)
- 技术约束
- 整体架构图(mermaid `graph TD`/`flowchart`,展示顶层模块及调用/依赖方向)
## 2. 模块职责表
| 模块 | 核心职责(一句话) | 对外暴露的能力 | 依赖的其他模块 |
|---|---|---|---|
## 3. 模块间依赖关系
- 依赖方向说明(可复用第 1 节的架构图,或单独画一张更细的依赖图)
- 模块间通信方式(协议/接口/事件等)
- 循环依赖排查结果
## 4. 关键模块详细设计
(对每个展开的核心模块,逐个描述内部职责划分、关键接口、状态管理,并附上该模块的 mermaid `classDiagram`)
## 5. 设计原则自查表
(按第五步的表格,逐条给出自查结论和必要的取舍说明)
如果是做架构评审而非从零设计,跳过模板产出,直接按第二~五步的检查逻辑,对现有架构逐项过一遍,给出具体问题和改进建议,而不是泛泛而谈"耦合度高"。
iOS / 移动端 SDK 场景
如果当前讨论的是 iOS/移动端 SDK 或组件化架构,在通用原则的基础上,参考 references/ios-patterns.md 中的具体模式(CocoaPods 组件化拆分方式、Protocol-Oriented 接口隔离、Clean Architecture/MVVM 分层选择、Protobuf/gRPC 服务契约的模块隔离实践)。这些是从实际 iOS SDK 项目中提炼出的可复用经验,但仍然要结合当前项目的实际规模判断是否适用——不要把重量级分层生搬硬套到一个很小的模块上。