YAOTU INSIGHTS

如何绘制不烂的架构图:diagram-design 规范全解析

如何绘制不烂的架构图:diagram-design 规范全解析
我接手某团队文档库的时候diagrams 目录底下躺着十几版“最终架构图”最新那几张里方框大小全凭当初手抖的程度箭头从右上角绕到左下角红蓝绿混成一锅路过的每个人都会顺手改两笔结果谁也不知道哪张才是对的。所以那段时间我专门整理了一套制图约定并维护为一个代号 diagram-design 的项目。它不是高深框架而是一整套从“选图、布线、着色、命名、维护”到“让图能持续更新而不烂掉”的实操规范。这篇文章会围绕这套 diagram-design 规范展开讲清楚六类常用 diagram 的适用边界、四个层面的视觉约束、图即代码的落地方式以及一个订单处理系统的完整走查案例。如果你受够了同事丢过来的“最终版v9”或者想把架构图画成能评审、能复用、能演进的东西这篇文章应该对你有用。1. 烂图的代价为什么我决定给制图立规矩1.1 典型烂图到底烂在哪先说最常见的烂法。我曾见过一张命名为 final_v9.drawio 的架构图整张图没有任何对齐线方框有的占半屏有的挤在角落同一个组件在图上出现了三次大小还不一样。更麻烦的是没有方向约定有的模块从左往右连有的从下往上连箭头贴着边框走过两个弯之后完全看不出指向谁。还可以再补几刀颜色没有语义红色画正常链路红色也画异常告警边框线粗细不统一虚线实线混用图里嵌着七八个接口名但至少三个已经改版没有图例没有版本号没有绘制日期。作者脑子里可能有一张完整蓝图但读者只能靠猜猜错了还不能怪图因为图本身就是一团乱麻。这种图的根因往往不是画图能力差而是没把图当工程产物来管理。随手拖框、随手连线、随手填色最后交付的只是一个“看起来像架构图”的图片而不是一个能传递准确信息的沟通载体。1.2 烂图如何拖垮整个文档生态一张烂图不是一个人难受而是连锁反应。新同事拿着旧图做系统 onboarding以为服务 A 是调服务 B 的结果代码里真实链路正好相反评审会上大家对着图讨论方案讨论到一半才发现讨论的这张图本身画错了半年后图过时了没人去更新于是所有人达成一个默契别看图看代码。我印象很深的一次是模拟项目 X 的联调阶段A 同学按旧图里的“校验中心”实现了一段假想逻辑结果真实链路里根本没有这个中间层。多写一个模块倒是小事关键是排查了整整一天最后才发现是图骗了人。那个夜晚之后我就决心把制图这件事标准化。烂图本质上是一种技术债它不像代码债务那么显性但会在每次查阅文档时重复收取理解税。只要团队超过三个人这种税就会变得非常可观。2. 选图先于画图六类常用 diagram 的适用边界画图之前先问一个问题你真正想表达的是什么是结构是顺序是决策分支是对象状态是数据关系还是物理位置。选错图后面怎么布线都会别扭选对图信息结构就成功了一半。这也是 diagram-design 里最先被写下来的原则选图优先于画图。2.1 架构分层图给系统拍一张全景照架构分层图回答的是“系统由哪些模块组成、模块之间怎么依赖”。它最典型的形态是自上而下分层接入层、业务层、数据层、外部依赖。画这种图时我要求依赖箭头只能从上往下指如果出现下层反向指向上层的箭头要么是分层设计有毛病要么是这张图画错了。很多团队把架构分层图当装饰画恨不得把所有服务都堆进去。实际上一张图只需要主干模块和关键依赖虚线框里的次要组件可以用“省略区域”表达。架构分层图不适合表达一次调用的完整时序那种需求请交给时序图。2.2 时序图把调用关系讲成时间线时序图回答的是“一次交互按什么顺序发生”。它特别适合跨服务调用链、异步回调、分布式事务、登录鉴权这类场景。画时序图的核心规矩是泳道从上到下的顺序代表时间推进消息从左到右只是空间安排不要为了让线条不交叉而随意调整泳道顺序否则时间线就乱了。时序图里的消息一定要编号。没有编号的时序图讨论“第几步超时了”时只能说“中间那步”沟通效率极差。另外异步消息和同步调用要用不同的箭头样式并且必须在图例里写清楚别让读者猜。2.3 流程图与状态图最容易混用的两种流程图和状态图名字相近长相也相近但表达的逻辑完全不同。流程图关注“一个任务从前到后经过了哪些处理和判断”比如下单流程创建订单、校验库存、支付、发货遇到库存不足就返回异常状态图关注“一个对象在哪些状态之间迁移”比如订单状态待支付、已支付、已发货、已完成、已取消。混用这两种图会画出一张四不像判断分支混着状态迁移矩形里写着“已支付”这种状态名又画了个菱形判断“是否支付成功”。我建议的做法是要表达处理过程用流程图要表达对象生命周期用状态图如果两者都重要画两张图而不是硬塞成一张。2.4 数据关系与部署拓扑ER 图和部署图的分工ER 图回答“数据实体之间有什么关系”用于数据库表设计、接口数据模型梳理。它关注实体、主外键、一对多或多对多关系画的时候别把“用户下单”这种动作画进去那是时序图的职责。部署图回答“系统跑在哪些节点上、网络边界怎么划分”。它需要表达物理节点、容器实例、网络区域以及节点间使用的协议端口。最常见的错误是把部署图画成逻辑组件图只看到微服务框却看不到任何关于环境、网段、端口的部署信息。记住部署图的读者是运维和联调同事不是只会看组件图的负责人。下面这张表是我内部培训时常用的速查表图类型核心问题推荐场景不推荐场景架构分层图系统由哪些模块组成、如何依赖模块划分、架构评审、系统概览描述单次调用的完整细节时序图交互按什么顺序发生跨服务调用、异步回调、分布式链路表达模块静态依赖关系流程图任务经过哪些处理和判断业务处理流程、功能逻辑梳理描述对象生命周期状态图对象在哪些状态之间迁移订单状态机、任务状态流转描述复杂分支处理ER 图数据实体及其关系数据库设计、数据模型评审表达运行时调用顺序部署图系统部署在哪些节点、网络边界在哪环境构建、联调排障、运维交接表达业务逻辑分支3. 四个层面的视觉与结构约定diagram-design 的核心规范选对图类型只是第一步同一类图不同人画出来可能是天壤之别。diagram-design 接下来要解决的就是“怎么画才统一”。我把约定拆成四个层面布局方向、颜色语义、命名标注、复杂度阈值。这四个层面都在回答一个问题如何让读者不费脑子地看懂你的图。3.1 布局方向与层级节奏让视线自动走对路我强制要求所有图优先采用自顶向下的布局特殊情况比如宽度远大于高度才允许自左向右但一张图里绝对不能混用两种方向。原因很简单人的扫读习惯是先上后下、先左后右方向统一后读者看到中部的内容就知道它是“中间层”不需要额外理解。同层节点必须基线对齐节点间纵向留白保持固定值。很多烂图的问题就是上下错落一眼看去像被风吹过。另外主链路尽量保持在图的中轴附近异常分支和次要路径靠边放这样读者先看到主干再关心细节。3.2 颜色语义低成本建立视觉编码颜色最忌讳的是“全凭心情”。我建议每套图维护一个有限的语义色板每种颜色只代表一种含义。例如颜色语义蓝色系统内部组件绿色外部依赖或第三方服务橙色数据存储红色异常路径或补偿逻辑灰色省略区域或非重点模块同时每个色板控制在 6 种颜色以内不要引入第 7 种“临时色”。还有一条容易被忽视颜色不能作为唯一信息载体因为打印成黑白图或遇到色盲读者时信息会丢失。所以即使某个组件涂了绿色文字上也要写清楚“外部依赖”而不是让人靠颜色去猜。3.3 命名、编号与标注让图能脱离正文独立阅读节点命名统一采用“名词短语 编号”的格式比如“订单服务S-01”、“支付回调队列Q-03”。编号的意义在于跨图引用时能明确指向同一个对象避免叫“订单”的节点在两张图里含义不一致。箭头必须带动词标注例如“调用”、“异步通知”、“写入”、“读取”。没有动词标注的箭头一律视为不合格图。箭头上的文字要短超过六个字就说明这条依赖太复杂可能需要拆图。每张图必须包含图例、版本号和生成日期版本号建议跟随文档仓库的提交版本方便回溯。3.4 复杂度阈值什么时候必须拆图决定一张图是否合格最简单的标准是数节点。我给出的硬性建议是单图节点数不超过 15 个图层级不超过 3 层。超过就得拆。为什么定这个数因为人的工作记忆容量有限一次性要记住 30 个节点的位置和关系大脑会直接放弃理解只留下“好复杂”的印象。拆图的思路是找天然边界按子系统拆按链路拆按层级拆。比如“订单系统整体架构图”拆成“订单创建链路图”和“订单状态迁移图”每一张都保持 15 个节点以内整体信息量反而更大。别指望一张图讲完所有事那不是图那是藏宝图。4. 让图活起来图即代码的落地路径与工具取舍规范定得再好如果工具不支持版本管理很快又会回到“导出图片发群里”的老路。所以这一章聊落地为什么要把图写进文本里工具链怎么选以及怎么让图在项目生命周期里持续维护而不是画完就变成僵尸图。4.1 为什么把图写进文本里传统拖拽式画图工具的最大问题是产物是二进制文件或私有格式Git diff 基本不可读。两个版本之间改了哪里只能靠人眼对比导出图评审效率极低。而把图以文本形式编写后diff 会变成一行行的文本变更评审者直接就能看出来“这里加了一个节点”“那里改了一条箭头”。文本化还有几个额外好处可以用 grep 查找节点名可以在多个图之间复制片段可以通过脚本批量检查规范比如节点数是否超限、箭头是否都有标注。缺点也有比如自由排版能力弱、装饰效果有限但对于架构图这种以信息传递为核心的场景这些牺牲完全值得。4.2 工具链选型三位主流选手的取舍目前最主流的“图即代码”方案有几个方向我按团队画像给建议。如果团队已经重度依赖 Markdown 文档站优先考虑 Mermaid它渲染结果干净和主流文档工具集成度高如果团队经常画时序图、状态机并且能接受安装独立渲染器PlantUML 的时序图表达力更强如果画依赖关系图、网络拓扑这类自动布局要求高的图Graphviz 的 DOT 语言值得投入学习成本。三者对比大致如下维度PlantUMLMermaidGraphviz (DOT)学习成本中低中高时序图表现较强够用一般Markdown 集成需插件原生友好需插件自动布局有限有限强适合团队Java 背景、重时序图文档站、轻量图为主复杂网络结构补充一个容易忽略的实践不要只提交源文件。建议在持续集成中把文本图渲染成 SVG 或 PNG作为构建产物归档。这样既保留源文件的版本可追溯性又让不看源文件的人能直接打开图片。4.3 生命周期管理评审、版本与回收图即代码落地之后还要把图纳入常规工程流程。首先每张图必须有明确的 owner通常是该模块的负责人。图跟着代码走放在对应模块的目录下而不是长期散落在文档库深处的某个共享文件夹里。其次把“改接口必须改图”写进团队约定代码评审时顺带看关联图发现图没跟上评论区和代码评论一样留“需要更新”的标记。最后是回收机制。很多团队的文档库里躺着大量早已失效的图因为没人敢删。我的建议是保留“归档”目录每季度或每个里程碑统一处理一次还在服务的模块图移到当前文档目录已下线模块的图压缩打包进 archive。这样当前文档永远只保留能用的图新人不至于在垃圾堆里找路。5. 一个订单处理系统 diagram 的完整走查过程规范讲再多不如完整走一遍。下面用一个简化的订单处理系统演示流程涉及网关、订单服务、支付回调、库存扣减和补偿任务。真实系统通常比这复杂但演示的重点在于方法而不是系统本身。5.1 需求边界收敛第一版只画四件事第一次画图最容易犯的错是把所有未来可能要加的功能都塞进来。当时我定义第一版只画四件事下单主链路、支付回调链路、库存扣减、失败补偿。目标读者是参与联调的五个同事他们当时只关心这些链路怎么串起来的。所以第一步不是打开画图工具而是列节点清单网关、订单服务、支付网关外部、库存服务、订单数据库、补偿任务。列完清单之后你会发现图大约七八个节点完全低于 15 个节点的复杂度阈值根本不需要拆图。等评审通过后再把每个链路的细节放到子图里这是最稳妥的节奏。5.2 从凌乱草稿到规范布局的两轮迭代第一轮草稿很典型所有节点排成一行订单服务在左边数据库在中间支付网关在右边箭头从数据库指回订单服务整张图横跨两屏。第一轮草稿不是不能用而是阅读成本太高。第二轮按照规范重排自顶向下分四层接入层放网关业务层放订单服务和补偿任务数据层放订单数据库外部依赖层放支付网关主链路居中异常路径靠右箭头全部标上动词。重排后信息量没变但结构清晰了很多。迭代过程中我还会做一个小动作给图里的每个箭头编号然后在图下方用文字列出编号对应的时序说明。这样有人问“第三步挂了怎么办”就能直接说“看箭头 3 的补充分支”讨论效率非常高。5.3 发布前的十项审查清单每次画完图我会用这份清单自查你也可以直接抄去当团队图的标准所有节点都对齐在统一的方向流上没有出现跨方向连线。主链路清晰一眼能看出核心路径。节点命名符合“名词短语 编号”没有裸单词。箭头全部带有动词标注数量不超过六个字。颜色不超过六种并且与图例完全对应。节点数不超过 15 个层级不超过三层。图例、版本号、生成日期都在图内。跨图引用的节点名称和编号一致。异常路径和补偿逻辑有单独的颜色或标注不淹没在主链路里。导出的是矢量格式放大之后依旧清晰。只要有一项不满足我就把图退回修改而不是让它带着小毛病进入文档。这套流程执行下来团队里的图质量有了明显变化至少“final_v9”这种名字再也没有出现过。最后再说一点个人经验。规则本身不值钱值钱的是把它嵌进日常工作流每次画图都当代码提交评审挑图和挑代码一样不留情面每次发现图与代码不一致第一时间修图而不是记在“以后再说”的备忘录里。diagram-design 这套约定本身并不复杂真正让它起作用的是所有参与者愿意遵守它。