博主 / 架构可视化 / 技术写作
“diagram-design”:从随手画到体系化——聊聊我整理架构图、流程图与系统图谱的完整思路
开头先说实话:我见过太多团队死磕代码,却栽在“说不清系统长什么样”这件事上。评审会上一张乱七八糟的箭头图,比一段烂代码更消耗耐心。后来我花了不少时间专门研究 diagram-design——不是学美术,而是把画图当成一种结构化表达。这篇文章就把我验证过的一套做法、踩过的坑、还有具体的工具选型逻辑,一次讲清楚。不管你是要画系统架构图、业务流程图,还是给文档配一张数据流转示意,按这套思路走,基本都能出活。
不知道你有没有这种感觉:需求文档里写了一大堆,但最让新同事崩溃的,往往不是文字,而是那张“看起来什么都有、实际上什么都没说明白”的架构图。箭头上没有方向说明,方框大小随心所欲,颜色能凑出彩虹——这种情况太常见了。而 diagram-design 的核心,恰恰是把这个混乱过程变成一个有约束、有原则、能复用的工程流程。
1. 先想清楚:技术图表到底解决什么问题
大部分人一开始就打开工具画图,这其实是个误区。画图的第一步不是打开编辑器,而是想明白这张图要替谁说话、要解决什么疑问。
1.1 图表是一种沟通协议
我在实际项目里发现,一张好的技术图表,本质上是一份“初始成本高、维护成本低”的沟通协议。你写一万字的需求文档,读者可能各执一词;但如果你画清楚一个系统的分层边界、模块依赖和调用路径,大家站在一起看同一张图,讨论立刻就能收敛到具体节点上。
这也是为什么 diagram-design 值得认真对待——它做的是把大脑里的逻辑模型外化成一个可共享、可修改、可核查的公共画布。这个画布不是给人“看着好看”的,而是给人“对着干活”的。
每次动手之前,我都会先问三个问题:
- 这张图的读者是谁?是刚接手模块的新人,还是评审架构的老手?
- 这张图要支撑什么决策?是确认边界、排查故障,还是规划扩容?
- 这张图的维护节奏是什么样?是一次性交付,还是随项目长期更新?
这三个问题的答案,直接决定了后续的所有选择:用文本绘图工具还是拖拽工具、图要画多细、布局要不要自动化。
1.2 三种最常见的图,对应三套方法论
在“diagram-design”这个主题下,我实际用得最多的其实是三种图型。它们不是互斥的,但方法论侧重点完全不同。
第一种是架构图。这类图的关键词是“分层与边界”。画的时候脑子里一直要有一种“容器思维”:哪些东西是进程边界?哪些是数据存储?哪些是外部依赖?架构图最怕把所有组件平铺在一层,那样根本看不出系统的吞吐逻辑。
第二种是流程图。这类图的关键词是“分支与状态”。核心在于把“条件判断”画准确:什么时候走正常路径,什么时候走异常路径,异常之后回退到哪里。很多人画的流程图,其实漏掉了异常分支,导致图上看起来顺顺当当,一上线就原形毕露。
第三种是时序图。这类图的核心是“消息与时间顺序”。尤其适合表达复杂的服务间调用链、异步回调、超时重试。我个人的经验是,当一个接口涉及超过三个服务协作时,把它画成时序图的收益,远大于堆文字。
先把图型选对,再谈工具和美观,这个顺序很重要。
2. 工具选型:没有万能工具,只有合适场景
作为常年写文档的人,我对“协同编辑时图能不能放进 Git 里走 diff”这件事非常在意。所以我的工具观很清楚:能用文本描述的,绝对不用二进制文件;能自动布局的,绝对手工不拖框。
2.1 主流文本画图工具对比
文本画图的核心价值,是把“图”变成“代码”,从而获得版本管理、diff 审查、脚本生成、批量修改的能力。我在项目里重度使用过 Mermaid、PlantUML 和 Graphviz,它们的适用场景差别挺大:
| 工具 | 上手曲线 | 自动化布局能力 | UML 支持 | 中文显示 | 典型场景 |
|---|---|---|---|---|---|
| Mermaid | 极平缓 | 中等 | 中等 | 依赖渲染环境 | 写技术文档、博客、Wiki 内嵌 |
| PlantUML | 平缓 | 中等 | 强 | 原生支持较好 | UML 建模、详细序列图 |
| Graphviz | 较陡 | 强(基于DOT自动排布) | 弱 | 需调整字体 | 复杂依赖关系、自动生成的图谱 |
有一个很容易踩的坑:Mermaid 的时序图虽然写起来快,但一旦消息数量超过二十条,渲染出来的布局会非常松散,图面拉得巨长,阅读体验反而糟糕。PlantUML 的时序图在多消息场景下的分组和注释能力明显更强,信息密度更高,长期维护也更舒服。
2.2 我为什么在文档里首选 Mermaid
先说结论:如果只是想在 Markdown 文档里放一张随代码迭代更新的流程图或简版架构图,Mermaid 基本是我的默认选项。
原因有三。第一,生态好,GitHub、各类在线文档平台、甚至很多代码托管系统都内置渲染,不需要额外搭建服务;第二,语法足够简单,团队里只要一个人懂,其他人看代码就能猜个大概;第三,它跟 Git 的配合完美,改一行文字就是一次提交,Review 的时候能清楚看到图的变化。
我自己比较常用的一套组合是:Markdown + Mermaid 画业务流程图和数据流图,PlantUML 画需要严格建模的时序图,Graphviz 画自动生成的大规模依赖图谱。各管一段,互不抢戏。
注意一点:凡是要给客户或外部团队看的高保真架构图,我不会只用 Mermaid 裸奔,而是会导出 SVG 后交给绘图工具做一轮人工排版和配色。
3. 设计原则:让图“一秒钟看懂”的五个关键
工具只是基础,真正拉开差距的,是对图本身的“视觉工程”处理。下面这五条,是我在多次返工中提取出来的硬经验,基本已经形成了checklist。
3.1 布局要顺应阅读顺序
人眼读图是有天然路径的,要么从左到右,要么从上到下。架构图就顺着数据流向排,流程图就顺着主流程排,别把主要模块放在图的正中央,然后让读者的视线四面八方乱飞。
我在画分层架构图时,一定会维持“底层在下、上层在上”的约定:底层是基础设施和服务,中间是领域能力,顶层是入口。一旦在前期就遵守这个约定,后面往图里加再多的模块,整体感都还在。
配置 Graphviz 或 Mermaid 时,显式指定方向(比如 Mermaid 里的graph TD或graph LR),比默认布局要可控得多。别小看这一行,它决定了整个图的主干走向。
3.2 把“分组”做成图的骨架
很多混乱的图,根本问题在于没有分组思维。正确的做法是先用大框把系统边界框出来,然后在框内放置具体组件,这样一张图就能同时表达“宏观容器”和“微观模块”。
画 Mermaid 的时候,我用 subgraph 的频率非常高。比如一个订单系统,我会先按业务域拆分 subgraph,每个 subgraph 代表一套独立的服务边界,然后再在服务内部画具体节点。这样做还有一个额外好处:当代码结构调整时,我只需要挪动 subgraph 的位置,内部节点关系基本不受影响。
3.3 什么是对外可输出的“好配色”?
这里必须明确一个观点:技术图表的配色不是为了好看,而是为了语义区分。颜色必须承载信息,不能用得随心所欲。
我给自己定的规矩是:
- 核心服务用同一种色系,外部依赖用完全不同的色系;
- 异常路径 / 告警节点用警示色点缀,但一屏内不超过三处;
- 灰度色作为默认底色,让真正的信息高亮出来。
Mermaid 的主题定制能力虽然不算强,但通过 classDef 自定义节点颜色已经足够满足 90% 的需求。Graphviz 就更自由了,几乎可以精细设置每个节点的填充色、边框色与字体色。
3.4 文字标注要“少而准”
节点里的文字,不要写完整句子,写能一眼看懂的名词短语。比如“用户创建订单成功,扣除库存并发送通知”,放进节点只会撑爆框体。拆成“创建订单”“扣库存”“发通知”三个节点,然后通过箭头表达因果关系,信息反而更清楚。
还有一个很容易被忽视的细节:给重要边配上文字标签。单纯画一条箭头,读者只能知道“有关联”,但不知道“是什么关联”。配上标签之后,比如“HTTP 调用”“异步消息”“SQL 查询”,图的表达力立刻提升一档。注意箭头的方向也要与实际调用方向一致,很多图画反了就是事故。
3.5 一致性比单个突出更重要
整套图里,同类元素必须保持同一种视觉语言:同级模块用相同尺寸的方框,边界框使用统一的虚线线型,外部系统用统一的异色底。哪怕一级模块之间存在字数差异,也要保证视觉上的近似尺寸,可以用注释或子节点补充细节,而不是把一个框拉得特别大。
这一点在团队协作里尤其重要。只要建立了“样式一致性”的隐性规则,任何人接手维护,新加的模块都能顺着既有风格走,图就不会越改越乱。
4. 完整实操:从零设计一张系统架构图
我拿一个亲历的模拟项目来演示完整流程:某跨平台系统需要把多个数据源同步到一套本地分析平台,再由上层报表服务做聚合展示。接手时没有一张像样的图,所有人对“边界到底在哪里”争论不休。
4.1 需求梳理与模块划分
第一步,我没有画任何东西,而是把系统的运行流程写成了文字:数据源产生数据,通过采集器接入消息队列,由消费服务清洗后写入分析库,报表服务读取分析库提供查询接口。同时要调度系统负责定时触发采集任务,权限服务负责控制报表访问范围。
写完这段话之后,边界自然就浮现了:接入层、传输层、处理层、存储层、应用层、支撑服务。按这个分层去画图,绝不会乱。
4.2 用 Mermaid 快速生成架构草稿
我用 Mermaid 写了一个初版架构图,关键代码是这样的:
graph TD S1[外部数据源A] --> C[采集器集群] S2[外部数据源B] --> C C -->|写入| Q[(消息队列)] Q --> P[消费处理服务] P -->|清洗转换| DB[(分析库)] R[报表服务] --> DB D[调度系统] --> C Auth[权限服务] --> R这段看起来简单,但已经包含了几个设计取舍:所有数据源统一接入一个采集器集群,而不是分别画到队列,因为架构图上要表达的是“采集能力统一”,具体物理部署在部署图上再展开。
4.3 细化和视觉优化
得到草稿后,第二步是补充“分组”和“语义色”。我使用 classDef 将核心处理链路和外部依赖区分开,又用 subgraph 把系统内组件和外部数据源隔开。最终版本大概长这样:
graph TD subgraph 外部数据域 S1[数据源A] S2[数据源B] end subgraph 系统内部 C[采集器集群] Q[(消息队列)] P[消费处理服务] DB[(分析库)] R[报表服务] D[调度系统] Auth[权限服务] end S1 --> C S2 --> C C -->|写入| Q Q --> P P -->|清洗转换| DB R --> DB D --> C Auth --> R classDef internal fill:#E8F4FD,stroke:#0072B2; classDef external fill:#FFF3E0,stroke:#E65100; classDef db fill:#EDE7F6,stroke:#4527A0; class C,P,R,D,Auth internal; class S1,S2 external; class Q,DB db;这版图做出来之后,团队里再开评审会,争论立刻从“我觉得边界在这”变成了“采集器的并发策略要不要改”,这说明图真正起到了收敛讨论的作用。
4.4 导出与交付
如果只是放在内部文档里,Mermaid 代码直接嵌进去就行;如果要拿去给协作方评审,我会再导成 SVG,用绘图工具做一轮手工微调。主要是把关键链路的箭头加粗、调整一下 subgraph 的间距、让标题更醒目。最终的交付物既保留了一份文本源文件(方便以后用脚本改),也产出了一个 SVG(方便演示和印刷)。
5. 常见问题与排查技巧实录
画了这么多图,最常被问到的问题其实是那几个重复率极高的痛点,我集中整理一下。
5.1 Mermaid 中文乱码怎么办
这个问题十个人有八个人会碰到。核心原因是渲染环境默认字体不含中文字形。如果是部署自己的渲染服务,可以在主题配置里显式指定中文字体;如果是在某个线上平台里渲染,那基本只能靠平台自身的字体设置。我的习惯是:凡是涉及中文的图,导出前先确认渲染端支持,否则就改用拼音或英文关键词来命名节点。
5.2 图太复杂,怎么减负
图一旦复杂到看的人发怵,不是渲染问题,而是信息分层问题。我的处理方式是把一张大图拆成多张小图:架构图只保留模块边界,交互图只画接口关系,部署图只画服务器与进程。每张图只回答一个问题,比一张“什么都想表达”的巨图有意义得多。
另外可以大胆删除低价值节点,比如某些只被一个服务调用的辅助类组件,不影响整体理解的情况下,直接从主图删掉,并在文字说明里补一句“详见代码注释”。
5.3 更新维护跟不上代码演进
图最容易烂的地方,是代码改了图没改。要解决这个问题,技术手段和制度手段得一起上。
技术手段:把图纳入 CI,用脚本比对源文件的变更,发现有改动但没更新图时,直接在合并前提示。制度手段:画图文件的目录和代码目录放在一起,谁动了相关模块,谁就被迫在这个目录下留下一次提交记录。这两招结合在一起,图的保鲜期会明显延长。
5.4 布局被自动排版打乱
Graphviz 的自动布局非常强大,但有时候它排出来的结果并不符合人眼的阅读习惯。遇到这种情况,我会手动调整一个参数:rankdir(方向)、splines(边是否弯曲)、nodesep/ranksep(节点间距)。这三个参数基本决定了整张图的骨架和干净程度。
如果你的图里存在大量跨层连边,优先考虑增加中间节点或使用constraint=false来禁止某些边的排布影响,这样能显著减少连边交叉的混乱感。
6. 从画图到制度化:让图表成为团队资产
单个项目的图再漂亮,也难以沉淀为团队整体能力。要真正把 diagram-design 变成可复用的资产,我推荐从下面三步入手。
6.1 建立组件库和图例规范
把常用的技术组件固定成一套标准视觉符号:数据库、消息队列、网关、服务、定时任务、外部系统,每种都有固定的颜色和边框样式。之后任何人画新图,直接从组件库里取用,不需要重新发明视觉语言。
这一步我建议在最开始就做,不然后期统一风格的工作量远比想象中大。
6.2 把图放进文档生成流水线
在技术文档系统里配置 Mermaid 渲染插件后,写文档时可以直接用三引号围栏写入图表代码,并随文档一起发布。这样图与文档同源,文档更新时图自动跟着变,彻底告别“文档里的图已经过期三个月”的尴尬。
6.3 用 Review 制度守住质量底线
图纸评审和代码评审一样,应当纳入流程。Review 的时候重点不是看样式是否顺眼,而是看语义是否准确:分层对不对、方向有没有反、异常分支有没有漏、低频组件是不是被不必要地突出。这一步看着轻,其实是维持“图永远可信”的关键。
7. 一些实操中的个人体会
这块属于不太会写进规范文档里的经验,但恰恰是最值钱的。
7.1 能删就删,能少就少
每画一个节点之前,都问自己:这张图的读者需要知道这个东西吗?很多时候答案是不需要。删掉一个次要节点,主干链路就更清晰一分。最终交付的图,宁可少画也不可多画,这是我一贯的原则。
7.2 不要追求“一张图搞定所有”
我见过有人试图在一张架构图里同时表达服务拓扑、调用链、部署环境和故障预案,结果就是图密得像电路板。每张图只讲一件事,讲透,就够了。需要全局视角时,就画一张极简的总览图,其他细节按需链接到子图或文档。
7.3 工具是手段,不是目的
选择工具不要被“粉丝数量”影响。Mermaid 再流行,如果团队需要的是严格 UML 建模,那还是 PlantUML 更合适;Graphviz 再强大,如果只是画个简易流程图,那反而是杀鸡用牛刀。工具选型的标准只有一个:它是不是能最轻松地帮你把人脑里的模型变成共识。
最后再分享一个小技巧:画图时永远保留一份纯文本原稿,不管是 Mermaid、PlantUML 还是 dot 格式。哪怕它渲染出来不够好看,或者要经过进一步绘图工具美化,这份源文件都是后续修改、自动生成、团队协作的根。丢掉它,就等于放弃了这张图的演进能力。