1. 从一张草图到一套系统:diagram-design 到底在解决什么问题
第一次看到 “diagram-design” 这个标题,很多人会以为它只是教你怎么把图画得好看一点。但真正在工程、产品、咨询、教学这些场景里摸爬滚打过的人都知道,图的问题从来不是“好不好看”,而是“能不能把复杂关系讲清楚,并且让不同角色的人在同一张图上达成共识”。diagram-design 这个项目,核心就是围绕“图的设计”建立一套可复用的方法论和工具链,让画图这件事从个人审美驱动,变成有结构、有规范、可协作的工程行为。
我接触过不少团队,画架构图、流程图、时序图、状态机图、业务链路图时,最常见的状态是:每个人用不同的工具,有人用在线白板,有人用绘图软件,有人直接拿代码生成,最后拼在一起像一锅大杂烩。箭头方向不统一,颜色含义不一致,图例缺失,层级混乱。更麻烦的是,图一旦画完就变成“死”的,代码改了图不改,需求变了图不更新,最后没人敢信图上的内容。diagram-design 要解决的,正是这种“图与系统脱节、图与协作脱节”的问题。
这个项目适合谁?如果你是后端工程师,需要画服务依赖和调用链路;如果你是产品经理,需要把业务流程和状态流转讲清楚;如果你是技术写作者或讲师,需要用图辅助表达;如果你是团队负责人,需要建立统一的图示规范,那 diagram-design 的思路和工具组合都值得你花时间研究。它不要求你有美术功底,但要求你有结构化思维,愿意把“画图”当成一项可以标准化的工作来做。
我个人的判断是:diagram-design 的价值不在于某一个具体工具,而在于它把“图”拆成了三个层次——语义层(这张图要表达什么关系)、结构层(用什么图类型、什么层级、什么粒度)、表现层(颜色、字体、布局、导出格式)。很多人一上来就纠结表现层,结果图越画越花,信息密度反而下降。正确的顺序是先定语义,再定结构,最后才调表现。这个顺序搞反了,后面全是返工。
2. 核心思路拆解:为什么“图即代码”是绕不开的方向
2.1 从“画图”到“描述图”:思维方式的转变
传统画图是“所见即所得”,你拖一个框,拉一条线,位置靠鼠标微调。这种方式适合一次性、小规模的图,但一旦图变大、要改、要多人协作,就会暴露三个致命问题:第一,版本管理困难,二进制文件没法 diff,改了什么全靠记忆;第二,复用性差,同样的服务节点在十张图里重复画十遍,改一个名字要改十处;第三,一致性无法保证,不同人画出来的风格天差地别。
diagram-design 倡导的“图即代码”,本质是把图变成文本描述,再由渲染引擎生成最终图形。你写的是“A 调用 B,B 依赖 C”,而不是“把 A 框放在左上角,B 框放在中间”。这样做的好处非常直接:文本可以进 Git,可以 review,可以 diff,可以批量替换,可以用脚本生成。图从“美术作品”变成了“工程产物”。
我试过在一个中等规模的项目里,把原本用绘图软件维护的二十多张架构图全部改成文本描述。改完之后,重命名一个服务只需要全局替换一次,新增一条调用关系只需要加一行,导出不同格式(PNG、SVG、PDF)只需要改一个命令。最爽的是,代码仓库里改了接口,CI 里跑一个脚本就能检查图有没有同步更新,图再也不会“过期”了。
2.2 工具选型:为什么是 Mermaid、PlantUML、Graphviz 这一套
市面上图即代码的工具不少,diagram-design 这个项目里最常被提到的组合是 Mermaid、PlantUML 和 Graphviz。它们各有侧重,不是互相替代,而是配合使用。
Mermaid 的优势是语法轻、上手快、和 Markdown 生态融合好。很多文档平台原生支持 Mermaid,你写一段代码块就能出图,适合流程图、时序图、状态图、甘特图这些“表达逻辑关系”的场景。缺点是布局控制力弱,复杂图的自动排版有时会出乎意料。
PlantUML 的优势是图类型极其丰富,除了常见的 UML 图,还支持架构图、部署图、网络图、思维导图、JSON 可视化等。它的布局引擎更成熟,适合画大型、层级深的图。缺点是语法相对重,学习曲线比 Mermaid 陡一点,渲染依赖 Java 环境。
Graphviz 则是更底层的布局引擎,用 DOT 语言描述节点和边,自动布局能力非常强,尤其适合画依赖关系图、调用图、拓扑图。很多工具(包括 PlantUML 的部分图类型)底层就是调 Graphviz。它的缺点是语法偏“原始”,写起来不如 Mermaid 直观,但控制力最强。
我的建议是:日常逻辑图用 Mermaid,复杂结构图用 PlantUML,纯关系拓扑用 Graphviz。不要试图用一个工具解决所有问题,那样只会让每张图都别扭。diagram-design 的思路就是按场景选工具,而不是按个人喜好选工具。
2.3 设计原则:一张好图的四个硬指标
在 diagram-design 的框架里,一张合格的图必须满足四个指标,我把它总结成“四可”:
- 可读:字号、对比度、留白到位,不放大也能看清主干。
- 可解:图例完整,颜色和形状有明确含义,不需要口头解释就能看懂。
- 可维护:源文件是文本,能进版本控制,改一处不影响全局。
- 可导出:能一键导出多种格式,适配文档、演示、打印等不同场景。
这四个指标里,最容易被忽视的是“可解”。很多人画图默认读者和自己有同样的背景知识,结果图里全是缩写和隐晦的颜色。我踩过的坑是:给一个跨部门评审画业务流程图,用了五种颜色表示五种状态,但没写图例,评审会上花了十分钟解释颜色含义,真正讨论业务的时间被压缩了一半。从那以后,我画任何图都强制自己加图例,哪怕觉得“这还用解释吗”。
3. 核心细节解析:图类型、语法要点与实操避坑
3.1 图类型选择:什么场景用什么图
选错图类型是画图翻车的头号原因。我见过用时序图表达业务流程的,也见过用流程图表达类关系的,读起来非常费劲。下面这张表是我在实际工作中总结的对照关系,可以直接抄作业。
| 表达需求 | 推荐图类型 | 推荐工具 | 常见误用 |
|---|---|---|---|
| 步骤先后与分支 | 流程图 | Mermaid | 用状态图表达线性步骤 |
| 对象间消息往来 | 时序图 | Mermaid / PlantUML | 用流程图表达异步调用 |
| 状态流转与触发条件 | 状态图 | Mermaid / PlantUML | 用流程图表达循环状态 |
| 服务依赖与拓扑 | 架构图 / 依赖图 | PlantUML / Graphviz | 用时序图表达静态依赖 |
| 数据模型与关系 | ER 图 | Mermaid / PlantUML | 用类图表达数据库表 |
| 类与继承关系 | 类图 | PlantUML | 用 ER 图表达代码结构 |
| 项目排期 | 甘特图 | Mermaid | 用表格代替甘特图 |
这张表的核心逻辑是:先问“我要表达的是时间、结构还是关系”,再选图类型。时间维度优先用时序图或流程图,结构维度优先用类图或 ER 图,关系维度优先用依赖图或拓扑图。选对了图类型,图就成功了一半。
3.2 Mermaid 实操要点:语法简洁但陷阱不少
Mermaid 的语法看起来很简单,但实际用起来有几个高频坑,我一个个说。
第一个坑是节点 ID 和显示文本混淆。Mermaid 里A[用户]表示节点 ID 是 A,显示文本是“用户”。如果你后面写A --> B,用的是 ID 不是文本。很多人写着写着就忘了 ID 是什么,导致连线连错。我的习惯是 ID 用有意义的英文短名,比如user、order、payment,显示文本用中文,这样既好读又好维护。
第二个坑是特殊字符转义。节点文本里如果有括号、引号、冒号,Mermaid 会解析出错。解决办法是用引号把文本包起来,比如A["用户(已登录)"]。这个细节文档里写得不多,但实际画图时几乎天天遇到。
第三个坑是布局方向控制。Mermaid 用graph TD表示从上到下,graph LR表示从左到右。但自动布局有时会把图排得很宽或很长,影响阅读。我的经验是:层级深的图用 TD,流程长的图用 LR,节点多的图考虑拆成多张,不要硬塞在一张图里。
下面是一段我常用的流程图模板,可以直接改:
graph TD A["用户发起请求"] --> B{"参数校验"} B -->|通过| C["查询订单"] B -->|不通过| D["返回错误"] C --> E{"订单存在"} E -->|是| F["执行支付"] E -->|否| D F --> G["更新状态"] G --> H["返回成功"]这段代码里,{}表示判断节点,|通过|表示边上的标签,[""]表示带特殊字符的文本。掌握这三个语法点,大部分流程图都能画出来。
3.3 PlantUML 实操要点:复杂图的利器
PlantUML 的语法比 Mermaid 重,但换来的是更强的表达力。我主要用它画三类图:组件图、部署图、时序图。
组件图的关键是包和依赖。用package把相关组件包起来,用-->表示依赖方向。这里有个经验:依赖箭头要指向被依赖方,不要画反。我见过很多图箭头方向混乱,读图的人要猜半天。统一规则是“谁主动谁在箭头尾部”。
部署图的关键是节点和制品。用node表示物理或逻辑节点,用artifact表示部署在节点上的制品。这张图的价值在于让运维和开发对“什么东西跑在哪里”达成一致。我建议部署图一定要标注环境(开发、测试、生产),否则容易混淆。
时序图的关键是参与者和消息顺序。PlantUML 的时序图支持激活框、返回消息、分组、注释,表达力比 Mermaid 强。画时序图时,我强制自己遵守一条规则:每条消息都要有明确的发起方和接收方,不允许出现“系统”这种模糊角色。模糊角色是时序图最大的信息黑洞。
3.4 样式与主题:统一比好看更重要
diagram-design 里有一个容易被低估的点:样式统一。一张图里如果字体、颜色、线型不统一,读者会下意识觉得“这图不专业”,进而怀疑内容质量。这不是审美问题,是信任问题。
我的做法是建立一套团队级的样式规范,写成一个主题文件,所有图共用。规范内容包括:主色不超过三种,分别表示正常、警告、异常;字体统一用无衬线;线型统一用实线表示同步、虚线表示异步;节点形状统一用矩形表示服务、圆角矩形表示外部系统、菱形表示判断。
这套规范一旦定下来,画图速度会大幅提升,因为不用每次纠结颜色和形状。更重要的是,团队里任何人画的图,别人都能快速看懂。我实测下来,统一主题后,跨团队评审时解释图的时间平均减少了三分之一。
4. 实操过程:从零搭建一套 diagram-design 工作流
4.1 环境准备与工具安装
要跑通一套图即代码的工作流,本地需要准备三样东西:一个文本编辑器(VS Code 就够)、一个渲染工具链、一个版本控制仓库。
VS Code 里装两个插件基本就够用了:Mermaid 预览插件和 PlantUML 插件。Mermaid 插件支持实时预览,写完代码右边直接出图。PlantUML 插件需要本地有 Java 环境,装完之后同样支持预览和导出。
如果你不想装本地环境,也可以用命令行工具批量渲染。Mermaid 有mmdc命令行工具,PlantUML 有plantuml.jar,Graphviz 有dot命令。这三个工具配合脚本,可以实现“改文本、自动出图、自动提交”的流水线。
我建议的目录结构是这样的:
diagrams/ src/ architecture.puml flow.mmd topology.dot dist/ architecture.svg flow.svg topology.svg theme/ default.json build.shsrc放源文件,dist放导出结果,theme放主题配置,build.sh是批量渲染脚本。这个结构清晰,源文件和产物分离,不会互相污染。
4.2 从需求到成图:一个完整案例
假设你要画一张“订单支付链路”的图,需求是让产品、后端、测试三方都能看懂。我的操作流程是这样的:
第一步,明确读者和目的。这张图给三方看,所以不能太偏技术细节,要突出业务流转和关键判断点。目的是对齐“支付成功和失败分别走什么路径”。
第二步,选图类型。因为有步骤、有分支、有状态变化,选流程图最合适。工具用 Mermaid,因为三方都能在文档里直接看。
第三步,列节点和边。先在纸上或脑子里列出所有节点:用户下单、校验库存、创建订单、发起支付、支付回调、更新订单状态、通知用户。再列出判断点:库存是否充足、支付是否成功。
第四步,写代码。把节点和边翻译成 Mermaid 语法,注意判断节点用{},边标签用| |。
第五步,加图例和注释。在图的旁边或下方加一段说明,解释颜色和形状的含义。这一步很多人省略,但它是“可解”的关键。
第六步,导出和嵌入。把图导出成 SVG,嵌入到文档或演示里。SVG 的好处是放大不失真,适合投影和打印。
这个流程看起来有六步,但熟练之后,一张中等复杂度的图十分钟就能搞定。关键是养成“先想清楚再动手”的习惯,不要一上来就拖框。
4.3 参数计算与布局调优
图即代码的一个痛点是自动布局有时不理想。比如 Mermaid 画一张有二十个节点的流程图,自动布局可能会把图拉得很长,或者把相关节点排得很散。这时候需要手动干预。
Mermaid 里可以通过subgraph把相关节点分组,让布局引擎把它们放在一起。还可以通过调整节点声明顺序,影响布局结果。我的经验是:把主干路径的节点先声明,分支节点后声明,这样主干会排在中间,分支在两侧,读起来更顺。
PlantUML 里可以用together关键字把几个节点强制放在一起,用left to right direction改变整体方向。Graphviz 里可以用rank和constraint控制节点层级。这些技巧文档里都有,但需要实际画几张图才能找到感觉。
还有一个实用技巧是控制图的粒度。一张图不要超过十五个节点,超过就拆成两张。我见过一张五十多个节点的架构图,打印出来字小得看不清,投影出来更是一片糊。图的价值在于“一眼看懂主干”,细节应该放在子图或文档里。
5. 常见问题与排查技巧实录
5.1 渲染失败与语法报错速查
图即代码最让人抓狂的就是渲染失败,尤其是语法报错时,错误信息往往很模糊。下面这张表是我踩坑总结出来的高频问题和解决办法。
| 问题现象 | 可能原因 | 解决办法 |
|---|---|---|
| 图渲染不出来,空白 | 语法错误或工具版本不兼容 | 先用最小示例测试,逐步加内容定位 |
| 节点文本显示不全 | 特殊字符未转义 | 用引号包裹文本,如A["文本"] |
| 连线方向反了 | 箭头语法写反 | 检查-->和<--的方向 |
| 布局太宽或太长 | 节点太多或方向不对 | 拆分图或改TD/LR |
| 中文显示乱码 | 字体未配置 | 在主题里指定中文字体 |
| 导出 SVG 后样式丢失 | 内联样式未嵌入 | 导出时选择嵌入样式选项 |
排查语法错误时,我的习惯是二分法:把图从中间切开,先渲染前半部分,再渲染后半部分,哪半报错就继续切。这样比一行行看快得多。
5.2 图与代码不同步的根治办法
图过期是图即代码要解决的核心问题,但如果工作流没设计好,图照样会过期。我的做法是把图的生成嵌入到 CI 流程里。
具体来说,在代码仓库里放一个脚本,每次合并请求时自动跑一遍,检查图源文件有没有更新。如果代码里的接口变了但图没变,脚本就报错,阻止合并。这个机制一开始会有点烦,但跑一段时间后,团队就养成了“改代码同时改图”的习惯。
另一个办法是从代码生成图。比如从接口定义文件生成时序图,从依赖配置文件生成架构图。这样图就是代码的“投影”,代码变了图自动变。这个方案实施成本高一些,但对大型项目非常值得。
5.3 团队协作中的图规范落地
一个人画图容易,一群人画图难。diagram-design 在团队落地时,最大的阻力不是工具,是习惯。我的经验是分三步走:
第一步,定规范。把图类型、颜色、字体、命名规则写成文档,放在团队知识库里。规范不要写太长,一页纸能说清最好。
第二步,做模板。把常用图类型做成模板文件,新人直接复制改内容,不用从零开始。模板里预置好主题和图例,减少自由发挥空间。
第三步,做评审。在代码评审里加一条“图是否同步更新”,把图的质量纳入评审范围。一开始大家不习惯,但坚持几周后,图的质量会明显提升。
我踩过的一个坑是:规范定得太细,细到规定每个节点的字号,结果大家觉得麻烦,干脆不遵守。后来我把规范精简到“颜色含义、图类型选择、命名规则”三条,执行率反而高了。规范要抓大放小,不要试图控制一切。
6. 进阶玩法:让图自动生成与持续演进
6.1 从数据生成图:脚本化出图
当图的数量超过一定规模,手动维护就不现实了。这时候需要脚本化出图。思路很简单:把图的数据抽出来,用脚本生成图源文件,再渲染成图。
比如画服务依赖图,数据源可以是配置文件或服务注册中心。脚本读取依赖关系,生成 DOT 或 PlantUML 代码,再调渲染工具出图。这样每次依赖变化,图自动更新,不需要人工干预。
我做过一个实验:用脚本从接口定义文件生成时序图。接口定义里本来就有调用关系,脚本把它翻译成 PlantUML 时序图语法,渲染出来直接可用。虽然生成的图不如手画的精致,但胜在准确和及时。对于“图要准”的场景,自动生成是更优解。
6.2 图的版本管理与 diff 技巧
文本图源文件进 Git 后,diff 非常直观。改了一个节点名,diff 里就是一行变化;加了一条边,diff 里就是新增一行。这比二进制文件的“改了但看不出改了什么”强太多。
我的做法是:图源文件和代码放在同一个仓库,同一个合并请求里同时改代码和图。评审时先看代码 diff,再看图 diff,确认两者一致。如果图 diff 是空的但代码 diff 有接口变化,就说明图没更新,打回重改。
还有一个技巧是给图源文件加注释。在 PlantUML 或 DOT 文件里用注释说明这张图的用途、读者、更新频率。这样半年后回来看,还能快速理解这张图是干什么的。
6.3 多格式导出与文档集成
图最终是要给人看的,所以导出格式很重要。我的经验是:文档用 SVG,演示用 PNG,打印用 PDF。SVG 矢量清晰,适合网页和文档;PNG 兼容性好,适合插入演示文稿;PDF 适合打印和归档。
导出时要注意两点:一是字体嵌入,否则换台机器可能显示异常;二是尺寸控制,导出时指定合适的宽度,避免图太大或太小。Mermaid 和 PlantUML 都支持导出参数,花几分钟调一下,效果差别很大。
文档集成方面,很多静态站点生成器原生支持 Mermaid,直接在 Markdown 里写代码块就能出图。PlantUML 需要额外的渲染步骤,但也有很多插件支持。我的建议是:文档里优先用 Mermaid,复杂图用 PlantUML 导出 SVG 后嵌入。这样兼顾了便捷性和表现力。
7. 我个人的实操体会与几个小技巧
画了几年图,我最大的体会是:图的质量不取决于工具,取决于画图的人有没有想清楚。工具再好,如果画图的人自己都没搞明白系统怎么运转,画出来的图一定是乱的。所以每次画图前,我都会先问自己三个问题:这张图给谁看?要表达什么核心关系?看完之后读者应该记住什么?这三个问题答不上来,就先别动手。
第二个体会是:图要少而精,不要多而全。我见过一些团队,每个模块都画图,结果图多到没人看。我的做法是只画三类图:全局架构图、核心链路图、关键状态图。其他细节用文字或表格表达。图是稀缺资源,用多了就不值钱了。
最后分享几个小技巧。一是用颜色表达状态而不是分类,颜色太多会分散注意力,三种以内最好。二是给图起名字,不要叫“流程图1”,叫“订单支付主链路”,这样找图和引用都方便。三是定期清理过期的图,图过期比没有图更危险,因为它会误导人。我每个季度会花半小时过一遍图库,把不再维护的图归档或删除。
这套 diagram-design 的思路和工具链,我从个人项目用到团队协作,从几张图用到上百张图,实测下来是稳的。它不会让你一夜之间变成绘图高手,但能让你画的每一张图都有据可循、有法可依、有人敢信。