UML图到底要画几张?删掉37张图后我总结的「三图原则」
一、先说个丢人的事
2019年我接手一个电商中台项目,前任架构师交接时甩给我一个压缩包,解压出来37张UML图,全是JPG,命名从 图1.jpg 一路排到 图37.jpg。那次交接会开了两个小时,我一个类名都没看清——图是从4K屏上直接截的,塞进A4纸里类名大概三号字。后来我自己做了个很土的统计(就是挨个问同事),半年内这37张图被真正点开看过的只有5张,剩下32张躺在Wiki第三层目录里,站内搜索都搜不出来,因为标题叫「设计文档V2最终」。
这件事之后我对UML的看法就变了。UML 2.5定义了14种图,7种结构图7种行为图,我当年软考背得滚瓜烂熟,但工作8年真正动手画过的就三种:类图、时序图、状态机图。用例图我也画过,画完发现它本质上是给产品经理和甲方看的,跟工程师之间的沟通效率关系不大——你把用例图画得跟花一样,后端该不懂的还是不懂,因为他不关心actor是谁,他关心的是这个接口失败了要不要重试。
二、14种图和现实的差距,摆个表
先把结论撂这儿:UML 2.5那14种图里,能活着进Git仓库的不到三分之一。我按自己的使用频率列了个表,纯个人数据,不权威:
| 图类型 | 我最近3年画过几次 | 主要问题 |
|---|---|---|
| 类图 | 约40次 | 超过25个类就看不清了 |
| 时序图 | 约70次 | 画一次改三次,维护成本最高 |
| 状态机图 | 约15次 | 订单/工单场景真香,其他场景用不上 |
| 用例图 | 3次 | 甲方爱看,工程师不看 |
| 活动图 | 5次 | 流程图工具能替代,没必要上UML |
| 部署图 | 2次 | 一次是画给运维看的,一次是画给领导看的 |
| 通信图/时序图旧版 | 0次 | 没人用,真的 |
| 其余7种 | 0次 | 我甚至想不起全名 |
对比一下就更明显:教科书花两章讲组合(Composition)和聚合(Aggregation)的实心菱形和空心菱形,我上一次在真实项目里看到有人正确使用空心菱形,是2017年一个从IBM出来的老哥,那是我唯一一次见。大部分团队的实际做法是——全部画成关联线,不标箭头。你说这不规范?是不规范,但它能跑通,而且没人误解。
三、我的「三图原则」
我现在的做法很简单,一个模块最多三张图,多一张都要写理由:
第一张,类图,但只画接口层。 上限15个类,超过就拆模块。类图里只保留字段名和方法签名,不写getter/setter(这玩意儿占了类图60%的面积,信息量为零)。字段类型如果一眼能看出来(比如status),不写类型。
第二张,时序图,只画异常路径。 正常流程代码本身就能读懂,不需要图。真正需要图的是「支付回调超时了会怎样」「库存扣减失败要不要回滚」这种。我画时序图的判断标准是:如果这段逻辑我口头讲需要超过3分钟,就画;3分钟能讲完,不画。
第三张,状态机图,只在状态超过4个的时候画。 一个订单如果只有「待支付/已支付/已取消」三个状态,画图纯属浪费;一旦变成「待支付/支付中/已支付/部分退款/全额退款/已关闭/超时关闭」七个状态,不画图必出bug,这个我有血泪教训——2021年一个退款状态机漏了「部分退款后再次退款」的路径,线上多了十几笔错账。
这三张图加起来,一个中等模块大概40到80行PlantUML代码,渲染出来一张A4能印下。
四、工具横评,这块我踩的坑最多
| 工具 | 上手成本 | 能否Git diff | 价格(我印象中的) | 适合谁 |
|---|---|---|---|---|
| PlantUML | 中,要装Java | 能,纯文本 | 免费 | 后端、写文档的人 |
| Mermaid | 低 | 能,纯文本 | 免费 | 前端、写Markdown的人 |
| draw.io | 极低 | 不能,除非存xml | 免费,桌面版也免费 | 临时画一张发给别人 |
| StarUML | 低 | 不能 | 3.x之后转订阅了 | 学生交作业 |
| Sparx EA | 极高 | 不能 | Professional版印象里三百美元上下 | 航空、军工那种要过审计的 |
我的实际组合是:日常用VS Code + PlantUML插件,快速画个图贴群里用draw.io网页版,别的不碰。draw.io有个隐藏好处是它能直接打开别人发来的vsdx,不用装Visio。
五、PlantUML 5分钟上手(真·5分钟)
步骤我按最小可运行来写,不废话:
- 装JDK,8以上就行,
java -version能看到版本号。PlantUML 1.2024.x 要求Java 8+。 - VS Code装插件「PlantUML」,作者是jebbs,装完重启一下。
- 建议顺手装Graphviz(Windows下是graphviz-12.x的msi),不装也能渲染,但类图布局会难看,箭头会绕圈。
- 新建一个
order.puml,粘下面这段:
@startuml
skinparam classAttributeIconSize 0
interface OrderService {
+createOrder(userId: Long, skuId: Long): Long
+cancelOrder(orderId: Long): Boolean
}
class OrderServiceImpl {
-inventoryClient
-paymentClient
+createOrder(userId, skuId): Long
}
OrderService <|.. OrderServiceImpl
OrderServiceImpl --> InventoryClient : 扣减库存
OrderServiceImpl --> PaymentClient : 预支付
@enduml
- 按 Alt+D 预览,右边出图。要导出PNG就 Ctrl+Shift+P 搜
PlantUML: Export Current Diagram。
一张15个类的类图渲染大概一两秒,我MacBook M1上实测基本瞬开。这段代码丢进Git,别人改了哪个字段,git diff 一行就能看出来——这是图片格式永远做不到的事。
六、7个高频问题和坑
Q1:组合和聚合到底怎么分? 说实话,除了面试,我不建议你花时间在这上面。真要用,记住一句话:整体没了部件还能活,是聚合;不能活,是组合。但实际项目里我建议你全画关联线,把生命周期的判断写到旁边注释里,比一个菱形清楚十倍。
Q2:时序图箭头实线虚线傻傻分不清? 同步调用是实心箭头,返回是虚线空心箭头,异步是开放箭头。记不住就记:有返回值的是虚线。
Q3:Mermaid能替代PlantUML吗? 类图不行,Mermaid的类图不支持嵌套分组,复杂继承关系画出来一团糟;时序图可以,而且GitHub、GitLab原生渲染,不用装任何东西。我的分工是:时序图用Mermaid,类图和状态机用PlantUML。
Q4:图会过时怎么办? 会过时,一定会。我的做法是在图的顶部写一行 最后更新: 2024-05-xx,然后每季度删一次,超过6个月没人动的图直接删掉。别心疼,烂图比没图危害大。
Q5:要不要画中文? 画中文。我见过太多团队用英文类名画图,结果新人看着 OrderAggregateRoot 一脸懵。UML规范不禁止中文,PlantUML对中文支持也没问题,唯一注意是别用生僻字,导出PDF偶尔会变方块。
Q6:图要进代码仓库还是放Wiki? 进仓库。放Wiki的图99%会烂,因为改代码的人不会去Wiki同步。放仓库虽然会让PR多几个文件,但至少改代码的那个人顺手就改了。
Q7:老板要全套设计文档怎么办? 给他三张图加一段文字说明,比37张JPG有用。如果非要37张,那就先画三张,剩下的慢慢补——反正最后也没人看,这话我说的。
七、最后
图的生命周期比代码短得多,这是我这几年最真切的感受。代码可以活五年,图一般活三个月。所以画图的目标不是「画得全」,而是「在它烂掉之前,把该传递的信息传递到位」。
我现在画图前会问自己一句:这张图三个月后还有谁会看?如果答案是「没人」,那我就画在白板上,拍张照发群里,聊完擦掉。真实一点说,白板照片的使用率,比我那37张JPG高多了。