去年做技术评审,我花了三个小时画了一张系统架构图,投影出来之后,前端组长盯着看了十秒钟,问了一句:“所以你画的这条虚线箭头,到底是调用还是消息推送?”
那一瞬间我意识到一个问题——很多人画 diagram 只是把脑子里的信息“倒”到画布上就完事,压根没想过“设计”。但 diagram-design 这件事,本质上是把抽象关系翻译成视觉关系,让看图的人在最短时间内建立起和画图人一致的心理模型。翻译得差,图就是噪音;翻译得好,图就是文档里最值钱的部分。
这篇文章不打算罗列某个工具的上百个快捷键,而是想从 diagram-design 的完整链路出发,讲清楚我在一次次评审、文档编写、团队协作中沉淀下来的方法论:动手之前想什么、工具怎么选、视觉规范怎么定、落地实战有哪些坑。适合正在写技术文档的工程师、要做方案汇报的架构师、以及所有需要“画一张讲得清楚的图”的人。
1. 先搞明白:一张好图不是信息堆砌,而是视觉翻译
1.1 信息层级:一张图只能有一个主角
很多图乱,第一个原因就是想表达的东西太多。系统里有十来个服务、七八条链路、五六个存储,恨不得一个不落全画上去。结果就是满画布都是方框,谁都不突出,谁都可以被忽略。
我自己的经验是,动笔之前先问一句:这张图的主角是谁?如果是核心调用链,那存储和配置中心就该弱化;如果是部署拓扑,那业务链路就该简化成一条粗箭头。主角只能有一个,其他全是背景。
具体操作上,可以给图里的元素分三个层级:核心链路用深色、粗线条、大尺寸;支撑模块用中性色、正常尺寸;外围依赖用浅色、小尺寸、甚至淡化成背景。看的人第一眼落在核心链路上,第二眼扫到支撑模块,第三眼才去读外围依赖。这个视觉顺序一旦建立,图的表达能力立刻上一个台阶。
1.2 读者决定细节密度
同样一张订单系统架构图,给CTO看和给刚入职的应届生看,画法完全不一样。
给决策者看,要突出的是“这个方案分几块、数据怎么流动、瓶颈在哪”,细节越少越好,最好能压缩成一页。给新同学看,要画清楚每个模块的职责、每个接口的出入参、异常处理往哪走,这时候图可以拆成多张,甚至一张图画不下就按子系统拆分。
我踩过的坑是:一张图想同时满足所有人,于是加了大量注释和分支,结果汇报时被说“太啰嗦”,给新人培训时又被说“看不懂”。后来我养成了一个习惯,画图前先写一句话——这张图是给谁看的,他要从中获得什么信息?如果答不上来,就先别打开画图工具。
1.3 载体决定画法:PPT、文档、白板、大屏不是一回事
同样一张图,放在PPT里和在文档里、在白板上现场画、投到大屏上,设计逻辑完全不同。
PPT里的图是“讲”出来的,元素要少,字号要大,最好能一个动画一个动画地出现,跟着讲解节奏走。文档里的图是“读”的,可以承载更多细节,但要有清晰的分区和编号,方便读者跳着看。白板上的图是“长”出来的,得从左上角开始画,边画边讲,所以结构要线性,不能一开始就铺满整个板面。大屏上的图则是“播”的,要考虑远距离观看,线条要粗,对比要强,细枝末节一概不要。
2. 动手之前,先回答四个问题
2.1 这张图的目的是解释、说服还是记录
这个分类比想象中重要。解释型图的目标是让读者理解一个概念或流程,比如“消息队列是怎么工作的”,重点在因果和顺序。说服型图的目标是推动决策,比如“为什么要引入新的缓存方案”,重点在对比和收益。记录型图的目标是沉淀事实,比如生产环境的部署架构,重点是准确和完整,哪怕牺牲一点美观。
不同目的决定了图的取舍方向。解释型图可以适当牺牲精确性换取直观,比如把复杂的重试机制简化成一个循环箭头。说服型图要突出“前后对比”和“关键指标”,可以用不同颜色把优化前后的路径标出来。记录型图则要把每个组件的版本、数量、连接方式都写清楚,这种图往往追求完整,但读起来会比较累。
我见过很多团队把记录型图画得像解释型,一堆箭头、一堆颜色,结果运维照着部署时发现少画了一个端口映射。这类事故的根源就是:画图的人没有搞清楚这张图到底是干嘛用的。
2.2 核心链路是什么
任何系统都能拆出一条主链路,比如“用户请求→网关→服务A→数据库→返回”。这条链路是整张图的骨架,其他一切都是围绕它展开的。
确定核心链路之后,先把它画出来,再逐步往外扩展。这个过程有点像写文章先列大纲——大纲立住了,细节往里面填才不会乱。如果发现核心链路本身有两条甚至三条,那说明这张图该拆了,要么拆成多张,要么把非核心的那条降级成虚线标注。
从实操来看,90%的混乱图都是因为核心链路不清晰。读者盯着密密麻麻的箭头,无法判断哪条是主路、哪条是旁路,自然就“看不懂”。
2.3 边界画到哪里
很多图之所以画不完,问题出在边界上。
画一个订单系统,要不要把上游的支付网关画进来?要不要把下游的物流系统画进去?把相关方全画进来,图就失控了。我的建议是:只画“本图要讨论的范围”,范围之外的东西用一个“外部系统”灰色框打包处理。
打个比方,画房间的平面图,只需要把墙画清楚,不需要把隔壁邻居家的家具也画进来。边界明确之后,图就能收敛,读者也能清楚地知道“这张图只管这一段”。
2.4 异常路径怎么处理
正常流程画完之后,异常路径是很多人的噩梦。超时、重试、降级、熔断,全画上去,图就花了;不画,又显得不严谨。
我的做法是:主流程画全,异常路径用统一的虚线+小红点标注,在图的角落配上编号注释。比如在主链路的某个调用旁标一个“①”,图底部写“①:超时重试3次,仍失败则降级返回缓存”。这样既保留了异常信息,又不破坏主流程的视觉连续性。
3. 工具选型:没有最好的画图工具,只有最匹配的场景
3.1 代码生成型工具:Mermaid、PlantUML、D2
代码生成型工具的特点是“用文本描述图结构”,改起来快,天然支持版本管理,适合放在仓库里和代码一起维护。
Mermaid 语法简单,渲染出来的图风格清新,是目前技术文档里最常见的选择。PlantUML 更老牌,UML 支持最全,时序图和用例图表现力强,但默认样式比较陈旧。D2 是后起之秀,语法更现代,布局引擎也更聪明,连线交叉问题比前两者少。
这类工具的共同弱点是布局可控性差。你想把一个节点放在画布正中间、把另一个节点放在它右下方,代码生成工具不一定听你的,因为布局由算法决定。所以代码生成型工具适合“结构清晰、层级明确”的图,比如模块划分、时序交互、ER关系,不适合“强排版要求”的视觉型图。
我用文本的方式演示一个简单的结构描述,方便你理解这类工具的输入长什么样:
核心服务(用户服务)──> 存储层(MySQL) 核心服务(用户服务)──> 缓存层(Redis) 核心服务(用户服务)──> 消息队列(Kafka) └─ 外部依赖(风控服务,虚线箭头标注)这段文本渲染出来,就是一张带箭头的简单模块图。改起来很快,想加一个节点就多写一行,想改连线就改箭头方向。这类工具的核心理念是“图即代码”,图跟着代码评审走,跟着提交记录走。
3.2 手动拖拽型工具:Draw.io、Excalidraw、FigJam、OmniGraffle
手动拖拽型工具把布局控制权完全交给你,想放哪就放哪,所见即所得。
Draw.io 免费、功能全、支持本地文件,适合画严肃的架构图和网络拓扑图。Excalidraw 走手绘风格,画出来的图有一种天然的“草稿感”,反而降低了读者的心理压力,适合方案讨论和快速原型。FigJam 是 Figma 家的白板工具,多人协作体验很好,适合线上工作坊。OmniGraffle 是 macOS 上的老牌工具,模板丰富,风格偏设计向,但价格不便宜。
手动拖拽工具的劣势也明显:排版全靠手调,一旦图的规模变大,对齐和维护会花掉大量时间。而且文件格式通常是私有的,不方便直接做文本 diff。
3.3 我的选型建议
| 场景 | 推荐工具 | 理由 |
|---|---|---|
| 技术文档、README、Wiki | Mermaid | 文本即图,版本管理友好,渲染快 |
| UML、时序图、用例图 | PlantUML | UML 支持完整,语法成熟 |
| 复杂架构图、网络拓扑 | Draw.io | 免费、离线、功能全面 |
| 方案讨论、快速原型 | Excalidraw | 手绘风降低正式感,脑暴友好 |
| 团队在线协作白板 | FigJam | 多人实时编辑,音频/便签一体 |
| 设计稿级别的架构图 | OmniGraffle / Figma | 排版自由度最高,适合对外汇报 |
工具只是手段,不是目的。我见过用 Excalidraw 画生产环境架构图的团队,也见过用 Mermaid 画得很精致的团队。关键是选一个你愿意长期用、团队里其他人也能上手的,别把时间耗在工具切换上。
4. 一套能直接抄走的 diagram 视觉规范
4.1 对齐与间距:干净感的来源
很多人觉得“高手画的图干净”,其实就是对齐和间距做得好。元素之间对齐、间距统一,哪怕配色一般,看起来也会舒服。
实际操作中,我习惯把画布设置为网格对齐,所有方框的尺寸取偶数,间距保持 8 的倍数。比如两个模块之间留 8px、16px、24px,不要出现 13px、17px 这种随意间距。模块内部文字与边框之间至少留 8px 的 padding,避免文字贴边。
还有一个很容易被忽略的细节:同一层级的方框,宽度尽量保持一致。一行排四个服务,如果每个宽度都不一样,视觉上会特别碎。先拖一个基准框,复制四个,再改文字,这比一个个去画要快得多。
4.2 配色:别超过三个主色,语义必须一致
配色是图中最容易翻车的地方。红、黄、蓝、绿、紫全上,图立刻像游乐场。
我推荐的配色方案是:一个主色(用来标记核心链路或重点模块)+一个中性色(灰色系,用来画支撑模块)+一个强调色(用来标记异常、告警或需要注意的点)。如果需要表示“已上线/规划中/已废弃”之类的状态,可以在这个基础上增加对应的状态色,但每种状态色只允许出现在状态标签上,不参与模块染色。
另外,同一张图里同一个颜色只能表示同一个含义。如果橙色代表“用户端”,那所有用户端相关的模块都必须用橙色,不能这个用橙色、那个用紫色。颜色语义一旦混乱,读者就会反复确认,图的效率就大打折扣。
4.3 形状与线条:别自创语法
画 diagram 时,形状是有默认语义的。矩形代表模块或系统,圆角矩形代表服务或操作,菱形代表判断或路由,圆柱代表数据库,平行四边形代表数据或消息。这些默认语义不是谁规定的,而是读者看多了之后形成的思维惯性。
如果你用的形状和默认语义不一致,读者就会困惑。比如用菱形表示一个普通服务,别人会下意识觉得这是一个判断节点。
线条同样有语义。实线代表确定的关系,虚线代表弱关联或异步,箭头代表数据流向或调用方向。最忌讳的是全图都用同一种带箭头的实线,没有任何粗细和虚实变化,读者只能靠猜。我的做法是:主调用链路用粗实线,异步/消息用细虚线,配置关联用不带箭头的细实线,这样一眼就能区分出不同类型的关系。
4.4 字体与字号:也是信息层级的一部分
中文技术图里,字体建议用系统默认的无衬线体,比如苹方、微软雅黑、思源黑体;代码块和接口名建议用等宽字体,比如 JetBrains Mono、Consolas。
字号至少分三档:图标题最大,比如 18~20px;模块名次之,14~16px;注释和标签最小,12px。小于 12px 的文字在投影或 PDF 导出时基本看不清,尽量避免。
同时注意,模块名不要超过 6~8 个字。名字太长就换行或者精简,否则框图看起来会非常笨重。接口名这类专业术语可以保留全称,但要考虑是否需要做视觉降噪,比如用灰色字体弱化。
5. 实战:从 0 到 1 设计一张系统架构图
5.1 先用文本把结构列出来,不要急着开画图工具
大多数人画图的错误开头是:打开工具,拖一个框,起个名字,再拖一个框,起个名字……画着画着发现布局不对,又全部推翻。
更高效的做法是先在文本编辑器或纸上把结构列出来。以“用户订单查询链路”为例,我会先写下:
客户端(App/Web) ↓ 接入层(API Gateway) ↓ 订单服务 ├── 读缓存(Redis) ├── 查数据库(MySQL 从库) └── 异步写日志(Kafka → 日志服务) 外围依赖:用户服务(账号校验)、风控服务(虚线关联)这一步的价值在于:结构在文字层面先得到确认,进入画图阶段后只需要关心布局,不再需要思考逻辑关系。文本结构列得越清楚,画图越快。
5.2 确定主视觉流向
拿到文本结构后,先确定主流向。大多数架构图适合“从上到下”或“从左到右”的流向。
从上到下适合分层结构,比如“接入层→业务层→数据层”;从左到右适合链路结构,比如“客户端→网关→服务→存储”。流向一旦确定,整张图的阅读顺序就固定了,读者不用上下左右来回找。
我倾向于优先选“从上到下”,因为和人们看文档的习惯一致。遇到特别长的链路,再转成从左到右。
5.3 从草稿到成图的细化过程
第一步,把核心链路的三四个模块先摆到画布上,按主流向排好。先不急着连箭头,把间距和对齐调好,保证这几个模块在视觉上是一个整体。
第二步,加支撑模块。把缓存、消息队列、依赖服务放到核心链路的两侧,用虚线或浅色连接。注意不要让支撑模块的连线穿到主链路的中间位置——保持核心链路区域尽量干净。
第三步,标注关键信息。比如在数据库模块上加“读写分离”、在消息队列模块上加“Topic 命名规范”,用注释文本放在模块旁边,而不是直接改模块标题。
第四步,处理异常路径。用统一的标号方式(比如红色小圆圈数字)标注重试、降级、熔断等行为,在图底部或右侧放一个“备注”区域统一说明。
5.4 成图之后的六个自检项
画完之后,我一般会按这个清单过一遍:
- 只看一眼:秒回核心链路是哪个吗?
- 颜色语义:同一种颜色是不是全程代表同一个含义?
- 线条语义:实线、虚线、箭头有没有混用或误用?
- 文字可读:导出 PNG 后,最小字号贴到屏幕上还看得清吗?
- 边界清晰:范围外的东西是不是都收进“外部系统”灰框了?
- 自洽完整:图中引用的服务名、端口号、Topic 名和实际代码/配置对得上吗?
其中最后一条最容易被忽视。图里的服务名和代码里不一致,是技术文档里非常低级但高频的错误。
6. 画图过程中容易翻车的细节
6.1 导出模糊:分辨率和格式的坑
画好的图要放进文档或PPT,最常见的翻车是导出模糊。
如果你用的是 Draw.io 或 Figma 这类矢量工具,导出时优先选择 SVG 或较高倍率的 PNG。我的建议是导出 2x 甚至 3x 的 PNG,或者直接嵌 SVG,这样无论显示在手机还是高分辨率大屏上都不会虚。不要直接截图粘贴,截图的清晰度取决于屏幕分辨率,很容易糊。
另一个坑是透明背景和白色背景。深色模式下,透明背景的图显示会很好看;但白底文档里,带深色底的 SVG 反而会一团黑。建议在导出时确认一下目标文档的底色,再决定导出配置。
6.2 中文与特殊字符乱码
Mermaid 和 PlantUML 这类代码生成工具,处理中文时偶尔会出现乱码或排版异常。尤其是 PlantUML 依赖本地的字体渲染,如果服务器或本地环境没有正确配置中文字体,生成图片时中文就会变成方框。
解决方案无非两条:一是环境层面安装并配置好中文字体(比如 Noto Sans CJK);二是尽量减少图里的中文,关键术语保留英文,模块名用中文做辅助说明。还有一点,某些工具对特殊字符(如_、|、>)敏感,文本里如果包含这类字符,需要转义或改成全角写法,否则解析时会断线。
6.3 连线交叉与绕路:版面乱的最大元凶
连线交叉之后版面必乱,这是所有画图人的共识。尤其架构图里模块一多,连线就像蜘蛛网,谁也看清。
减少交叉的方法有几个:一是把关系紧密的模块放在相邻位置,长连线少,交叉自然少;二是利用“聚合线”或“总线条”,多条同类关系合并成一条粗线,到目标区域再分叉;三是重新考虑布局方向,从上到下太挤,就换从左到右。
如果必须交叉,尽量让交叉点落在空白区域,不要在模块上交叉。交叉点上加一个小圆弧或桥接符号,能显著降低“线缠在一起”的错觉。
6.4 图也要纳入版本管理
很多团队文档仓库里只管代码,图是散落在个人电脑里的在线草稿,一换人全丢了。
图如果用了代码生成工具,直接随仓库维护就行,改图等于改代码,diff 一目了然。如果用了手动拖拽工具,至少把源文件存到团队共享的云盘或 Git LFS 中,同时导出一份 PDF 或 PNG 作为快照。我更推荐前者——代码生成工具有天然优势。
7. 让图“活”起来:组件库、图层与团队协作
7.1 图层思维:从“画一张图”到“管理整张图”
复杂系统一张图画不下,就要拆图层。不是绘图软件里的 Layer,而是逻辑上的“视图层”。
比如一个微服务架构,可以拆成“部署视图”“调用视图”“数据视图”三张图。每一张图只讲一个维度,读者可以按需查阅,而不是面对一张超复杂总图。这个思路在 C4 model 里用得最系统,我也在实际项目里验证过它的价值——画图的人好维护,看的人好理解。
7.2 团队组件库:别再每个人各画各的
团队里如果每个人都按自己的审美画图,那文档仓库里的图风格会乱七八糟。有的用蓝底,有的用绿底,有的用圆角,有的用直角,读者跳着看会非常分裂。
组件库也分代码型和视觉型两种。代码型组件库,是把常见模块的文本模板沉淀下来,比如“标准服务节点”“MySQL节点”“Redis节点”,用的时候复制粘贴改名字就行。视觉型组件库,是在 Figma 或 Draw.io 里定义好一套主色、字号、图形模板,团队成员统一从这里拖。
7.3 从静态图到交互原型:进阶但不一定必要
图做得好的人,最后往往会想:能不能做成可交互的架构图?比如点击某个服务节点,能看到它的详细指标。
如果团队有精力,这确实很酷。但我要泼一盆冷水:交互图维护成本很高,如果不是客户演示或高管驾驶舱这类强需求,没必要一上来就做。先用好静态图,把静态图的结构、规范、版本管理做到位,性价比远高于追求交互。
我在实际项目中见过太多团队卡在“把图做酷炫”上,却连最基础的视觉一致性都没解决。先把基本功打牢,再考虑炫技。
我自己画了这几年图,最大的感受是:diagram-design 的本质不是“画得好看”,而是“让人少费劲”。一张好的图能省掉一小时的会议讨论,一张烂图能引发一整轮的口水战。每次画完图,我都会问自己一句:如果我是第一次看这张图的人,我需要花多长才能看出它想说什么?答案超过十秒,就继续改。也希望你画的每一张图,都能让别人觉得“这个系统我好像一下子就懂了”。