设计规约
设计规约将架构设计原则落地为可执行的工程规范,涵盖 UML 建模指导、面向对象设计原则、可扩展性设计等核心内容。
提示
阿里巴巴系统设计规范与UML建模指导
强制规则
系统设计必须遵守的规范:
存储方案和底层数据结构的设计获得评审一致通过,并沉淀成为文档。
在需求分析阶段,如果与系统交互的User超过一类并且相关的User Case超过5个,使用用例图表达。
如果某个业务对象的状态超过3个,使用状态图表达并明确状态变化的各个触发条件。
如果系统中某个功能的调用链路上的涉及对象超过3个,使用时序图表达。
如果系统中模型类超过5个,并且存在复杂的依赖关系,使用类图表达。
如果系统中超过2个对象之间存在协作关系,并且需要表示复杂的处理流程,使用活动图表示。
接口契约层面,错误码是 API 设计中最先需要统一的部分——错误码怎么分类、怎么编排、怎么随响应返回,直接影响前后端联调效率与线上排障速度,完整规范见 错误码设计。
推荐的架构设计目标
- 确定系统边界:确定系统在技术层面上的做与不做
- 确定系统内模块之间的关系:确定模块之间的依赖关系及宏观输入与输出
- 确定指导后续设计与演化的原则
- 确定非功能性需求:安全性、可用性、可扩展性
面向对象设计原则
单一职责原则
类在设计与实现时要符合单一原则。随着系统演进,很多时候会忘记类设计的初衷。
里氏替换原则
不得已使用继承的话,必须符合里氏代换原则——父类能够出现的地方子类一定能够出现。
依赖倒置原则
系统设计阶段,尽量依赖抽象类与接口,有利于扩展与维护。低层次模块依赖于高层次模块的抽象。
开闭原则
系统设计阶段,注意对扩展开放,对修改闭合。交付的代码在极端情况下是不可修改的。
DRY原则
共性业务或公共行为抽取出来公共模块、公共配置、公共类、公共方法等,在系统中不出现重复代码。
UML建模指导
| 场景 | 推荐图例 | 说明 |
|---|---|---|
| 需求分析 | 用例图 | User Case > 5个 |
| 状态管理 | 状态图 | 状态 > 3个 |
| 调用链路 | 时序图 | 调用对象 > 3个 |
| 类结构 | 类图 | 模型类 > 5个 |
| 协作流程 | 活动图 | 协作对象 > 2个 |
状态图示例
订单状态流转(任何状态下都可能被取消):
时序图示例
下单的调用链路:
可扩展性本质
可扩展性的本质是找到系统的变化点,并隔离变化点。
世间众多设计模式其实就是一种设计模式——即隔离变化点的模式。极致扩展性的标志,就是需求的新增,不会在原有代码交付物上进行任何形式的修改。
设计文档的价值
- 明确需求
- 理顺逻辑
- 后期维护
- 次要目的:指导编码
注意:代码即文档的观点是错误的。代码的深度调用、模块层面上的依赖关系网、业务场景逻辑、非功能性需求等问题需要相应的文档来完整呈现。
架构设计文档模板
一份可落地的设计文档建议包含以下章节(按评审场景裁剪):
| 章节 | 核心内容 | 回答的问题 |
|---|---|---|
| 背景与目标 | 业务背景、要解决的问题、衡量指标 | 为什么做?做到什么程度算成功? |
| 需求范围 | 功能清单、非功能性需求(性能/可用性/安全) | 做什么?不做什么? |
| 总体方案 | 架构图、模块划分、技术选型及理由 | 怎么做?为什么这么选? |
| 关键设计 | 领域模型、状态机、核心时序、存储设计 | 核心难点如何解决? |
| 接口设计 | API 列表、错误码、幂等与限流策略 | 上下游如何协作? |
| 风险与备选 | 风险清单、备选方案对比、回退策略 | 出问题怎么办? |
| 演进路线 | 分期实施计划、兼容性方案 | 如何落地?先做什么? |
设计评审清单
提交评审前自查:
适用场景
| 场景 | 应用规范 | 原因 |
|---|---|---|
| 新项目启动 | 存储方案评审 + UML 建模 | 提前识别设计风险 |
| 复杂业务流程 | 状态图 + 时序图 | 明确状态转换和调用链路 |
| 团队协作开发 | DRY 原则 + 依赖倒置 | 降低耦合,提高可维护性 |
| 系统重构 | 可扩展性设计 + 单一职责 | 隔离变化点,降低修改风险 |
FAQ
Q: 什么时候需要画 UML 图? A: 阿里规范给出了明确阈值:User Case 超过 5 个画用例图,状态超过 3 个画状态图,调用对象超过 3 个画时序图,模型类超过 5 个画类图,协作对象超过 2 个画活动图。不是所有设计都需要 UML,简单功能直接编码即可。
Q: DRY 原则和过度抽象的界限在哪? A: DRY 消除的是"重复的业务逻辑",而非"相似的代码结构"。如果两段代码恰好结构相似但业务含义不同,强行抽象会导致一个业务的修改影响另一个业务。判断标准:如果修改一处逻辑时必须同步修改另一处,才是真正的重复,需要抽象。
Q: 代码即文档为什么是错误的? A: 代码只能表达"怎么做",无法表达"为什么这么做"。业务背景、设计决策、取舍权衡、非功能性需求(性能指标、安全要求)等信息无法从代码中获取。深度调用链、模块间的依赖关系网也需要架构文档来呈现。