1. 从一个空输入说起:为什么"diagram-design"值得单独拎出来聊
第一次看到diagram-design这个标题,正文、关键词、摘要全是空的,我反而觉得这是个特别典型的场景。做技术内容这些年,我见过太多人卡在"图"这件事上——不是不会画,而是画出来的东西自己都不满意,改来改去最后干脆放弃,直接用文字硬讲。架构图、流程图、时序图、状态机图、数据流图,这些词大家都熟,但真正能把一张图设计到"别人看一眼就懂"的程度,其实是个被严重低估的技能。
diagram-design这个标题本身就很直白:它讲的不是某个具体工具怎么用,而是"图的设计"这件事本身。这跟"用某某软件画流程图"是两个层次的问题。工具是术,设计是道。你完全可以用最朴素的工具画出一张让人拍案叫绝的图,也可以用最贵的软件画出一坨谁也看不懂的线团。我见过太多团队,架构文档里塞满了自动生成的图,箭头密密麻麻,颜色五花八门,结果新人看了三天还是不知道系统到底怎么跑起来的。
所以这篇内容我想聊的是:当你手上有一个需要被"画出来"的东西时,从零到一该怎么设计这张图。它适合谁?适合所有需要靠图来沟通的人——后端工程师画架构、产品经理画流程、运维画部署拓扑、学生画课程设计、甚至写文档的人画个示意图。不管你是刚入门的新手,还是画了几年图但总觉得差点意思的老手,这里面的思路都能用得上。核心就一句话:图是给人看的,不是给工具看的,设计图的本质是设计信息传递的路径。
2. 先想清楚"这张图给谁看",再动手画第一根线
2.1 受众决定了图的抽象层级
我踩过最大的一个坑,就是拿到需求就开始画,画完发现方向全错。后来我总结出一条铁律:画图之前,先回答"这张图给谁看"。这个问题的答案会直接决定你画的是哪一层的东西。
给老板看的图,重点是"全局和结论"。他关心的是系统有几个大模块、数据从哪来到哪去、瓶颈可能在哪。你给他画一张标满端口号和线程池参数的部署图,他只会觉得你在炫技。反过来,给运维同事看的部署图,你不标端口、不标机器规格、不标网络分区,他根本没法落地。同样一个系统,给不同人看,图的抽象层级可以差出三四个档次。
我一般会把受众分成三类,对应三种画法:
- 决策层/外部人员:只画业务边界和核心流转,一个方框代表一个子系统,箭头代表数据或请求的流向,不出现任何技术细节。这类图的目标是"30秒内让人明白这是个什么东西"。
- 协作层/同团队工程师:画模块划分、接口关系、关键依赖。可以出现技术名词,但不需要出现具体配置。目标是"让人知道改动会影响谁"。
- 执行层/自己或接手的人:画到组件、服务、端口、存储、调用链路。目标是"照着这张图能复现环境"。
很多人画图翻车,就是因为把这三层混在一张图里。一张图里既有"用户下单"这种业务动作,又有"Redis 连接池 maxTotal=200"这种参数,读者的注意力会被撕碎,最后什么都没记住。
2.2 一张图只讲一件事
这是我从写文档里迁移过来的经验:一张图只讲一件事。如果你发现一张图里既要表达部署拓扑,又要表达请求时序,还要表达数据模型,那它注定失败。
举个具体的例子。假设你要描述一个"用户上传文件后触发处理"的流程。这里面至少有三件事可以画:第一,文件从客户端到存储的物理路径(部署视角);第二,上传接口到处理服务的调用顺序(时序视角);第三,文件状态从"待处理"到"已完成"的变化(状态视角)。这三件事画在三张图里,每张都清清楚楚;硬塞进一张图,就是灾难。
我自己的习惯是,动手前先在纸上写一句话:"这张图要回答的问题是______。"如果这句话超过一行,说明该拆图了。这个习惯帮我省下了大量返工时间。因为一旦你明确了"这张图回答什么问题",后面所有的取舍都有了判断标准——跟这个问题无关的元素,一律不画。
2.3 抽象层级和细节密度的平衡
确定了受众和主题,接下来是细节密度的问题。这里有个反直觉的结论:新手倾向于画得太细,老手倾向于画得太粗,而好的图在中间。
画得太细的典型表现:每个类、每个方法、每个字段都画上去,图大得像一张海报,缩放到能看清字的时候已经看不到全貌了。这种图的问题不是信息不够,而是信息过载,读者找不到重点。画得太粗的典型表现:三个大方框加两根箭头,读者看完还是不知道系统怎么工作。
我的经验法则是"三层展开原则":从最顶层开始,往下展开不超过三层。比如"系统 → 子系统 → 模块",到模块这一层就停,模块内部的类和方法不画,用文字补充。如果某个模块特别关键,单独为它画一张展开图,而不是在主图里往深了钻。这样主图保持清爽,细节图按需深入,读者可以按自己的需要选择看哪张。
3. 选对图的类型,比画得漂亮重要一百倍
3.1 常见图类型的适用边界
很多人画图不好看,根本原因不是审美问题,而是用错了图类型。拿流程图去表达时序,拿时序图去表达结构,怎么画都别扭。我把常用的几类图整理成一张表,方便对照:
| 图类型 | 最适合表达 | 典型误用 | 关键元素 |
|---|---|---|---|
| 流程图 | 有分支的业务逻辑、审批流 | 表达并发调用 | 判断菱形、开始结束圆角矩形 |
| 时序图 | 多个角色之间的调用顺序 | 表达静态结构 | 生命线、消息箭头、激活条 |
| 架构图 | 系统的模块划分与依赖 | 表达运行时序 | 分层方框、依赖箭头 |
| 状态机图 | 一个对象的状态流转 | 表达多对象交互 | 状态圆角框、迁移箭头、事件标签 |
| 数据流图 | 数据在系统中的流转与加工 | 表达控制流 | 加工圆、数据存储、外部实体 |
| ER图 | 数据实体与关系 | 表达业务流程 | 实体矩形、关系菱形、基数标注 |
这张表我建议存下来,每次画图前扫一眼。选对类型,图就成功了一半。选错类型,后面再怎么优化都是事倍功半。
3.2 为什么时序图最容易被画错
时序图是我见过被误用最多的图类型。很多人把时序图画成了"带时间轴的架构图",把一堆不相关的组件全塞进去,箭头乱飞。时序图的核心是顺序,它回答的是"谁先调用谁、谁等谁、谁和谁并行"。
画时序图有个关键技巧:只画参与这次交互的角色。如果某个组件在这次交互里只是被路过,不参与实际的消息传递,就不要画。我见过一张时序图里画了十几个角色,结果真正有消息往来的只有四个,剩下八个是"背景板",纯属干扰。
还有一个细节:激活条(那个细长的矩形)要画准。激活条表示"这个角色正在处理",它的长度应该反映处理时间的长短。如果两个角色的激活条重叠,说明它们在并行处理;如果一个角色的激活条在另一个的消息箭头之后才开始,说明是串行。这个细节很多人忽略,但恰恰是时序图最有价值的信息。
3.3 架构图的分层画法
架构图最容易犯的错是"平铺"——所有模块画在一个平面上,箭头横七竖八。正确的做法是分层。典型的分层是:接入层、应用层、服务层、数据层。每一层内部放对应的模块,层与层之间用统一的箭头方向连接。
分层的好处是读者可以快速定位。他看到一个问题,第一反应是"这是接入层的问题还是数据层的问题",而不是在一堆平铺的方框里找。我画架构图时有个习惯:同一层的模块用同一种颜色或同一种边框样式,这样即使不看文字,也能一眼看出层次。
另外,架构图里的箭头要区分类型。依赖、调用、数据流向,这三种关系用不同的线型或颜色区分。我一般用实线表示同步调用,虚线表示异步消息,带箭头的粗线表示数据流向。这个约定一旦建立,读者看图的效率会大幅提升。
4. 视觉编码:颜色、形状、布局背后的信息逻辑
4.1 颜色不是装饰,是分类工具
新手画图喜欢用颜色"让图好看",老手用颜色"让图好懂"。这两者的区别是:装饰性颜色是随机的,分类性颜色是有语义的。
我的颜色使用原则是:同一种颜色只代表同一类事物。比如所有"存储"相关的模块用蓝色,所有"计算"相关的用绿色,所有"外部依赖"用灰色。这样读者看到蓝色就知道是存储,不需要每次去读文字。颜色数量控制在四到五种以内,超过五种人眼就分不清了,反而增加认知负担。
还有一个坑:不要用颜色表达程度。比如用深浅表示"重要程度",读者很难判断"这个深蓝比那个浅蓝重要多少"。程度用大小、粗细、位置来表达更直观。颜色只用来做分类,不做程度。
4.2 形状承载语义
形状和颜色一样,应该承载语义。常见的约定是:矩形表示模块或服务,圆角矩形表示过程或状态,菱形表示判断,圆柱表示数据库,云形表示外部系统。这些约定不是强制的,但一旦你在图里用了,就要全图统一。
我见过一张图里,数据库一会儿用圆柱,一会儿用矩形,一会儿用带横线的矩形,读者根本分不清哪个是数据库。统一形状的成本很低,但收益很高。如果你觉得标准形状不够用,可以自定义,但要在图例里说明。图例是图的说明书,很多人省略图例,结果读者只能靠猜。
4.3 布局的阅读动线
布局决定了读者的阅读动线。人眼习惯从左到右、从上到下阅读,所以图的布局应该顺应这个习惯。流程类的图,主流程从左到右或从上到下;架构类的图,调用方在上,被调用方在下。
有个细节很多人不注意:箭头的方向要尽量一致。如果一张图里箭头一会儿向左一会儿向右,读者的视线会来回跳,很累。我画图时会尽量让主流程的箭头方向统一,反向的箭头(比如回调、响应)用不同颜色或虚线区分,减少视觉干扰。
还有,留白是设计的一部分。新手喜欢把图填满,觉得空着浪费。其实留白让图有呼吸感,模块之间的间距均匀,读者更容易分辨"哪些是一组"。我一般会让模块间距至少是模块宽度的三分之一,这样分组关系一目了然。
5. 从草图到成品:一套可复用的画图工作流
5.1 先用纸笔,别急着开软件
这是我最想强调的一点:先用纸笔画出草图,再打开画图软件。原因很简单,纸笔的修改成本几乎为零,你可以快速试错。而一旦打开软件,你会不自觉地开始调对齐、调颜色、调字体,把大量时间花在"美化"上,而核心的结构问题反而被掩盖了。
我的工作流是这样的:先在纸上画三到五个版本的草图,每个版本尝试不同的布局和抽象层级。画完对比一下,哪个版本最能回答"这张图要回答的问题",就选哪个。这个过程通常不超过二十分钟,但能省下后面几个小时的返工。
草图阶段只画方框和箭头,不写具体文字,用代号代替。这样你的注意力全在结构上,不会被文字细节带偏。等结构定了,再往软件里搬。
5.2 软件里的"先骨架后血肉"
进了软件之后,我的顺序是:先摆骨架,再填内容,最后调样式。
骨架就是所有模块的位置和主要连接。这个阶段只用最朴素的矩形和直线,不调颜色不调字体。骨架摆好之后,退后一步看整体,检查布局是否平衡、箭头是否清晰、有没有明显的交叉。
骨架没问题了,再填文字。文字要精炼,能用两个词说清楚的不用一句话。模块名用名词,箭头标签用动词。比如"订单服务 → 支付服务"上面标"发起支付",而不是"订单服务调用支付服务进行支付操作"。
最后才是调样式。颜色、字体、线型,这些是锦上添花,不是雪中送炭。我见过太多人把顺序搞反,先调样式,结果结构一塌糊涂,再好看也没用。
5.3 自检清单:一张图发布前的最后检查
图快画完的时候,我会用一份自检清单过一遍。这份清单帮我拦下了很多低级错误:
- 受众检查:这张图给目标受众看,他们能看懂吗?有没有出现他们不熟悉的术语?
- 主题检查:这张图只讲了一件事吗?有没有混入无关信息?
- 方向检查:箭头方向是否一致?有没有让人迷惑的反向箭头?
- 颜色检查:颜色是否只用于分类?有没有用颜色表达程度?
- 文字检查:模块名是否都是名词?箭头标签是否都是动词?有没有错别字?
- 图例检查:如果用了自定义符号,图例里说明了吗?
- 缩放检查:把图缩小到50%,还能看清主要结构吗?
这份清单看起来琐碎,但每一条都对应着我踩过的坑。尤其是最后一条"缩放检查",很多图在100%大小下看着挺好,一缩小就糊成一团,说明信息密度太高,需要精简。
6. 那些年我画图踩过的坑
6.1 追求"大而全"导致重点丢失
早期我画架构图,总想着"把所有东西都画上去,这样才完整"。结果图画得巨大,A0纸都打不下,读者看完只记得"东西很多",记不住任何重点。后来我明白了一个道理:图的完整性和可读性是矛盾的,你必须在两者之间做取舍。
我的做法是:主图只画核心链路,把非核心的部分折叠成一个方框,标注"其他模块详见XX文档"。这样主图保持清爽,需要细节的人可以去看文档。图的作用是建立整体认知,不是替代文档。
6.2 箭头交叉成蜘蛛网的解法
箭头交叉是画图绕不开的问题。当模块多了,箭头难免交叉。我的解法有三个层次:
第一,调整模块位置。很多时候交叉是因为模块摆放不合理,把相关的模块放近一点,交叉就少了。这个最简单,优先用。
第二,用颜色区分不同链路的箭头。如果两条链路必须交叉,用不同颜色区分,读者可以顺着颜色追踪。
第三,拆图。如果交叉实在太多,说明这张图承载的信息超了,该拆成两张。拆图不是失败,是设计。
我见过有人为了不交叉,把模块摆成各种奇怪的角度,结果图变得很别扭。其实适度的交叉是可以接受的,只要不影响追踪。不要为了消除交叉而牺牲布局的自然性。
6.3 文字标签的"动词名词"陷阱
这个坑很隐蔽。很多人写箭头标签时,习惯写"调用""依赖"这种动词,但写模块名时,又写成"调用订单服务"这种动宾结构。结果整张图里名词和动词混在一起,读者分不清哪个是模块哪个是动作。
我的规则很简单:模块名一律用名词,箭头标签一律用动词。"订单服务"是模块,"发起支付"是动作。这样读者看到方框就知道是模块,看到箭头上的字就知道是动作,不需要额外判断。
还有一个细节:箭头标签要放在箭头的上方或右侧,不要压在箭头上。压在箭头上会让文字和线重叠,很难读。这个是小细节,但影响很大。
7. 让图"活"起来:版本管理与协作中的图
7.1 图也要进版本控制
很多人把图当成一次性产物,画完导出PNG就完事。结果系统改了,图还是旧的,文档和图对不上,新人看了更迷糊。我的做法是:图的源文件也要进版本控制,和代码一起管理。
现在很多画图工具支持文本格式的源文件(比如用代码描述图的结构),这种格式特别适合进Git。每次系统变更,同步更新图源文件,提交记录里能看到图的演变。这样图永远不会"过期",因为它和代码是同步演进的。
即使你的工具不支持文本格式,至少要把源文件(不是导出的图片)存进仓库。导出图片只用于展示,源文件才是"真相"。
7.2 图里的"变更标记"
在协作场景里,图经常需要标注"哪里变了"。我的做法是用颜色或边框标记变更部分。比如新增的模块用绿色边框,修改的用黄色,删除的用灰色虚线。这样评审的人一眼就能看到变更点,不需要对比新旧两张图。
这个技巧在架构评审、方案评审里特别有用。评审时间宝贵,让评审人快速定位变更点,能大幅提升评审效率。我一般会在图旁边附一句话说明:"本次变更涉及三个模块,分别是……",图和文字配合,信息传递效率翻倍。
7.3 图与文档的配合
图不是孤立的,它通常嵌在文档里。图和文档的配合有个原则:图负责建立整体认知,文档负责补充细节。图里不出现的细节,文档里要能查到;文档里的关键结论,图里要能对应上。
我写文档时,习惯在图的下面加一段"图注",说明这张图回答什么问题、有哪些关键点、哪些细节在文档的其他章节。这样读者看图时知道该关注什么,看文档时知道该对应哪张图。图和文档形成闭环,信息传递才完整。
8. 工具选择:别让工具绑架了设计
8.1 工具的分类与选择逻辑
画图工具大致分三类:代码驱动型(用文本描述图,如各类DSL工具)、拖拽型(手动摆放,如各类在线画图工具)、自动生成型(从代码或配置自动生成图)。
选择逻辑很简单:看图的更新频率。如果图经常变,选代码驱动型,改文本比拖拽快得多,而且能进版本控制。如果图基本不变,选拖拽型,自由度更高。如果图是从代码自动生成的(比如依赖关系图),选自动生成型,省得手动维护。
我自己的组合是:架构图和流程图用代码驱动型,因为经常变;示意图和演示图用拖拽型,因为要精细控制样式。没有哪个工具是万能的,关键是匹配场景。
8.2 别在工具上过度投入
我见过有人花大量时间研究画图工具的各种高级功能,结果图本身画得一般。工具是手段,不是目的。一张用最朴素工具画的好图,胜过一张用高级工具画的烂图。
我的建议是:选一个顺手的工具,把它的核心功能用熟,就够了。剩下的时间花在"想清楚画什么"上,收益大得多。工具的高级功能(比如自动布局、智能对齐)确实能省时间,但它们解决的是"画得快"的问题,不是"画得好"的问题。
8.3 导出格式的取舍
导出格式也有讲究。PNG适合展示,但不支持缩放;SVG支持缩放,适合嵌入网页;PDF适合打印。我的习惯是:源文件 + SVG + PNG 三件套。源文件用于编辑,SVG用于嵌入文档和网页,PNG用于快速分享。
如果图里有大量文字,导出时要注意字体嵌入。有些工具导出的SVG在别的机器上打开会字体错乱,就是因为字体没嵌入。这个坑我踩过,后来养成了导出后换台机器验证的习惯。
9. 一些让图更"专业"的细节
9.1 对齐与间距的强迫症
对齐和间距是图"看起来专业"的关键。模块没有对齐,间距忽大忽小,图就会显得业余。我的做法是:用网格对齐,所有模块的边都落在网格线上。间距用统一的数值,比如模块间距统一为20像素,组间距统一为40像素。
这个习惯一开始会觉得麻烦,但养成之后,画图速度反而更快,因为不需要反复微调位置。而且对齐的图,读者阅读时视线移动更顺畅,信息吸收效率更高。
9.2 字体的选择
字体选择的原则是:可读性优先,风格其次。正文用无衬线字体(如各类黑体),标题可以稍粗。字号要统一,同一层级的模块用同一字号。不要在一张图里用超过两种字体,那会显得很乱。
还有一个细节:中英文混排时注意字体搭配。有些字体中文好看但英文难看,有些反之。如果图里有中英文混排,选一个中英文都好看的字体,或者中英文分别设置字体。这个细节很多人忽略,但影响观感。
9.3 图例与注释的位置
图例放在图的角落,通常是右下角或左下角,不要放在中间挡视线。注释放在相关模块的附近,用引线连接,不要离得太远。如果注释很多,考虑用编号,图下方统一列出编号对应的说明。
我一般会把图例做得简洁,只列出自定义符号和颜色的含义,标准符号(如矩形、箭头)不列,因为读者默认就懂。图例太啰嗦反而增加阅读负担。
10. 从"能看"到"好懂":图的迭代与反馈
图画完不是终点,拿给别人看,收集反馈,再迭代,这才是让图变好的关键。我每次画完重要的图,都会找一两个目标受众之外的人看,问他们"这张图讲了什么"。如果他们说的和我想表达的不一致,说明图有问题。
收集反馈时,不要问"你觉得这张图怎么样",这种问题得到的回答通常是"挺好的"。要问具体的问题:"你能告诉我数据从哪流到哪吗""你觉得哪个模块是核心""有没有哪里你看不懂"。具体的问题才能得到有用的反馈。
迭代的时候,优先解决"看不懂"的问题,其次解决"不好看"的问题。看不懂是硬伤,不好看是软伤。硬伤必须改,软伤可以慢慢优化。
我个人的体会是,一张好图通常要迭代三到五轮。第一轮解决结构,第二轮解决细节,第三轮解决样式,后面几轮解决边角问题。不要指望一次画好,迭代是常态。每次迭代都问自己"这张图比上一版好在哪里",如果答不上来,说明这轮迭代没价值。
最后分享一个小技巧:把图打印出来看。屏幕上看和纸上看的感觉不一样,纸上更容易发现布局问题。我习惯把图打印成A4大小,贴在墙上,隔几米远看,如果还能看清主要结构,说明图的层次是清晰的。这个土办法帮我发现了很多屏幕上看不出来的问题。