1. 从一张草图到一套系统:diagram-design 到底在解决什么问题
第一次看到 “diagram-design” 这个标题,很多人会以为它只是教你怎么画流程图、时序图或者架构图。但真正做过技术方案、写过设计文档、跟产品运营吵过需求的人会明白,图只是表象,背后真正要解决的是信息结构混乱、沟通成本高、方案难以复用这三座大山。我做了十多年一线开发和技术方案,画过的图少说也有几千张,踩过的坑包括但不限于:图里少了一个关键模块导致开发返工、箭头方向画反导致数据流向理解错误、配色太花导致评审时没人看得清重点。这些问题看起来是“画图技巧”问题,实际上是一套设计表达系统缺失的问题。
diagram-design 这个项目,我的理解是:它不是一个单纯的绘图工具教程,而是一套从需求拆解、结构抽象、视觉编码到交付复用的完整方法论。它适合谁?适合所有需要把脑子里的复杂逻辑外化成别人能看懂的东西的人——后端开发要画服务依赖,产品经理要画状态流转,运维要画部署拓扑,甚至运营要画活动流程。你不需要是设计师,但你需要知道为什么有的图一眼就懂,有的图看三遍还在猜。
这篇文章我会从整体设计思路、核心细节、实操过程、常见问题四个维度,把 diagram-design 拆开揉碎。所有内容基于我实际项目中的做法,结合常见工具链的合理实践,给出可以直接抄作业的方案。全文不会出现任何具体公司名、人名或真实项目名,案例全部用虚构代称。
2. 整体设计思路:为什么你的图总是“差点意思”
2.1 先想清楚图的“读者”是谁,再决定怎么画
很多人画图的第一反应是打开工具,拖几个框,连几条线,然后觉得“差不多就行了”。但 diagram-design 的核心逻辑恰恰相反:先定义读者,再定义信息层级,最后才动手画。我见过一个典型的反面案例:某开发同学给运维团队画部署架构图,把代码里的类名、方法名全标上去了,结果运维看完只说了一句“我就想知道哪台机器挂了会影响哪个服务”。这就是读者错位。
我的做法是,在动手之前先问三个问题:这张图给谁看?他们最关心什么?看完之后他们要做什么决策?如果是给开发看的数据流图,那重点就是字段映射和异常分支;如果是给领导看的整体架构,那重点就是模块边界和关键依赖。把这三个问题答案写在一张便签上,贴在屏幕旁边,画的过程中随时对照。这个习惯让我少返工了至少一半的图。
2.2 结构抽象:从“有什么”到“分几层”
diagram-design 里最值钱的部分,我认为是分层抽象的思路。不管什么图,先别急着画细节,而是把信息分成三到四层。以最常见的系统架构图为例:
- 第一层:上下文层。这张图在整个系统里的位置,外部依赖是什么,用户从哪进来。
- 第二层:容器层。系统由哪几个可独立部署的单元组成,比如前端应用、后端服务、数据库、消息队列。
- 第三层:组件层。每个容器内部的关键模块,比如订单服务里的支付模块、库存模块。
- 第四层:代码层。一般不在架构图里画,除非是专门给开发看的详细设计。
这个分层思路来自我实际做技术方案评审的经验。评审时最怕的就是一张图里既有宏观部署又有具体类名,信息密度忽高忽低,读者注意力被分散。分层之后,你可以根据读者身份只展示其中一层或两层,比如给领导看第一层和第二层,给开发看第二层和第三层。这样一张图可以拆成多张,也可以组合成一张,灵活性非常高。
2.3 视觉编码:颜色、形状、线型都是有语义的
diagram-design 另一个容易被忽视的点是视觉编码的一致性。我见过太多图,同样的蓝色一会儿表示数据库,一会儿表示外部系统,读者直接懵掉。我的原则是:颜色不超过四种,形状不超过三种,线型不超过两种。具体怎么分配,看图的类型。
以数据流图为例,我通常这样定义:
| 视觉元素 | 语义 | 示例 |
|---|---|---|
| 蓝色圆角矩形 | 内部服务 | 订单服务、用户服务 |
| 灰色直角矩形 | 外部系统 | 支付网关、短信平台 |
| 绿色圆柱 | 数据存储 | MySQL、Redis |
| 实线箭头 | 同步调用 | HTTP、RPC |
| 虚线箭头 | 异步消息 | MQ、事件 |
| 红色虚线 | 异常或补偿路径 | 重试、回滚 |
这套编码一旦定下来,整个项目所有图都沿用。好处是团队里任何人看到图,不需要看图例就能猜个八九不离十。我试过在团队里推行这套规则,新同学上手画图的速度明显快了,评审时争论“这个框是什么意思”的时间减少了大概七成。
2.4 工具选型:别在工具上纠结超过半小时
关于工具,我的态度很明确:工具是次要的,思路是主要的。但工具选对了确实能省事。常见的几类:
- 代码生成类:适合开发人员,图用文本描述,可以进版本控制,改起来快。缺点是样式调整不够灵活。
- 拖拽类:适合快速出图,上手门槛低,但复杂图容易乱,版本管理麻烦。
- 手绘风格类:适合早期讨论和头脑风暴,强调“这是草图,别抠细节”,能降低评审时的对抗感。
我的建议是:早期讨论用手绘风格,正式方案用代码生成,对外交付用拖拽类精修。不要试图用一个工具解决所有场景。我自己在项目里通常同时用两到三种工具,根据阶段切换。这个切换成本很低,但收益很大。
3. 核心细节解析:从需求到图的关键转化步骤
3.1 需求拆解:把一段话变成一张图的思维过程
假设产品经理给你一段需求描述:“用户下单后,系统先扣库存,然后调用支付,支付成功后发消息通知发货,如果支付失败要回滚库存,如果库存不足要提示用户。”这段话看起来很简单,但直接画图容易漏掉关键分支。我的拆解步骤是这样的:
第一步,提取名词。用户、订单、库存、支付、消息、发货。这些是图中的节点候选。
第二步,提取动词。下单、扣库存、调用支付、发消息、通知发货、回滚、提示。这些是节点之间的动作。
第三步,识别分支和异常。支付成功和支付失败是两个分支,库存不足是另一个分支。异常路径往往是最容易漏的,但恰恰是开发最关心的。
第四步,确定边界。哪些是系统内部,哪些是外部依赖。支付通常是外部,消息队列可能是内部也可能是外部,取决于你的系统边界定义。
第五步,排优先级。主流程放中间,异常分支放两侧或下方,用不同线型区分。这样读者第一眼看到的是主流程,需要时再看异常。
这套步骤我用了很多年,基本上任何业务流程都能在十分钟内拆成一张结构清晰的图。关键是不要跳过“提取名词和动词”这一步,很多人直接凭感觉画,结果画到一半发现漏了东西,回头改结构,时间全浪费了。
3.2 布局算法:为什么你的图总是交叉线太多
交叉线是图的美观杀手,也是理解障碍。diagram-design 里有一个很重要的原则:分层布局,从左到右或从上到下,尽量减少跨层连线。具体怎么做?
- 主流程走直线。如果 A 调用 B,B 调用 C,那就 A、B、C 排成一行或一列,不要拐弯。
- 同层节点对齐。同一层级的服务放在同一水平线或垂直线上,视觉上自然形成分组。
- 跨层连线走边缘。如果确实需要跨层调用,让线从边缘绕过去,不要穿过其他节点。
- 异常分支向下或向侧边延伸。主流程保持干净,异常路径用不同颜色或线型,放在下方或右侧。
我实测下来,遵循这几条规则,一张中等复杂度的图(15 个节点左右)的交叉线可以从十几条降到两三条。读者的理解速度至少提升一倍。如果你用的是代码生成类工具,通常有自动布局算法,但自动布局不一定最优,手动微调几个节点的位置往往效果更好。
3.3 标注与注释:什么时候该写字,什么时候该闭嘴
图里的文字不是越多越好。我的经验是:节点名称必须写,关键参数选写,实现细节不写。比如一个“订单服务”节点,你不需要写它用了什么框架、什么语言、什么版本。但如果这个服务有特殊的约束,比如“仅支持人民币”“QPS 上限 1000”,那可以写在节点下方或旁边,用灰色小字。
箭头上的标注也是同理。同步调用可以不写,因为实线已经表达了;异步消息可以写“MQ”或具体主题名;异常路径必须写清楚条件,比如“支付失败”“库存不足”。我见过一张图,每个箭头上都写了“调用”“返回”“发送”“接收”,信息量几乎为零,反而干扰视线。
注意:图里的文字是给读者看的,不是给你自己看的。你自己知道的东西,读者不一定知道;但读者不需要知道的东西,你写了就是噪音。
3.4 版本管理与复用:别每次从零开始画
diagram-design 的长期价值在于复用。我自己的做法是维护一套“图元件库”,包括常用的服务图标、数据库图标、消息队列图标、外部系统图标,以及常用的连线样式。每次画新图,先从这个库里拖,而不是重新画。这样不仅快,而且风格统一。
版本管理方面,如果用的是代码生成类工具,直接把图描述文件放进 Git,每次修改都有记录,可以 diff,可以回滚。如果是拖拽类工具,至少把导出的图片和源文件按“项目名-日期-版本号”命名,放在共享目录里。我踩过的坑是:改了三版之后,忘了哪版是最终评审通过的,结果开发拿着旧版去实现了。后来我强制自己每次评审后把最终版单独放一个“approved”目录,并且在图里加一个不起眼的版本号水印,问题就解决了。
4. 实操过程:从零画出一张能直接进评审的架构图
4.1 环境准备与工具配置
假设我们要画一张中等复杂度的系统架构图,包含前端、网关、三个后端服务、两个数据库、一个消息队列、两个外部依赖。我以代码生成类工具为例,因为这类工具最适合需要版本管理的场景。具体工具名称我就不提了,市面上主流的几款思路都差不多。
首先,安装工具并初始化项目目录。通常需要创建一个描述文件,里面定义节点和连线。我的习惯是分三个文件:nodes定义所有节点及其属性,edges定义所有连线及其类型,layout定义布局方向和对齐方式。这样改的时候互不影响。
配置方面,最重要的是主题文件。把前面说的颜色、形状、线型规则写进主题文件,所有图共用。这样即使换项目,视觉风格也是一致的。我通常会把主题文件也放进 Git,团队里谁改了样式,其他人拉下来就能用。
4.2 节点定义:从需求到结构化描述
继续用前面的下单流程例子。先把节点列出来:
- 用户(外部角色)
- 订单服务(内部服务)
- 库存服务(内部服务)
- 支付网关(外部系统)
- 消息队列(内部组件)
- 发货服务(内部服务)
- 订单数据库(数据存储)
- 库存数据库(数据存储)
然后给每个节点定义属性:类型(服务/存储/外部)、层级(第一层/第二层)、标签文字。比如订单服务定义为type: service, layer: 2, label: "订单服务"。这些属性决定了它在图里的形状、颜色和位置。
这里有一个细节:外部系统的形状要和内部服务明显区分。我通常用直角矩形表示外部,圆角矩形表示内部。这样读者一眼就能看出哪些是自己可控的,哪些是依赖别人的。
4.3 连线定义:主流程与异常分支分开处理
连线是图的灵魂。我的做法是先定义主流程,再定义异常分支,最后定义数据存储的读写关系。
主流程连线:
- 用户 -> 订单服务:创建订单(实线,同步)
- 订单服务 -> 库存服务:扣减库存(实线,同步)
- 订单服务 -> 支付网关:发起支付(实线,同步)
- 支付网关 -> 订单服务:支付结果(虚线,回调)
- 订单服务 -> 消息队列:发送发货消息(虚线,异步)
- 消息队列 -> 发货服务:消费消息(虚线,异步)
异常分支连线:
- 库存服务 -> 订单服务:库存不足(红色虚线)
- 支付网关 -> 订单服务:支付失败(红色虚线)
- 订单服务 -> 库存服务:回滚库存(红色虚线)
数据存储连线:
- 订单服务 -> 订单数据库:读写(实线,无箭头或双向箭头)
- 库存服务 -> 库存数据库:读写(实线)
注意,异常分支我用了红色虚线,并且在连线上标注了触发条件。这样开发一看就知道哪些情况需要特殊处理。主流程的连线尽量简洁,不写多余的标注。
4.4 布局调整:让图自己“说话”
定义完节点和连线后,工具通常会生成一个初始布局。但这个布局往往不完美,需要手动调整。我的调整顺序是:
第一步,确定主流程方向。我通常选择从左到右,因为大多数人的阅读习惯是从左到右。用户放最左边,外部系统放最右边,内部服务放中间。
第二步,对齐同层节点。订单服务、库存服务、发货服务属于同一层,垂直对齐。订单数据库和库存数据库属于同一层,放在对应服务下方。
第三步,处理交叉线。如果订单服务到支付网关的线穿过了库存服务,就把支付网关往上或往下移。如果消息队列到发货服务的线穿过了其他节点,就把消息队列放在发货服务正上方或正下方。
第四步,调整间距。节点之间不要太挤,留出足够的空白。我通常设置节点间距为节点宽度的 1.5 倍,这样视觉上不压抑。
第五步,检查异常分支。异常分支的线不要和主流程线重叠,用不同的颜色和线型,并且尽量走图的边缘。
这套流程走下来,一张 15 个节点左右的图,从定义到最终布局,熟练的话大概 20 分钟。第一次可能会慢一些,但画过两三张之后,速度会明显提升。
4.5 导出与交付:格式选择与注意事项
图画完之后,导出格式很重要。我的经验是:
- 给开发看:导出 SVG 或 PNG,SVG 可以无限放大,适合放进文档;PNG 适合贴到聊天工具里。
- 给领导看:导出 PDF 或高清 PNG,确保打印出来也清晰。
- 进版本库:保留源文件(描述文件或工程文件),导出的图片作为附件。
导出时注意两点:一是字体嵌入,如果用了特殊字体,导出 PDF 时要嵌入,否则别人打开会乱码;二是背景透明,PNG 导出时选择透明背景,这样贴到任何颜色的文档里都不会有白底。
提示:交付前一定要自己用手机打开看一眼。很多图在电脑上看着清楚,手机上字小得根本看不清。如果手机上看不清,说明节点太密或字号太小,需要调整。
5. 常见问题与排查技巧实录
5.1 图太乱看不清,怎么快速定位问题
图乱通常有三个原因:节点太多、连线交叉太多、视觉编码不统一。我的排查顺序是:
第一,数节点。如果一张图超过 20 个节点,大概率太密了。解决办法是拆图,按层级拆,按模块拆。一张图只讲一件事。
第二,看交叉线。如果交叉线超过 5 条,说明布局有问题。重新调整节点位置,让主流程走直线,异常分支走边缘。
第三,检查颜色和形状。如果同一种颜色出现了三种以上含义,或者同一种形状表示了不同层级的东西,那就是视觉编码混乱。回到主题文件,重新定义规则。
我实测下来,90% 的“图太乱”问题,通过拆图和调整布局就能解决,不需要换工具。
5.2 评审时被问“这个框是什么意思”,怎么提前避免
这个问题本质是图的自解释性不够。解决办法有三个:
一是加图例。图例不需要很大,放在角落,用最小字号。图例里说明颜色、形状、线型的含义。
二是节点命名要具体。“服务 A”“模块 B”这种命名等于没命名。用“订单服务”“库存服务”“支付网关”这种一看就懂的名字。
三是关键约束写在节点上。比如“仅支持人民币”“QPS 上限 1000”“异步处理”,这些信息写在节点下方,用灰色小字,不干扰主视觉,但评审时能直接回答很多问题。
我自己的习惯是,图交付之前,找一个没参与项目的同事看一眼,问他“这张图你看懂了吗?哪里看不懂?”如果他能在一分钟内说出主流程,说明图合格了。
5.3 开发说“图跟代码不一致”,怎么从流程上杜绝
这是最致命的问题。图跟代码不一致,通常是因为图更新不及时。我的解决办法是把图纳入开发流程:
- 设计阶段:图是设计的一部分,评审通过才能开发。
- 开发阶段:如果实现和设计有偏差,必须同步更新图,并且注明变更原因。
- 上线阶段:上线前对照图检查一遍,确保图反映的是线上真实状态。
如果用的是代码生成类工具,图描述文件和代码放在同一个仓库,改代码的时候顺手改图,提交时一起提交。这样至少保证了版本一致。如果是拖拽类工具,至少指定一个人负责维护图,每次变更后 24 小时内更新。
我踩过的坑是:图是评审时的版本,开发过程中改了三次架构,图没更新,结果新来的同事看图理解系统,完全理解错了。后来我强制要求“图不更新,代码不合并”,虽然有点极端,但确实有效。
5.4 常见问题速查表
| 问题现象 | 可能原因 | 排查方法 | 解决技巧 |
|---|---|---|---|
| 图太乱看不清 | 节点太多或交叉线太多 | 数节点数量,看交叉线数量 | 拆图,调整布局,主流程走直线 |
| 评审时被问框的含义 | 图例缺失或命名太泛 | 检查是否有图例,节点名是否具体 | 加图例,用业务名称命名节点 |
| 图跟代码不一致 | 更新流程缺失 | 检查最近一次代码变更后图是否更新 | 图纳入版本库,变更时同步更新 |
| 手机上看不清 | 字号太小或节点太密 | 手机打开图片查看 | 放大字号,减少节点,拆图 |
| 颜色含义混乱 | 视觉编码不统一 | 检查同色是否多义 | 定义主题文件,全项目统一 |
| 异常分支被忽略 | 异常路径不明显 | 检查异常线是否和主线区分 | 用红色虚线,标注触发条件 |
| 导出后字体乱码 | 字体未嵌入 | 换一台电脑打开导出文件 | 导出 PDF 时嵌入字体 |
| 布局自动生成不理想 | 自动布局算法限制 | 对比手动调整后的效果 | 手动微调关键节点位置 |
5.5 独家避坑技巧:我这些年总结的几条铁律
第一条,画图之前先写字。把要表达的内容用文字列出来,再转成图。直接画图容易漏东西。
第二条,一张图只讲一件事。如果发现一张图里有两件不相干的事,拆成两张。读者不会因为图多而烦躁,只会因为图乱而放弃。
第三条,颜色是最后才加的。先用黑白灰把结构画清楚,确认逻辑没问题了,再加颜色。颜色是辅助,不是主角。
第四条,找外行看一眼。外行能看懂,说明图的自解释性够好。外行看不懂,说明你用了太多内部术语。
第五条,图是给人看的,不是给机器看的。不要为了追求“完整”而把所有细节都画上。读者需要的是理解,不是信息轰炸。
6. 从单张图到图体系:diagram-design 的长期价值
6.1 建立团队自己的图规范
一个人画图好看不难,难的是团队里所有人画图都好看,而且风格一致。我的做法是制定一份团队图规范,内容包括:颜色定义、形状定义、线型定义、命名规范、布局规范、导出规范。这份规范不需要很长,两三页就够,但必须所有人都遵守。
规范制定之后,新同学入职第一周就要学,并且用规范画一张图作为练习。我试过在团队里推行这套规范,大概一个月后,评审时关于“图看不懂”的抱怨减少了八成。大家把精力从“猜图”转移到了“讨论方案”上,效率提升非常明显。
6.2 图作为文档的一部分,怎么组织
图不是孤立的,它通常和文字文档一起出现。我的组织方式是:每张图配一段文字说明,文字说明包括图的背景、关键决策、异常处理、相关链接。图和文字放在同一个文档里,图在上,文字在下,或者图在左,文字在右。
如果是大型项目,我会建一个“图目录”,把所有图按模块分类,每个图有一个简短的描述和最后更新日期。这样任何人需要了解系统时,可以先看图目录,找到相关图,再看详细文档。这个习惯让我在多次项目交接中省了大量时间。
6.3 图体系的迭代与维护
图体系不是一次建成的,是迭代出来的。我的做法是每季度回顾一次所有图,检查是否有过时的、重复的、没人看的图。过时的图要么更新,要么归档;重复的图合并;没人看的图直接删掉。保持图体系的精简,比保持完整更重要。
另外,每次项目复盘时,我会专门花十分钟回顾这次项目里画的图,哪些图帮助很大,哪些图没人看,哪些图画错了。这些反馈会直接影响到下一次画图的方式。我个人的体会是,画图能力和写代码能力一样,都是练出来的,但练的方法不是画更多图,而是画完图之后看效果、听反馈、做调整。
6.4 一个实际案例的完整复盘
最后分享一个我最近做的案例。某次需要设计一个跨系统的数据同步方案,涉及三个内部服务、两个外部系统、一个消息队列。第一次评审时,我画了一张大图,把所有节点和连线都放上去了,结果评审会上大家花了二十分钟在争论“这个箭头是什么意思”。会后我重新拆成三张图:一张上下文图,只画外部依赖和用户;一张容器图,画内部服务和消息队列;一张数据流图,画具体的数据字段映射。第二次评审,十分钟就通过了。
这个案例让我更加确信:图的本质是沟通工具,不是技术展示。工具再高级,如果读者看不懂,就是失败的图。diagram-design 的核心不是教你用某个工具,而是教你站在读者角度,用最合适的方式把复杂信息讲清楚。这个能力,比会画任何图都值钱。