前阵子接手一摊旧系统代码倒还好说最让人头疼的是文档——接口关系全靠文字描述模块边界要靠读代码才敢确认。项目组里新来的同事看了一周文档开会时还是把消息队列的方向画反了。我那时候就意识到diagram-design这件事看起来只是画图实际上是在帮团队把脑子里那团浆糊重新梳理成大家都能看懂的共识。这篇文章不聊虚的就讲讲我从零搭建一套可复用架构图设计工作流的完整过程包括工具选型、设计规范、自动化生成以及几轮实测之后踩出来的坑。1. 图不是画出来的是设计出来的很多人一听到画架构图第一反应是打开绘图软件拖几个框连上线加个颜色就算完事。但真正做过几个跨系统项目之后你会发现图和图之间的差距往往不在美术功底而在设计逻辑。1.1 从需求推倒出来的图表品类动手之前先回答一个问题这张图给谁看用来做什么我梳理过手上项目的真实需求最后归成三类。第一类是系统架构图。面向新成员和技术评审回答的问题是这个系统由哪些模块组成、模块之间什么关系。这类图的核心价值是准确不能为了美观把调用链隐藏起来。第二类是时序图。面向联调和排障回答的是一次完整请求经过哪些服务、各自做了什么。这类图的核心价值是顺序消息走错一步整个图就失去意义。第三类是部署拓扑图。面向运维和上线评审回答的是服务和中间件分布在哪些环境、网络怎么打通。这类图的核心价值是真实所有节点必须和环境一一对应。需求决定了终点终点反推工具选型。如果只是自己临时用用在线工具随便挑一个就行但如果要沉淀成团队资产、进文档系统、还能跟着代码一起版本化那选择范围就窄了很多。1.2 一个反直觉的结论手绘往往比工具更高效在确定正式方案之前我做过一次对比实验。拿同一个模块的调用链分别用在线绘图工具和手绘白板来表达。结果是手绘花了7分钟在线工具花了23分钟。原因不复杂在线工具拖着拽着容易陷入细节调整——对齐、配色、字号这些操作在思路还没成型的时候全是噪音。而手绘阶段只需要定三个东西边界、节点、方向。所以我搭的工作流是两段式第一段用纸笔或白板把结构画出来拍照存档第二段才把确认过的结构放进工具里精修。这个习惯一直保留到现在带来的最大好处是评审会上大家讨论的是逻辑而不是线的粗细。2. 工具选型对比为什么我用代码画图而不是鼠标画图市面上能画架构图的工具大致分两类图形化拖拽和声明式代码。我最终选了后者这不是因为前者不好而是因为我的使用场景里有一个硬指标——图必须能进版本控制。2.1 图形化工具和代码化工具的真实差异图形化工具的优势是上手快所见即所得临时改个框、挪个位置非常方便。但它在三个场景里让我很难受多人协作时谁改了什么凭感觉回退几乎不可能图一旦复杂图层管理就是灾难一个方块被另一个方块盖住是常有的事从文档系统迁移到另一个平台时导出格式经常错位重画成本太高。代码化工具正好反过来。学习曲线陡一点但一旦写熟图就是文本文本就能diff、能code review、能跟着代码库走。2.2 我对三种文本化方案的实测感受我分别试了PlantUML、Graphviz和D2各有各的脾气。PlantUML最老牌也最成熟关键词最好记类图、时序图、用例图都有一套专门语法。它的时序图在表达异步消息时非常顺手我项目中80%的时序图都用它。缺点是引擎渲染偶尔会抽风布局不合理时调整成本高。Graphviz擅长复杂拓扑关系而且有强大的布局算法节点特别多的时候反而比人手工排得整齐。代价是代码可读性差语法偏底层画流程图不如PlantUML直观。D2是后起之秀语法设计得很现代写起来是一种享受官方文档也漂亮。我用它画过几张部署拓扑图效果也满意。但团队里用的人少文件交给别人接力时对方还得先学语法。所以我的结论是按需混用比绑定一个工具强。跨模块的架构图用PlantUML复杂网络关系用Graphviz部署拓扑用D2三个工具通过同一条命令统一渲染成SVG。3. 可复用的图表设计规范比画图本身值钱画图工具定下来之后下一个问题是怎么样让不同人画的图看起来像一个项目组的作品这里说的看起来像不只是配色统一而是信息的编排方式一致。看过太多技术图第一眼看配色很舒服但仔细一看——箭头方向错了、层级线穿过了标题、图例和实际颜色对不上。这些问题的根源都是缺少设计规范。3.1 版式、配色、字体三项基础约定我根据自己踩过的坑定了一份内部规范核心条目如下。颜色方面我选了12色基础板。不是12种颜色随便用而是定义了语义数据存储一律用冷色调计算服务用暖色调外部系统用灰色系异常路径用红色描边。这样一张图扫过去观众第一眼就能凭颜色判断哪些是存储、哪些是计算不需要逐个读标签。字体方面中文一律用无衬线字体字号分三档图标题16号、节点名12号、注释文字10号。比字号更重要的是字间距——节点内文字如果超过长度限制就换行而不是缩小字号缩小字号的结果是每次投影都要眯眼睛。布局方面消息流向统一从左到右跨层依赖必须画虚线回边。这个约定极其重要它让看图人形成一个阅读惯性不用每次从头找起点。3.2 图层、命名和版本管理的设计代码化制图有个隐藏优势——命名规范可以强制执行。我给每个节点制定了统一的ID规则{系统代号}-{模块名}-{功能名}。比如订单系统的库存扣减节点ID就是ordr-inv-deduct。这个ID不只是图片上的标签它会同步出现在依赖列表和监控告警里排查问题时候能快速对应上。版本管理上图和代码走同一个仓库但单独放一层目录。我习惯在目录下维护一个README记录每张图的演进历史和关键决策。比如某张图从订单直连库存改成通过MQ解耦在README里写清楚原因是降低峰值耦合后来的人看历史就一目了然。4. 从结构草图到成品图半自动化的生成管线有了规范和工具剩下的问题就是效率。一张架构图如果每改一次业务逻辑就要重画一次团队很快就会放弃维护。我把生成流程做成了半自动化管线改图变成了改配置文件。4.1 用元数据驱动的图数据模型我抽了一张架构图背后的元数据建立了两个概念节点和关系。节点描述有什么包含字段ID、类型、是否内部、所属层。关系描述怎么连包含字段源节点、目标节点、协议、是否异步、方向。有了这套元数据任何一张图都可以被抽象成一张表。这意味着我可以用Java写个小工具扫描项目配置里的服务注册信息自动生成节点清单再根据接口定义自动生成调用关系。人工只需要校对和补充那些动态的部分比如定时任务、人工操作。这套做法的直接收益是系统里新增一个微服务并注册到配置中心后下一次构建架构图就自动出现这个服务节点。整个团队再也不用担心架构图过期。4.2 构建脚本和产物输出管线用ShellJava的组合完成。Shell负责编排流程、拉取配置文件、调用渲染命令Java负责解析元数据并输出PlantUML/D2的代码片段。举个例子一份服务清单的YAML片段长这样services: - id: ordr-svc name: 订单服务 type: internal-service layer: application dependencies: - target: inv-svc protocol: mq direction: async - id: inv-svc name: 库存服务 type: internal-service layer: application工具读入这份清单自动拼出PlantUML的component定义和关系连线再调用渲染引擎输出SVG和PNG。整个过程不到10秒流程图就能更新到最新。4.3 不想写代码的替代思路如果你不想维护一套自研工具也有低配方案用静态站点生成器管理图文档把每张图的源代码和渲染图放在一起配合Git钩子push之后自动触发渲染。我见过有团队直接用CI流水线文档仓库收到更新后构建器批量渲染所有PlantUML文件然后在文档站上展示。这套方案不需要写Java解析器但对文件命名和目录结构要求更严格否则时间长了目录会乱。5. 让AI参与画图大模型时代的新工作流大模型流行之后我最先试的场景就是把自然语言描述直接转换成图表源码。这一步比想象中要成熟得多但还是有几个细节需要注意。5.1 自然语言转PlantUML的可行性和陷阱我实测过把一段系统包含A、B、C三个服务A通过MQ异步调用BB通过HTTP同步调用C的描述丢给大模型它能直接输出可渲染的PlantUML代码格式基本正确。但一旦描述里出现模糊词汇比如间接依赖偶尔调用部分数据模型就很容易画出与实际不符的线型。我的对策是在提示词里显式声明语法规则把线型定义成封闭枚举不允许它自由发挥。我常年在提示词里加这样一段约束只有明确标注异步的关系才使用虚线箭头只有跨网段的调用才标注协议名称节点类型必须从枚举值中选不得自创新类型5.2 用AI做图表审查比生成更靠谱这是我实测下来意外收获——让AI去挑图的毛病比让它纯凭空生成图更可靠。方法是把PlantUML源码和我的设计规范一起给模型让它按照规范逐条检查配色是否符合语义、连线方向是否一致、图例是否存在、有没有悬空节点。模型做这种找茬任务相当稳定经常能揪出人眼忽略的问题。比如有一次模型指出某条回边画成了同步而不是异步我核对代码确实漏了箭头标记。这种错误的代价在文档评审时不大但落到排障时会引起误判。5.3 我的AI辅助流程图模板最后分享一个我常用的模板结合了结构化提取和代码生成两个环节。第一轮让AI从一段长文本中提取参与者、动作、顺序、分支条件输出为JSON。第二轮把JSON转换成PlantUML时序图代码。两轮拆分的好处是提取结果可以复用——同一份JSON既能生成时序图也能生成一份文字概要还能生成状态表。6. 多场景复用的实践从代码文档到评审汇报图一旦沉淀下来复用的场景远超我的预期。它不只是文档里的一张插图而是能直接作为各类协作的输入物料。6.1 在代码审查和接口文档中的应用我在接口文档里嵌入了自动生成的时序图每条核心链路的调用顺序都配上图。新同事联调时不需要翻代码先看图再按图索骥找具体模块上手速度明显快了。代码审查环节我也改了习惯不再用纯文字描述改动影响面而是贴一张改动前和改动后的架构对比图。评审者对着两张图看差异一眼就知道哪些模块引入了新的依赖哪些调用链被整体绕开了。6.2 评审会上如何用图控制节奏这套工作流跑通之后我发现图还有一种微妙的价值它能控制会议的节奏和经验值落差。技术评审最怕的是大家各说各话但有了统一标准的图讨论自然会被拉到同一个频道上。我会在评审材料首页放一张全链路架构图第二页开始才放局部的详细图。这个顺序默认了先整体后局部的决策路径避免一开始就陷入某个细节的争论。6.3 从系统图到领域模型的边界一个常见的误区是架构图画得越来越细细到最后和代码逐行一样。这恰恰违背了图的本质。我在实践中立了一条规则架构图只保留跨模块的信息模块内部的实现细节一律不进入架构图而是进入模块自己的页面。否则图会庞大到没人愿意打开。这条边界守住的直接结果是架构图的更新频率明显下降了从每周改变成按迭代改反而维护的动力更足。7. 实测阶段的踩坑记录与排查思路讲完了方法必须讲讲翻过车的那些时刻。这套流程不是一次就顺的中间踩了几个不大不小的坑有些至今还留着防御措施。7.1 渲染引擎和流程图字体不兼容第一次在CI里自动出图PNG里的中文字符全部变成了方块。排查过程走了不少弯路先怀疑编码问题改了UTF-8还是没变后来怀疑系统缺字体装了中文字体之后重新渲染才正常。这条路线的经验是代码化渲染环境和本地环境往往是两套字体库CI镜像里必须显式安装中文字体否则一切编码努力都是白费。7.2 布局爆炸的根因不是节点太多有张部署拓扑图一开始渲染出来密密麻麻节点之间的线完全交叉成蜘蛛网。第一反应是工具布局算法不行换了Graphviz还是不行后来发现是元数据里有重复的边——同一个关系被同时建模成同步调用和异步事件渲染就画了两条线。删掉冗余关系之后布局立刻清爽。这个问题非常有代表性大多数图太乱的问题根因不是绘图能力而是数据模型里的脏数据。7.3 避免维护疲劳的操作细则最后一条经验是心态层面的。图要活得久维护成本必须降到你几乎感觉不到不然一定会过期。我验证过的原则是不追求一张图画全所有系统而是每个系统都有自己的局部图全貌图只保留到子系统级别。这样任何一次变更最多只影响一两张局部图整个更新负担在一个可控范围。还有一条细则每次变更提交时图和代码一起进同一个Pull Requestreview过程中强制检查图是否同步更新。把图过期变成代码合并不通过的风险团队执行起来基本不会漏。从画图到设计图再到自动生成图这条路我走了三轮迭代。回头看最值钱的不是最终那张精美的架构图而是中间沉淀下来的那套规范化、自动化的思维框架。项目还在往前演进这套图体系也跟着代码库一起长。最近新来的同学已经能在一周内上手画局部图了比起当初那个对着空白画布发愁的时候算是迈出了挺大一步。