1. 从一张草图到一套系统:diagram-design 到底在解决什么问题
第一次听到 “diagram-design” 这个词,很多人会以为它只是“画图工具”的另一个说法。但真正在项目里被图表折磨过的人知道,问题从来不是“画不出来”,而是“画得出来却维护不了”。我见过太多团队,需求评审时随手用某个在线工具拖出一张架构图,两周后系统加了一个模块,那张图就永远停留在旧版本,没人愿意回去改,因为改一张图的成本比重新画还高。diagram-design 要解决的,正是这个“图与人、图与代码、图与时间”之间的脱节问题。
它本质上是一套以文本描述驱动图表生成的设计方法论与工具链组合。你不再用手去拖拽每一个方框和箭头,而是用结构化的文本(比如 Mermaid、PlantUML、D2、Graphviz DOT 等)把图“写”出来,再由渲染引擎把它变成可视化的图形。这个思路听起来简单,但它带来的连锁反应是巨大的:图表可以进版本控制、可以走代码评审、可以被程序自动生成、可以在 CI 流程里做一致性校验。适合谁来参考?如果你是需要长期维护系统架构图的后端工程师、要反复输出流程图的產品经理、或者想把文档图表纳入自动化流水线的 DevOps 从业者,这套东西值得你花时间吃透。
我个人的判断是,diagram-design 的价值不在“画图快”,而在“改图不痛”。一张手绘图的生命周期通常只有一次演示;一张文本驱动的图,生命周期可以跟项目一样长。这个差别,决定了你是在做一次性消耗品,还是在做可积累的资产。
2. 核心思路拆解:为什么是“文本驱动”而不是“拖拽式”
2.1 拖拽式工具的隐性成本在哪里
拖拽式工具(各类在线白板、桌面绘图软件)在“第一次画”这个环节确实爽,所见即所得,门槛极低。但它的成本被推迟到了后面。我总结过三个最典型的隐性成本。
第一是对齐与布局的重复劳动。你每加一个节点,都要手动调整它和周围节点的间距、连线走向、文字位置。节点一多,光是让图“看起来不乱”就能耗掉半小时。第二是版本对比的灾难。两个版本的图存成二进制文件或私有格式,你根本没法用 diff 看出“到底改了哪三个框”。评审时只能靠人眼找茬。第三是无法复用与自动化。你想让图随着接口定义自动更新?拖拽式工具基本做不到,只能人工同步,而人工同步必然滞后。
注意:我不是说拖拽式工具没用。做头脑风暴、快速勾勒概念时,它依然是最好的选择。问题在于,当一张图需要“活过”一次会议,你就该考虑换文本驱动了。
2.2 文本驱动图表的四个核心优势
把图写成文本之后,前面那些成本几乎被一次性消解。我按重要性排个序。
可版本控制是第一位。文本文件天然适配 Git,每次改动都有清晰的 diff,谁在什么时候加了哪个节点一目了然。可评审是第二位,图的变化可以像代码一样走 Pull Request,团队在合并前就能看到结构变动。可自动化是第三位,图可以由脚本、模板、甚至运行时数据生成,比如从服务注册中心拉取依赖关系直接出图。布局自动化是第四位,渲染引擎会根据你声明的逻辑关系自动排版,你只需要关心“谁连谁”,不用关心“框放哪”。
这四个优势叠加起来,图表就从“一次性插图”变成了“工程产物”。这也是 diagram-design 这套方法论真正的立足点。
2.3 常见文本图表语言怎么选
不同语言适合不同场景,选错了会平添痛苦。我整理了一张对照表,都是实测下来的体感。
| 语言/工具 | 擅长场景 | 学习曲线 | 布局能力 | 适合进 CI |
|---|---|---|---|---|
| Mermaid | 流程图、时序图、状态图、简单架构 | 低 | 自动,够用 | 是 |
| PlantUML | UML 全家桶、复杂时序、组件图 | 中 | 自动,较强 | 是 |
| D2 | 现代架构图、带容器的分层图 | 中低 | 自动,美观 | 是 |
| Graphviz DOT | 大规模关系图、依赖拓扑 | 中高 | 自动,极强 | 是 |
| 手写 SVG | 高度定制的视觉稿 | 高 | 手动 | 勉强 |
我的经验是:日常沟通用 Mermaid,正式架构文档用 D2 或 PlantUML,超大规模依赖关系用 Graphviz。不要一上来就追求最强大的工具,先用 Mermaid 把“写图”这个习惯建立起来,比什么都重要。
3. 核心细节解析:把图写好的关键不在语法,在结构
3.1 先想清楚图的“信息层级”
很多人写文本图表,第一反应是查语法。但语法只是皮毛,真正决定图好不好看、好不好懂的,是你在写之前有没有想清楚信息层级。一张架构图通常有三层:系统边界层(哪些是外部、哪些是内部)、模块层(内部由哪些服务组成)、交互层(它们之间怎么调用)。如果你把这三层混在一起平铺,图必然一团乱麻。
我的做法是先在纸上(或脑子里)列出节点清单,标注每个节点属于哪一层,再决定用什么容器或分组语法把它们框起来。Mermaid 的subgraph、D2 的容器、PlantUML 的package,都是用来表达层级的。层级清楚了,渲染出来的图自然有呼吸感。
3.2 命名与注释的规范
节点命名是最容易被忽视的细节。我踩过的坑是:一开始用中文全称当节点名,结果图里文字太长,框被撑得巨大,连线全被挤到角落。后来改成短标识 + 图例说明的方式,图立刻清爽了。
具体做法是节点用英文短名或缩写(如svc-order、db-user),然后在图的下方或单独一节用文字解释每个缩写的含义。如果一定要在节点里显示中文,控制在一行 6 到 8 个字以内。注释方面,善用note或comment语法,把“为什么这么设计”写进去,而不是只写“这是什么”。图的注释是给未来的自己和同事看的,价值极高。
3.3 连线语义要统一
连线是图表的灵魂,但也是最容易语义混乱的地方。同一个项目里,有人用实线表示“同步调用”,有人用实线表示“数据流”,还有人用实线表示“依赖”,最后图就没法看了。diagram-design 的一个核心纪律就是:在项目开始前,定义好一套连线语义规范,并写进文档。
我常用的一套规范是这样的:实线箭头表示同步请求,虚线箭头表示异步消息,粗线表示高频调用,带标签的线注明协议或数据格式。这套规范一旦定下来,所有图都遵守,读者看第一张图时建立的认知,可以直接迁移到后面所有图。这就是“设计系统”思维在图表上的体现。
4. 实操过程:从零搭一套可维护的图表工作流
4.1 环境准备与工具选型
先说最小可用方案。如果你只想快速上手,装一个支持 Mermaid 的 Markdown 编辑器就够了,很多主流编辑器都内置了 Mermaid 预览。但如果要进团队协作和 CI,我建议这样搭:
- 渲染引擎:本地用命令行工具(如 Mermaid CLI、D2 CLI),保证和 CI 环境一致。
- 存储方式:所有图表源文件放在代码仓库的
docs/diagrams/目录下,和代码同生命周期。 - 预览方式:编辑器插件实时预览,或者本地起一个静态站点。
- 导出格式:统一导出 SVG,因为 SVG 是矢量、可搜索、体积小,比 PNG 清晰得多。
提示:导出格式尽量选 SVG。PNG 在高分屏上会糊,而且无法用文本搜索节点名,后期维护很痛苦。
4.2 一个完整的架构图实操示例
假设我们要描述一个订单系统的调用关系。用 Mermaid 写出来大概是这样:
flowchart TD Client[客户端] -->|HTTPS| Gateway[API 网关] Gateway -->|同步| OrderSvc[订单服务] Gateway -->|同步| UserSvc[用户服务] OrderSvc -->|同步| InventorySvc[库存服务] OrderSvc -->|异步| MQ[(消息队列)] MQ -->|消费| NotifySvc[通知服务] OrderSvc -->|读写| OrderDB[(订单库)] UserSvc -->|读写| UserDB[(用户库)]这段代码里,TD表示从上到下布局,方括号是节点,圆括号是数据库这类特殊形状,-->|标签|是带标签的连线。渲染出来就是一张清晰的调用拓扑。关键在于,这张图是纯文本,你可以把它放进 Git,每次服务拆分或合并时改一行代码,图就更新了。
4.3 把图表接入 CI 做一致性校验
这是 diagram-design 真正拉开差距的地方。我做过一个实践:在 CI 里加一个步骤,检查图表源文件是否能成功渲染。如果某个同事改图时写错了语法,CI 直接失败,避免了一张坏图被合并进主分支。
更进一步,可以写脚本对比“图表里声明的服务”和“代码里实际存在的服务”,一旦对不上就报警。这个脚本不复杂,核心逻辑就是解析图表源文件里的节点名,和配置文件里的服务列表做集合比对。这一步做完,图表就再也不会“悄悄过期”了。
# 伪代码示意:渲染所有图表,失败则退出 for f in docs/diagrams/*.mmd; do mmdc -i "$f" -o "${f%.mmd}.svg" || exit 1 done4.4 团队协作中的目录与命名约定
团队一多人,文件命名就会乱。我建议约定一套目录结构,比如按“系统/模块”分层,文件名用“主题-类型”格式,例如order-overview-arch.mmd、order-create-sequence.mmd。这样任何人找图都不用问人,看目录就知道在哪。命名约定看起来是小事,但它决定了半年后你还能不能快速定位到那张图。
5. 常见问题与排查技巧实录
5.1 渲染出来布局很丑怎么办
这是最高频的问题。布局丑通常不是引擎的错,而是你的图“信息密度”太高。我的排查顺序是:先看节点数量,超过 20 个就该拆图;再看连线是否交叉严重,交叉多说明层级没分好;最后看是否有孤立节点,孤立节点往往意味着你漏了关系或者该删掉。拆图永远比硬塞进一张图更明智。
5.2 中文显示乱码或字体不对
文本图表渲染中文时,偶尔会遇到字体缺失导致方块字。解决办法是在渲染配置里显式指定一个支持中文的字体,比如在 Mermaid 配置里设置fontFamily。如果导出 SVG 后中文变方块,多半是渲染环境没装对应字体,在 CI 镜像里补上即可。
5.3 图表和代码不同步
这是流程问题,不是工具问题。根治办法只有一个:把图表源文件放进代码仓库,并在代码评审清单里加一条“涉及结构变更时是否更新了图表”。工具能帮你校验语法,但“要不要更新图”这个判断,只能靠流程约束。
5.4 常见问题速查表
| 现象 | 可能原因 | 解决方向 |
|---|---|---|
| 布局拥挤 | 节点过多、层级不清 | 拆图、加分组 |
| 中文乱码 | 字体缺失 | 指定中文字体 |
| 连线交叉严重 | 层级混乱 | 重排节点归属 |
| 图与代码不符 | 无同步机制 | 纳入仓库与评审 |
| 渲染 CI 失败 | 语法错误 | 本地先预览再提交 |
| 导出模糊 | 用了 PNG | 改用 SVG |
注意:不要指望一次就把图画完美。图表是迭代出来的,先出一版能看的,再根据反馈调整,比憋一张“完美图”效率高得多。
6. 我踩过的坑与几条实在的经验
说几个只有真做过才会知道的细节。第一,别在图表里塞业务逻辑。图是给人快速建立认知的,不是文档的替代品。把复杂的条件分支全画进流程图,读者只会晕。第二,给图加更新时间戳和负责人。一张不知道谁维护的图,等于没有。第三,定期清理废弃图。仓库里堆着几十张过期图,比没有图更糟,因为新人会误以为它们还有效。
我个人在实际操作中的体会是,diagram-design 最难的不是学语法,而是养成“先想结构再动手”的习惯。语法半小时就能学会,但把一张图的信息层级想清楚,需要的是对系统的理解。工具只是放大器,它放大的是你原本就清晰的思路,或者原本就混乱的思路。所以每次动手前,我都会先问自己一句:这张图,读者看完应该记住哪三件事?想清楚这个,图就成功了一半。