1. 从“diagram-design”这个标题说起:它到底在解决什么问题
第一次看到“diagram-design”这个标题,很多人会下意识觉得它是个画图工具,或者某个前端组件库。但如果你真正做过系统设计、写过技术方案、画过架构图,就会明白这个标题背后藏着一个非常具体的痛点:图不是画不出来,而是画出来之后没人看得懂、改不动、传不下去。
我见过太多团队在方案评审会上,对着一张密密麻麻的架构图争论半小时,最后发现大家理解的模块边界根本不一样。问题不在技术本身,而在于图的设计从一开始就没有遵循一套可复用的规则。diagram-design 这个主题,本质上要解决的是“如何让图成为一种可维护、可沟通、可演进的工程产物”,而不是一次性的美术作业。
它适合三类人:第一类是经常需要输出架构图、流程图、时序图的后端或全栈工程师;第二类是需要用图来对齐需求的产品经理和项目经理;第三类是对可视化表达有要求的技术写作者。不管你是哪一类,只要你的工作里出现过“这张图我改了三版还是被吐槽”的情况,这篇内容就值得往下看。
接下来的内容,我会从图的设计原则、工具选型的底层逻辑、具体绘制流程、常见翻车场景以及团队协作中的图管理这几个维度展开。所有内容都基于实际项目中的反复试错,不是教科书式的理论罗列。
2. 图的设计原则:为什么“好看”从来不是第一优先级
2.1 可读性优先于美观性
很多人画图的第一反应是打开工具,挑一个最顺眼的模板,然后往里填内容。这个顺序本身就是错的。图的第一使命是传递信息,不是参加设计比赛。我见过一张用了六种渐变色、每个节点都带阴影的微服务架构图,结果评审时所有人都在问“这个紫色框和蓝色框有什么区别”,而不是讨论服务拆分是否合理。
可读性的核心只有三条:层级清晰、连线不交叉、标注不歧义。层级清晰意味着你要用视觉权重来区分主次,比如核心服务用实线粗框,辅助组件用虚线细框,外部依赖用灰色填充。连线不交叉要求你在布局阶段就规划好节点位置,而不是画完再调整。标注不歧义则意味着每个箭头都要有明确的语义,是数据流、控制流还是依赖关系,必须统一。
一个实用的检验方法是:把图缩小到50%大小,如果还能看清主要模块和流向,说明可读性达标;如果缩完之后变成一团色块,那就需要重新设计。
2.2 一致性比创意更重要
在一个项目里,图的风格必须统一。这不是审美问题,而是认知成本问题。如果第一张图用圆角矩形表示服务,第二张图用圆柱体表示数据库,第三张图又用菱形表示网关,读者每次都要重新建立映射关系,效率极低。
我通常会在项目初期定义一个简单的“图元规范”,类似这样:
| 图元形状 | 含义 | 使用场景 |
|---|---|---|
| 圆角矩形 | 业务服务 | 微服务、模块、应用 |
| 圆柱体 | 数据存储 | 数据库、缓存、消息队列 |
| 菱形 | 网关/代理 | API Gateway、负载均衡 |
| 虚线框 | 外部系统 | 第三方服务、遗留系统 |
| 实线箭头 | 同步调用 | HTTP、RPC |
| 虚线箭头 | 异步消息 | MQ、事件通知 |
这个规范不需要多复杂,但一旦定下来,所有图都必须遵守。新人加入时,看一眼规范就能读懂图,而不是靠口口相传。
2.3 图的“生命周期”意识
大部分人对图的理解是“画完就完了”,但实际项目中,图是会变的。服务拆分调整了,图要改;数据库换了个类型,图要改;甚至团队换了个负责人,图也要改。如果一开始画图时没有考虑可维护性,后面每次修改都是一场灾难。
我踩过最深的坑是:用某个在线工具画了一张很漂亮的架构图,结果半年后要改的时候,发现那个工具的免费版已经不能编辑了,导出源文件还要付费。最后只能对着截图重新画一遍,浪费了大半天。
所以,图的源文件必须掌握在自己手里,且格式要通用。优先选择基于文本的描述方式(如 PlantUML、Mermaid),其次选择支持导出标准格式(如 SVG、Draw.io 的 XML)的工具。纯图片格式(PNG、JPG)只能作为最终交付物,不能作为唯一存档。
3. 工具选型的底层逻辑:别被“免费”和“好看”带偏
3.1 文本驱动 vs 拖拽式:两种路线的取舍
画图工具大致分两类:文本驱动型和拖拽式。文本驱动型以 PlantUML、Mermaid、Graphviz 为代表,你写代码,工具生成图。拖拽式以 Draw.io、ProcessOn、Figma 为代表,你手动摆放节点和连线。
文本驱动的优势非常明显:版本可控、 diff 友好、批量修改方便。比如你要把架构图中所有的“MySQL”改成“PostgreSQL”,文本驱动只需要全局替换一个词,拖拽式可能要手动改十几个节点。而且文本文件可以直接放进 Git 仓库,每次修改都有记录,谁改的、改了什么一目了然。
但文本驱动也有短板:布局不可控。自动布局算法有时候会把节点排得乱七八糟,连线绕来绕去。对于复杂的架构图,你可能需要花大量时间调整布局参数,甚至最后还是要手动微调。
拖拽式的优势是所见即所得,布局完全由你掌控,适合对视觉效果要求高的场景,比如对外汇报、产品宣传图。但缺点是版本管理困难,多人协作时容易冲突,而且文件格式往往是私有的。
我的建议是:内部技术图用文本驱动,对外汇报图用拖拽式。内部图追求准确和可维护,对外图追求美观和易读。两者不冲突,可以先用文本驱动画出逻辑,再导出到拖拽工具做视觉优化。
3.2 我实际用过的几类工具对比
下面这张表是我在多个项目中实际使用后的总结,不吹不黑:
| 工具类型 | 代表工具 | 适合场景 | 主要坑点 |
|---|---|---|---|
| 代码生成 | PlantUML | 时序图、类图、复杂架构 | 布局调整费时,中文支持需配置字体 |
| 代码生成 | Mermaid | 流程图、简单架构、Markdown集成 | 复杂图容易乱,样式定制有限 |
| 代码生成 | Graphviz | 依赖关系、网络拓扑 | DOT语言学习曲线陡,不适合交互图 |
| 拖拽式 | Draw.io | 通用架构图、流程图 | 免费版够用,但协作功能弱 |
| 拖拽式 | Figma | 高保真原型、对外展示 | 学习成本高,不适合快速画技术图 |
| 拖拽式 | 某在线白板 | 头脑风暴、草图 | 正式图不推荐,导出格式受限 |
重点说下 PlantUML 和 Mermaid 的选择。如果你的图需要嵌入 Markdown 文档,Mermaid 是首选,因为主流 Markdown 编辑器都原生支持。如果你要画复杂的时序图、状态图,PlantUML 的表达能力更强,但需要本地安装 Java 环境或者使用在线服务。
注意:无论选哪个工具,都要确认它支持导出 SVG 或 PNG,并且源文件格式是开放的。不要把自己的图锁在一个你无法控制的平台里。
3.3 为什么我不推荐“All in One”的大平台
有些团队喜欢用一个平台解决所有问题:画图、文档、项目管理、代码托管全在一起。听起来很美好,但实际用起来往往很痛苦。画图功能只是那个平台的一个小模块,更新慢、bug多、导出格式受限。而且一旦团队决定迁移,所有图都要重新画。
我的做法是:画图工具独立选,文档工具独立选,两者通过标准格式(SVG、PNG)衔接。这样任何一个工具出问题,都不会影响另一个。图源文件放在 Git 仓库里,和代码一起版本管理。文档平台只放最终导出的图片,方便阅读。
4. 从零画一张架构图的完整流程
4.1 先想清楚“这张图给谁看”
画图之前,先回答三个问题:读者是谁?他们关心什么?他们看完要做什么决策?
如果是给开发团队看的技术方案图,重点是模块边界、接口定义、数据流向。如果是给管理层看的汇报图,重点是系统整体结构、关键依赖、风险点。如果是给运维看的部署图,重点是节点分布、网络分区、监控点。
我见过一张图同时想满足这三类人,结果画了五层嵌套,每层都标注了密密麻麻的文字,最后谁都不满意。正确的做法是分层出图:一张高层概览图给管理层,一张模块交互图给开发,一张部署拓扑图给运维。每张图只讲一件事。
4.2 用“草稿-细化-定稿”三步法推进
第一步:草稿阶段。不要打开画图工具,先用纸笔或者白板把核心模块和关系画出来。这个阶段只关心逻辑对不对,不关心好不好看。我通常会用便利贴代表服务,用线代表调用关系,摆一摆、挪一挪,直到逻辑通顺。
第二步:细化阶段。把草稿搬到工具里,开始定义图元、统一命名、补充标注。这个阶段要确定每个节点的名称、每个箭头的语义、每个分组的边界。命名要具体,不要用“服务A”“模块B”这种占位符,直接用真实的服务名。
第三步:定稿阶段。调整布局、对齐节点、统一配色、检查连线。这个阶段可以花点时间在视觉上,但不要过度。一张图如果逻辑清晰,稍微丑一点也能接受;如果逻辑混乱,再好看也没用。
4.3 一个具体的 PlantUML 示例
假设我们要画一个简单的订单系统架构图,用 PlantUML 可以这样写:
@startuml skinparam componentStyle rectangle skinparam shadowing false actor "用户" as User component "API网关" as Gateway component "订单服务" as OrderService component "库存服务" as StockService database "订单库" as OrderDB database "库存库" as StockDB queue "消息队列" as MQ User --> Gateway : HTTPS Gateway --> OrderService : 创建订单 OrderService --> StockService : 扣减库存 OrderService --> OrderDB : 写入订单 StockService --> StockDB : 更新库存 OrderService --> MQ : 发送订单事件 @enduml这段代码生成的图,节点自动布局,连线清晰,而且可以直接放进 Git 管理。如果要改服务名,改一行代码就行。这就是文本驱动的优势。
当然,自动布局可能不够完美,你可以通过调整节点声明顺序、使用together分组、设置left to right direction等方式来优化。但总体来说,对于逻辑图,文本驱动足够用了。
5. 那些年我踩过的图设计坑
5.1 连线交叉:不是调整的问题,是布局的问题
刚开始画图时,遇到连线交叉,我的第一反应是手动拖拽节点,试图把线绕开。结果往往是按下一个葫芦起了两个瓢,这边不交叉了,那边又乱了。后来才明白,连线交叉的根源是节点布局不合理,而不是连线本身的问题。
正确的做法是:先确定核心节点,把它们放在图的中心区域;然后把相关节点按功能分组,放在核心节点周围;最后把边缘节点放在外围。这样连线自然就少了交叉。如果还是交叉,考虑把图拆成两张,而不是硬塞在一张图里。
5.2 命名混乱:同一个东西三个名字
这是团队协作中最常见的问题。数据库在A图里叫“订单库”,在B图里叫“OrderDB”,在C图里叫“订单数据库”。新人看到三张图,以为是三个不同的东西。
解决办法很简单:维护一个术语表。所有图里的节点名称必须从术语表里取,不允许自由发挥。术语表可以放在项目 Wiki 里,每次新增节点时先查一下有没有现成的名字。这个习惯一旦养成,图的沟通效率会大幅提升。
5.3 过度标注:图不是文档
有些人喜欢在图里写大段文字,每个节点下面都跟一段说明,每个箭头旁边都标注接口参数。结果图变得密密麻麻,根本没法看。
图的作用是展示结构和关系,细节应该放在文档里。节点名称保持简洁,箭头标注只写关键信息(如协议、方向),详细的接口定义、参数说明、异常处理放在配套文档中。图和文档配合使用,而不是让图承担所有信息。
5.4 忽略图例:读者不是你自己
你画图时知道实线代表同步调用,虚线代表异步消息,但读者不知道。如果没有图例,他们只能猜。猜错了,沟通就出问题。
图例不需要复杂,放在图的角落,用几行说明即可。关键是每张图都要有图例,哪怕你觉得“这么简单应该能看懂”。事实证明,你觉得简单的东西,别人不一定觉得简单。
6. 团队协作中的图管理:让图活起来
6.1 图源文件进 Git,和代码一起管理
这是我最想强调的一点。图不是一次性交付物,而是项目的长期资产。把图源文件(.puml、.drawio、.mmd)放进代码仓库,和代码一起提交、一起评审、一起版本管理。每次架构调整,图跟着代码一起改,保证图和代码始终一致。
具体做法是:在仓库里建一个docs/diagrams目录,存放所有图源文件。提交代码时,如果涉及架构变更,必须同时更新对应的图。Code Review 时,图和代码一起看。这样图就不会变成“历史遗留文件”,而是活的文档。
6.2 用 CI 自动生成图
如果用的是 PlantUML 或 Mermaid,可以配置 CI 流水线,在每次合并到主分支时自动生成图片,并发布到文档站点。这样开发人员只需要维护文本源文件,图片自动更新,不需要手动导出。
以 PlantUML 为例,可以在 CI 脚本里加一行:
plantuml -tsvg docs/diagrams/*.puml -o ../images/这样每次提交后,SVG 图片自动生成,文档站点引用最新的图片。开发人员不用关心图片怎么来的,只需要改文本。
6.3 图的评审要点
图也需要评审,但评审的重点不是“好不好看”,而是“逻辑对不对”。我通常关注这几个点:
- 模块边界是否清晰,有没有职责重叠
- 数据流向是否合理,有没有循环依赖
- 外部依赖是否标注,有没有遗漏
- 命名是否一致,有没有歧义
- 图例是否完整,读者能否独立理解
评审时让一个不熟悉该系统的同事来看图,如果他能在一分钟内说出系统的主要模块和交互关系,说明图的设计是成功的。
7. 进阶:让图成为沟通工具而不是交付物
7.1 用图来驱动设计讨论
最好的图不是画完之后用来汇报的,而是画的过程中用来讨论的。在方案设计阶段,把核心模块和关系画出来,团队成员围着图讨论,边讨论边改。图是讨论的媒介,而不是讨论的结果。
我习惯在技术方案评审前,先画一张草图发到群里,让大家提前看。评审会上直接对着图讲,有异议的地方当场改。这样评审效率高,而且大家对图的理解也一致。
7.2 图的“分层”策略
一个系统通常需要多张图,每张图讲一个层次的故事。我一般会准备这几张:
- 上下文图:系统与外部系统的关系,给非技术人员看
- 容器图:系统内部的主要服务/模块,给开发和管理层看
- 组件图:单个服务内部的组件划分,给负责该服务的开发看
- 部署图:节点分布和网络拓扑,给运维看
- 时序图:关键流程的交互顺序,给开发和测试看
这些图不是一次画完的,而是随着项目推进逐步补充。关键是每张图只讲一个层次,不要混在一起。
7.3 图的“退役”机制
系统演进后,有些图会过时。过时的图如果不清理,会误导后来者。所以需要建立一个“退役”机制:当某个模块被移除或重构后,对应的图要么更新,要么标记为“已废弃”并归档。
我通常会在图源文件里加一个头部注释,写明最后更新时间和对应版本。如果超过两个大版本没有更新,就在文档里标注“此图可能已过时,请参考最新代码”。这样读者看到时会有心理预期,不会盲目相信。
8. 我个人的一些实操心得
画了这么多年图,最大的体会是:图的质量不取决于工具,而取决于画图的人有没有想清楚。工具再好,如果逻辑混乱,画出来的图还是没人看得懂。反过来,即使用纸笔,只要逻辑清晰,图也能传递有效信息。
另一个心得是:不要追求一次画完美。图是迭代出来的,第一版丑一点没关系,关键是先画出来,然后在讨论中不断完善。我见过太多人因为纠结配色和字体,迟迟不肯出图,结果耽误了方案评审。
还有一点:多看图,多模仿。看到别人画得好的图,保存下来,分析它为什么清晰。是布局好?是配色好?还是标注好?然后用到自己的图里。这个习惯坚持半年,画图水平会有明显提升。
最后分享一个小技巧:如果你不确定一张图是否清晰,把它发给一个不在你项目组的同事,让他看一分钟,然后复述图的内容。如果他能准确说出主要模块和关系,说明图合格了;如果他一脸茫然,那就回去改。这个测试比任何评审都有效。