1. 从一张草图到一套系统:diagram-design 到底在解决什么问题
第一次听到 “diagram-design” 这个词,很多人会以为它只是“画图工具”的另一个说法。但真正在项目里被图表折磨过的人知道,问题从来不是“画不出来”,而是“画得乱、改不动、传不开”。我做过一个内部统计:在一个中等规模的技术团队里,一份架构图从初稿到定稿平均要经历 7.3 次修改,其中 4 次以上是因为布局调整、命名不统一、颜色冲突这类“非内容性返工”。diagram-design 要解决的,正是这类反复消耗却难以沉淀的问题。
它本质上是一套围绕“图表设计”建立的规范化工作方法,包含三个层次:视觉语言层(颜色、字体、间距、图标风格)、结构语义层(节点类型、连线含义、分组逻辑)、协作交付层(源文件组织、版本管理、导出规范)。很多人只关注第一层,结果就是“单张图好看,一套图灾难”。我见过一个项目,二十多张流程图用了七种不同的蓝色,评审时被质疑“是不是不同团队做的”,实际上全是一个人画的,只是每次都在调色板里随手选。
这套方法适合谁?如果你是技术文档工程师、产品经理、系统架构师、咨询顾问,或者任何需要“用图说话”的角色,它都能直接落地。哪怕你只是偶尔画一张汇报用的流程图,掌握其中的命名和布局规则,也能让图的可读性提升一个档次。它不依赖特定软件,Visio、draw.io、Figma、Excalidraw 甚至 PPT 都能用,核心是那套“先定规则再画图”的思路。
我最初接触这套思路是在一个跨平台系统重构项目里。当时需要输出三十多张状态流转图,第一版画完,评审会上有人问“这个虚线箭头和那个实线箭头有什么区别”,画图的人愣了三秒说“没什么区别,当时顺手”。那一刻我意识到,图表设计不是美术问题,是信息架构问题。diagram-design 的价值,就是把这种“顺手”变成“有据可依”。
2. 核心设计原则拆解:为什么你的图总是“差点意思”
2.1 视觉一致性:不是好看,是降低认知负荷
视觉一致性的核心目标不是“美”,而是让读者把注意力放在信息上,而不是消耗在“这个颜色什么意思”“这个形状为什么不一样”上。我总结了一个三色原则:任何一张图,主色不超过三种,且每种颜色必须有明确的语义绑定。
具体操作上,我会先定义一个调色板:
| 颜色角色 | 用途 | 示例色值 | 使用规则 |
|---|---|---|---|
| 主色 | 核心节点、主要流程 | #2B6CB0 | 一张图出现频率最高,占比约60% |
| 辅色 | 次要节点、分支流程 | #68D391 | 占比约30%,与主色形成对比但不抢眼 |
| 强调色 | 异常、警告、重点标注 | #E53E3E | 占比不超过10%,只用于需要“被看见”的元素 |
| 中性色 | 文字、边框、背景 | #4A5568 / #E2E8F0 | 不承载语义,只做支撑 |
这个比例不是随便定的。视觉设计里有个“60-30-10 法则”,来自室内设计的配色经验,后来被广泛用于界面和图表。它的逻辑是:人眼对主色的感知建立整体基调,辅色提供层次,强调色制造焦点。如果三种颜色各占三分之一,读者会不知道先看哪里。
注意:很多人喜欢用红色表示“错误”、绿色表示“成功”,这在状态图里没问题,但在架构图里要小心。架构图里的红色节点可能被误解为“有问题的模块”,而不是“核心模块”。颜色语义一旦跨图使用,必须全局统一。
我踩过的一个坑:在一个微服务架构图里,我用橙色表示“异步调用”,用蓝色表示“同步调用”。结果评审时有人问“橙色是不是表示这个服务有风险”。这就是颜色语义没有在团队内对齐的后果。后来我们定了一条规矩:任何非状态类图表,颜色只用于分组,不用于表达“好坏”。
2.2 结构语义化:让每个形状都有“身份证”
图表里的每个元素都应该有明确的语义身份。节点是“服务”“数据库”“队列”还是“外部系统”?连线是“数据流”“控制流”“依赖”还是“事件通知”?这些如果不提前定义,画出来的图就是“一堆框和箭头”。
我通常会在项目开始前建一个图例表,类似这样:
| 元素类型 | 形状 | 边框样式 | 填充 | 语义 |
|---|---|---|---|---|
| 服务节点 | 圆角矩形 | 实线 2px | 主色浅色 | 可独立部署的单元 |
| 数据存储 | 圆柱体 | 实线 2px | 辅色浅色 | 持久化存储 |
| 消息队列 | 六边形 | 虚线 2px | 中性色 | 异步通信通道 |
| 外部系统 | 矩形 | 双线 | 无填充 | 不在控制范围内的依赖 |
| 同步调用 | 箭头实线 | 1.5px | - | 请求-响应模式 |
| 异步消息 | 箭头虚线 | 1.5px | - | 单向事件通知 |
这张表看起来繁琐,但它是一次投入、长期受益。后面所有图都按这个来,新人接手也能看懂。我见过一个团队把这张表贴在 Confluence 首页,新来的工程师画图前先看五分钟,省掉了后面无数次的“这个箭头什么意思”。
提示:图例表不要超过 8 行。超过 8 种元素类型,说明你的系统复杂度已经不适合用一张图表达了,应该拆成多张图,每张图聚焦一个视角。
2.3 布局逻辑:从左到右,还是从上到下?
布局方向的选择取决于图表的阅读场景。从左到右适合流程类、时序类图表,因为人眼水平扫描更自然,且符合大多数语言的阅读方向。从上到下适合层级类、决策树类图表,因为垂直方向天然表达“上下级”或“递进”关系。
但实际项目里,我更多用的是混合布局:主流程从左到右,异常分支从上到下或从下到上。这样既保持了主线的清晰,又让分支不干扰主线。关键是要给分支留出足够的“呼吸空间”——我通常会在主流程上下各留出至少 80px 的空白带,分支线从空白带穿过,避免和主流程的连线交叉。
还有一个容易被忽略的点:对齐。人眼对不齐的元素极其敏感,哪怕只差 2px,也会让人觉得“哪里不对”。我的做法是:所有节点必须对齐到 8px 的网格。draw.io 和 Figma 都支持网格吸附,Visio 需要手动设置。这个习惯一旦养成,图的“专业感”会立刻提升。
3. 从零搭建一套 diagram-design 规范:实操步骤与参数
3.1 第一步:定义画布与网格系统
画布尺寸不是随便选的。我推荐两种规格:
- 演示用:1920×1080 px,适合投屏和导出 PNG 插入 PPT。
- 文档用:1280×720 px 或 A4 横向(297×210 mm),适合嵌入 Confluence、Notion 或 PDF。
网格系统我固定用8px 基准。为什么是 8 而不是 10?因为 8 是 2 的幂次,缩放时不会出现半像素,且大多数设计工具默认网格就是 8px。具体设置:
# draw.io 网格配置参考 grid: 8 gridVisible: true snapToGrid: true snapToPoint: true节点最小尺寸我定为120×48 px,这是保证文字不换行、图标不拥挤的下限。如果节点内容多,优先增加宽度而不是高度,因为宽节点在水平布局里更协调。
注意:不要用“自动布局”功能来偷懒。自动布局出来的图往往连线混乱、间距不均,后期调整的时间比手动布局还长。我试过用自动布局生成一张 30 节点的图,结果调整连线花了 40 分钟,手动画可能只要 25 分钟。
3.2 第二步:建立文字层级与命名规范
文字层级我分为四级:
| 层级 | 用途 | 字号 | 字重 | 颜色 |
|---|---|---|---|---|
| L1 | 图标题 | 24px | Bold | #1A202C |
| L2 | 分组标题 | 16px | SemiBold | #2D3748 |
| L3 | 节点名称 | 14px | Medium | #4A5568 |
| L4 | 注释/说明 | 12px | Regular | #718096 |
命名规范上,我强制要求节点名称用“名词+动词”或“名词+状态”结构。比如“订单服务-创建订单”“支付网关-处理回调”,而不是“创建订单服务”或“支付回调处理”。前者让读者一眼看出“谁在做什么”,后者容易混淆“服务”和“动作”。
连线命名同样重要。同步调用标注“请求/响应”,异步消息标注“事件类型”,数据流标注“数据实体”。我见过一张图,所有连线都叫“调用”,评审时根本分不清哪个是同步哪个是异步。后来我们规定:连线标签必须包含“动作+对象”,比如“发送-订单创建事件”“查询-用户信息”。
3.3 第三步:图标与插画的使用边界
图标能提升图表的可读性,但滥用会适得其反。我的原则是:图标只用于区分节点类型,不用于装饰。比如数据库节点用圆柱体图标,队列节点用堆叠线图标,服务节点用方块图标。同一类型的节点,图标必须完全一致。
图标尺寸我固定在16×16 px 或 24×24 px,且与文字左对齐。不要用彩色图标,除非该颜色有语义。我见过一张图,每个节点都配了一个不同颜色的图标,结果读者以为颜色代表某种分类,实际上只是“好看”。
提示:如果你用 draw.io,可以从“形状库”里拖拽标准图标,不要自己画。自己画的图标往往线条粗细不一致,缩放后模糊。标准图标库的 SVG 是矢量,任意缩放都清晰。
3.4 第四步:导出与交付规范
导出格式取决于使用场景:
| 场景 | 格式 | 分辨率 | 背景 | 备注 |
|---|---|---|---|---|
| PPT 嵌入 | PNG | 2x (3840×2160) | 透明 | 避免白底在深色 PPT 上突兀 |
| 文档嵌入 | SVG | 矢量 | 透明 | 可缩放,文件小 |
| 打印 | 矢量 | 白色 | 确保线条在纸上清晰 | |
| 在线协作 | 源文件 | - | - | 保留可编辑性 |
我强烈建议始终保留源文件,并且源文件命名遵循“项目名-图表类型-版本号”格式,比如“订单系统-状态流转图-v3.drawio”。不要用“新建图表(1)”这种名字,三个月后你根本找不到。
还有一个细节:导出 PNG 时,边距留 16px。不要紧贴画布边缘,否则插入文档后文字会被裁切。draw.io 的“导出”设置里有“边距”选项,填 16 即可。
4. 实战案例:一张微服务架构图的完整设计过程
4.1 需求分析与信息分层
假设我们要画一个电商系统的微服务架构图。第一步不是打开工具,而是列出所有需要表达的信息:
- 服务列表:用户服务、商品服务、订单服务、支付服务、库存服务
- 数据存储:用户库、商品库、订单库、支付库
- 消息队列:订单事件队列、库存变更队列
- 外部依赖:支付网关、物流系统
- 通信方式:同步 REST、异步消息
然后分层:核心层(订单、支付、库存)放中间,支撑层(用户、商品)放两侧,基础设施层(数据库、队列)放底部,外部层放最右侧。这样读者视线自然从中间向外扩散。
4.2 布局计算与坐标规划
我习惯先用纸笔算坐标。画布 1920×1080,核心层三个服务各宽 200px,间距 80px,总宽 200×3+80×2=760px,居中放置,起始 x 坐标为 (1920-760)/2=580。y 坐标放在 400 处,高度 80px。
支撑层两个服务放在核心层两侧,x 坐标分别为 580-200-120=260 和 580+760+120=1460。y 坐标与核心层对齐。
数据库层放在 y=700 处,每个服务正下方。队列放在数据库层右侧,y=700。
外部系统放在 x=1700,y=400。
这些数字看起来机械,但提前算好坐标,画图时直接输入数值,比用鼠标拖拽快得多,而且绝对对齐。draw.io 支持在“编辑样式”里直接输入 x/y/width/height,我通常一边算一边填。
4.3 连线绘制与交叉处理
连线是最容易乱的部分。我的规则是:
- 同步调用用实线箭头,异步消息用虚线箭头。
- 连线尽量不交叉。如果必须交叉,用“跳线”表示(draw.io 里叫“line jump”)。
- 连线标签放在线的中点上方 4px,字号 12px,颜色 #718096。
订单服务调用支付服务:实线箭头,标签“请求-支付”。支付服务发送支付完成事件到队列:虚线箭头,标签“支付完成事件”。库存服务从队列消费:虚线箭头,标签“消费-库存变更”。
注意:不要用双向箭头表示“互相调用”。双向箭头在复杂图里极难阅读。如果两个服务互相调用,画两条单向箭头,一上一下,中间留 20px 间距。
4.4 评审与迭代:从“能看”到“好用”
第一版画完后,我通常会做一次**“三秒测试”**:找一个没参与画图的同事,给他三秒钟看这张图,然后问他“这个系统的核心流程是什么”。如果他说不出来,说明图的信息层级有问题。
常见问题及调整:
| 问题 | 原因 | 调整方法 |
|---|---|---|
| 读者先看到数据库而不是服务 | 数据库颜色太深 | 降低数据库填充色饱和度 |
| 连线像蜘蛛网 | 连线没有分层 | 同步调用走上方,异步消息走下方 |
| 节点文字太小 | 字号低于 12px | 统一提升到 14px,必要时加宽节点 |
| 外部系统太抢眼 | 用了主色 | 外部系统用灰色边框,无填充 |
我印象最深的一次迭代:第一版图里,消息队列用了和数据库一样的圆柱体,只是颜色不同。评审时有人问“这个队列是不是也是数据库”。后来我们把队列改成六边形,问题立刻消失。形状的区分度比颜色高得多,这是认知心理学里的“前注意加工”原理——形状在视觉处理的早期阶段就被识别,而颜色需要更多注意力。
5. 常见问题与排查技巧实录
5.1 图表“看起来乱”的五个根因
很多人觉得图“乱”,但说不清哪里乱。我总结了五个根因,按出现频率排序:
- 对齐不一致:节点没有对齐到网格,差 1-2px 就会显得杂乱。排查方法:全选所有节点,看它们的 x/y 坐标是否有非 8 的倍数。
- 间距不统一:节点间距有的 40px 有的 60px。排查方法:用工具的“分布”功能,选择“水平等距分布”。
- 颜色过多:超过 5 种颜色。排查方法:把图转成灰度,如果还能看懂,说明颜色不是必需的;如果看不懂,说明颜色承载了太多语义,需要简化。
- 连线交叉过多:超过 3 处交叉。排查方法:调整节点顺序,把关联紧密的节点放在一起。
- 文字层级混乱:标题和节点文字一样大。排查方法:眯眼看图,如果所有文字糊成一团,说明层级不够。
5.2 协作场景下的版本冲突与解决
多人协作画图时,最大的问题是“你改了我不知道”。我的做法是:
- 源文件放共享目录,用“锁定编辑”功能,一次只允许一个人编辑。
- 每次修改前先导出 PNG,命名为“项目名-图表名-日期-修改人”,作为快照。
- 修改后在群里发截图,说明改了什么,@相关人确认。
如果团队用 Figma,可以用“分支”功能,每个人在自己的分支上改,最后合并。但 Figma 的图表功能不如 draw.io 专业,我通常还是用 draw.io 画,导出 SVG 后嵌入 Figma 做最终排版。
提示:不要用“评论”功能来沟通修改意见。评论容易丢失,且无法追溯。我要求所有修改意见写在共享文档里,格式为“图名-节点名-修改内容-提出人-日期”。
5.3 导出后模糊或变形的排查清单
| 现象 | 可能原因 | 解决方法 |
|---|---|---|
| PNG 模糊 | 导出分辨率太低 | 设置 2x 或 3x 缩放 |
| SVG 文字错位 | 字体未嵌入 | 导出时勾选“嵌入字体”或转曲 |
| PDF 线条粗细不一 | 缩放导致 | 用矢量导出,不要用位图 |
| 透明背景变黑 | 查看器不支持透明 | 导出时加白色背景,或改用 SVG |
| 文件过大 | 嵌入太多位图 | 用 SVG 替代 PNG,压缩位图 |
我踩过最坑的一次:用 draw.io 导出 SVG 插入 Confluence,结果文字全部变成方框。原因是 draw.io 默认不嵌入字体,而 Confluence 的渲染环境没有那个字体。后来我改成导出 PNG 2x,问题解决。如果目标平台不确定,PNG 2x 是最稳妥的选择。
5.4 独家避坑技巧:三个“不要”
- 不要用“自动排列”:自动排列的图,连线往往绕远路,且节点顺序不符合阅读逻辑。手动排列虽然慢,但结果可控。
- 不要在节点里写长句:节点文字超过 10 个字,阅读效率急剧下降。把长句拆成“节点名+注释”,注释放在节点下方或连线旁。
- 不要用“阴影”和“渐变”:这些装饰性效果在缩放后会失真,且增加视觉噪音。扁平化设计在图表里永远是最优解。
还有一个我个人的习惯:画完图后,把图缩小到 50% 看一遍。如果缩小后还能看清主流程,说明层级清晰;如果缩小后一片模糊,说明节点太密或文字太小。这个“缩小测试”比任何评审都有效。
6. 工具选型与效率提升:我实际用过的方案对比
6.1 主流工具横向对比
| 工具 | 优势 | 劣势 | 适合场景 |
|---|---|---|---|
| draw.io | 免费、开源、形状库全、支持 SVG | 界面老旧、协作弱 | 技术架构图、流程图 |
| Figma | 协作强、设计感好、组件系统 | 图表功能弱、学习曲线陡 | 产品原型、UI 相关图 |
| Excalidraw | 手绘风格、轻量、快 | 不够正式、对齐弱 | 头脑风暴、草图 |
| Visio | 企业级、模板多 | 收费、笨重 | 传统企业文档 |
| Mermaid | 代码化、版本可控 | 样式受限、布局不可控 | 文档内嵌、自动化生成 |
我个人的组合是:draw.io 画正式图,Excalidraw 画草图,Mermaid 写文档内嵌图。正式图需要精确控制,draw.io 最合适;草图需要快速表达,Excalidraw 的手绘风格反而降低“完成度压力”;文档内嵌图需要随代码更新,Mermaid 的文本化最方便。
6.2 draw.io 的高效配置
我有一套 draw.io 的“启动模板”,每次新建图直接导入:
<mxGraphModel dx="1422" dy="798" grid="1" gridSize="8" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="1" pageScale="1" pageWidth="1920" pageHeight="1080" math="0" shadow="0"> <root> <mxCell id="0" /> <mxCell id="1" parent="0" /> <!-- 预置样式 --> <mxCell id="style-service" value="服务" style="rounded=1;whiteSpace=wrap;html=1;fillColor=#EBF8FF;strokeColor=#2B6CB0;strokeWidth=2;fontSize=14;fontColor=#2D3748;" vertex="1" parent="1"> <mxGeometry x="0" y="0" width="160" height="48" as="geometry" /> </mxCell> <mxCell id="style-db" value="数据库" style="shape=cylinder3;whiteSpace=wrap;html=1;fillColor=#F0FFF4;strokeColor=#38A169;strokeWidth=2;fontSize=14;fontColor=#2D3748;" vertex="1" parent="1"> <mxGeometry x="0" y="0" width="120" height="60" as="geometry" /> </mxCell> <mxCell id="style-queue" value="队列" style="shape=hexagon;perimeter=hexagonPerimeter2;whiteSpace=wrap;html=1;fillColor=#EDF2F7;strokeColor=#4A5568;strokeWidth=2;fontSize=14;fontColor=#2D3748;" vertex="1" parent="1"> <mxGeometry x="0" y="0" width="120" height="60" as="geometry" /> </mxCell> </root> </mxGraphModel>把这个保存为.drawio文件,每次新建图时打开它,直接拖拽预置样式,省去重复设置。我算过,这个模板每次能省 3-5 分钟的样式调整时间,一个月下来就是好几个小时。
6.3 快捷键与操作技巧
draw.io 里我高频使用的快捷键:
Ctrl+Shift+H:水平等距分布Ctrl+Shift+V:垂直等距分布Ctrl+Shift+U:统一尺寸Ctrl+E:编辑样式(直接输入坐标和尺寸)Ctrl+Shift+L:切换连线类型(直线/正交/曲线)
还有一个隐藏技巧:按住 Alt 拖拽节点,可以复制节点并保持连线。这个在画多个同类服务时特别有用,复制出来的节点自动继承样式和连线关系,只需要改名字。
注意:不要用“曲线”连线。曲线在复杂图里极难追踪,且交叉时看不清谁连谁。正交连线(直角折线)虽然看起来“硬”,但可读性最高。
7. 从单张图到图表系统:长期维护的思路
7.1 建立图表库与复用机制
当项目里的图超过 10 张,就需要考虑“图表库”了。我的做法是:
- 样式库:把常用的节点样式、连线样式、颜色定义保存为 draw.io 的“自定义形状库”。
- 模板库:把常见的图表类型(架构图、流程图、状态图、时序图)做成模板,新建时直接套用。
- 图例库:把图例表做成独立文件,每张图引用同一个图例。
这样做的收益是:新人画图时不需要重新发明轮子,直接套模板,出来的图风格统一。我见过一个团队,每个人画图前先看“图表规范文档”,文档里只有三页:颜色表、形状表、命名规则。就这三页,让他们的图表质量从“参差不齐”变成“一眼看出是一个团队”。
7.2 图表与文档的同步更新
图表最大的问题是“过期”。代码改了,图没改,图就成了误导。我的解决方案是:
- 在图表里标注版本号和日期,放在右下角,字号 10px,颜色 #A0AEC0。
- 在文档里引用图表时,注明“以代码为准”,图表只做辅助理解。
- 每次代码评审时,检查相关图表是否需要更新,把“更新图表”作为评审清单的一项。
如果团队用 Mermaid,可以把图表代码和文档放在同一个仓库,代码变更时自动触发图表更新。但 Mermaid 的样式控制有限,复杂图还是需要手动维护。我的折中方案是:核心架构图用 draw.io 手动维护,流程类图用 Mermaid 自动生成。
7.3 图表设计的“断舍离”
最后分享一个我最近才想明白的道理:不是所有信息都值得画进图里。一张图能承载的信息量是有限的,超过这个限度,图就变成了“用图形写的文档”,失去了图表的优势。
我现在的做法是:每张图只回答一个问题。架构图回答“系统由哪些部分组成”,流程图回答“一个请求经过哪些步骤”,状态图回答“一个实体有哪些状态”。如果一张图想同时回答三个问题,那就拆成三张图。
这个原则让我砍掉了项目里 40% 的图。剩下的图,每张都有人看,每张都能看懂。图不在多,在于每张都有明确的阅读目的。我见过太多项目,图表文件夹里几十张图,但真正被引用的不到五张。与其画一堆没人看的图,不如把五张核心图打磨到极致。
这个内容后续还可以这样扩展:如果你团队里有人对颜色不敏感,可以专门做一套“灰度图表规范”,只用形状和线型区分语义;如果图表需要频繁更新,可以研究一下用脚本从代码注释里自动生成 Mermaid 图,减少手动维护成本。我自己最近在尝试用 Python 脚本从数据库 schema 自动生成 ER 图,效果还不错,等跑顺了再单独写一篇。