1. 从一张草图到一套系统:diagram-design 到底在解决什么问题
第一次听到 “diagram-design” 这个词,很多人会下意识觉得它只是“画图”的另一种说法。但真正在项目里被图表折磨过的人都知道,画图本身从来不是难点,难点在于图表的可维护性、一致性和表达效率。你画了一张架构图,两周后系统加了一个模块,你是重新画一张,还是在原图上改?改完之后导出 PNG 发给同事,同事说“这个框能不能往左挪一点”,你打开源文件发现图层已经乱成一锅粥。这就是 diagram-design 要解决的核心问题:把图表从“一次性美术作品”变成“可迭代的工程产物”。
我接触 diagram-design 这个概念,最早是在一个内部工具链重构的项目里。当时团队有十几张核心架构图,分散在三个人的电脑里,格式有 Visio、有 draw.io、有 PPT 直接画的,还有一张是某位同学用代码生成的。每次开评审会,光是确认“哪张图是最新版”就要花十分钟。后来我们决定统一用一套 diagram-design 规范来管理所有图表,从配色、字体、间距到图元命名,全部定死,再用代码化的方式生成。那之后,图表的维护成本至少降了七成。
所以这篇内容适合谁看?如果你是技术文档写作者、系统架构师、产品经理,或者任何需要频繁输出图表的人,diagram-design 的思路会让你少走很多弯路。它不要求你会设计,也不要求你精通某个绘图软件,它要求的是一种“把图表当代码管”的意识。下面我会从整体设计思路、核心细节、实操流程到问题排查,完整拆一遍这套方法。
2. 整体设计思路:为什么图表要“设计”而不是“画”
2.1 图表失控的三个根源
在讲怎么做之前,先搞清楚图表为什么会失控。我观察下来,根源无非三个。
第一个是样式漂移。今天你用蓝色表示数据库,明天同事用绿色表示数据库,后天新来的人用了一个渐变蓝。单看每张图都没问题,放在一起就像三个不同公司出的。样式漂移的本质是缺少一个“单一事实来源”,每个人都凭感觉选颜色和形状。
第二个是结构耦合。很多人的图是“画”出来的,不是“描述”出来的。框和箭头的位置靠鼠标拖拽,一旦某个框变大,所有箭头都要手动调。这种图的信息和布局是耦合的,改一处动全身。
第三个是版本混乱。图表的源文件通常是二进制格式,没法像代码一样 diff。你改了哪里、为什么改,全靠记忆。时间一长,没人敢动那张“祖传架构图”。
diagram-design 的思路就是针对这三点:用规范解决样式漂移,用声明式描述解决结构耦合,用文本化源文件解决版本混乱。
2.2 声明式 vs 命令式:一个生活化类比
我用做菜来类比。命令式画图就像你手把手教一个人做菜:“先放油,等三秒,放葱,翻炒五下,放肉……”每一步都要你盯着,火候变了、锅换了,菜就做砸了。声明式画图则是你写一份菜谱:“红烧肉,主料五花肉 500g,辅料葱姜蒜,口味咸鲜。”至于用什么锅、火开多大,交给执行的人去判断。
diagram-design 走的是声明式路线。你描述的是“系统里有哪些组件、它们之间是什么关系”,而不是“这个框放在坐标 (120, 340),宽 80 高 40”。布局引擎会根据你的描述自动排布。这样做的好处是,当你增加一个组件时,不需要手动挪动其他所有元素,引擎会重新计算。
注意:声明式不是万能的。对于高度定制化的视觉稿,比如需要精确控制每个像素的营销图,声明式反而低效。diagram-design 适合的是结构清晰、以信息传达为主的技术图、流程图、架构图。
2.3 工具选型的取舍逻辑
市面上能实现声明式图表的工具不少,我大致分过几类。一类是纯代码驱动的,比如用特定语法描述图结构,渲染成 SVG;一类是文本 DSL 配合渲染引擎;还有一类是可视化编辑器但支持导出结构化数据。
选型的核心考量是三点:学习成本、渲染质量、协作友好度。学习成本决定了团队愿不愿意用,渲染质量决定了图能不能直接放进正式文档,协作友好度决定了多人维护时会不会打架。
我个人的经验是,如果团队里程序员居多,优先选代码驱动的方案,因为大家本来就习惯用文本管理东西。如果团队以产品和设计为主,选支持结构化导出的可视化工具更现实,强行推代码只会遭到抵制。diagram-design 的规范是工具无关的,你可以用任何工具实现,关键是那套“描述优先、样式统一、源文件文本化”的原则。
3. 核心细节解析:一套可落地的 diagram-design 规范
3.1 视觉语言的最小完备集
一套图表规范不需要很复杂,但必须覆盖几个最小要素。我总结为“四定”:定色、定形、定字、定距。
定色,就是确定一套有限的调色板。我的做法是选一个主色、两个辅助色、一个强调色、一个中性灰阶。主色用于核心组件,辅助色用于次要组件,强调色只用于需要引起注意的部分(比如故障点、待办项),中性灰用于文字和边框。颜色数量控制在 5 到 7 个,多了必然乱。
定形,就是确定图元的形状语义。比如矩形表示服务,圆角矩形表示外部系统,圆柱表示数据库,菱形表示判断。形状一旦定下来,就不能随意混用。我见过有人用菱形表示数据库,理由是“好看”,结果读者完全懵了。
定字,就是确定字体、字号、字重。技术图建议用无衬线字体,字号分三级:标题 16px、组件名 14px、注释 12px。字重只用常规和加粗两种,不要用细体,投影或缩放后会糊。
定距,就是确定间距规则。组件之间的水平间距、垂直间距、文字与边框的内边距,都要有固定值。我通常用 8 的倍数作为基准,比如 8px、16px、24px。这样排出来的图有节奏感,不会显得拥挤或松散。
3.2 图元命名的约定
这一条是很多人忽略的,但极其重要。图元命名不是给你自己看的,是给未来的维护者看的。我建议采用“类型-名称-状态”的三段式命名。比如svc-order-api、db-user-primary、queue-payment-retry。
为什么要带类型前缀?因为在声明式描述里,你经常需要按类型批量操作。比如“把所有 db 类型的图元染成蓝色”,如果命名里没有类型信息,你就得手动一个个指定。带状态后缀则是为了区分主从、主备、正常与异常。
实操心得:命名里不要用中文、空格和特殊符号。中文在某些渲染引擎里会导致对齐问题,空格会让解析器困惑,特殊符号可能和语法冲突。用短横线连接,全小写,这是最稳的。
3.3 布局策略:分层与分组
声明式布局引擎虽然会自动排布,但你不能完全撒手不管。我的经验是,先分层,再分组,最后让引擎微调。
分层是指按逻辑层次划分,比如接入层、服务层、数据层。每一层内部再分组,比如服务层里按业务域分组。分组的意义在于,引擎会把同一组的元素排在一起,组与组之间留出更大的间距,视觉上自然形成区块。
如果不做分层分组,引擎可能把数据库和前端组件排在同一行,图就废了。分层分组的信息需要在描述文件里显式声明,这是 diagram-design 里最需要花心思的部分。
3.4 样式与内容的分离
这是软件工程里的老原则,放到图表上同样适用。样式定义在一个地方,内容定义在另一个地方。内容文件里只写“有哪些组件、什么关系”,样式文件里写“服务用蓝色矩形、数据库用圆柱”。
这样做的好处是,换一套配色方案时,只需要改样式文件,所有图自动更新。我们团队做过一次品牌色升级,十几张图只花了半小时就全部换新,靠的就是这个分离。
4. 实操过程:从零搭建一套 diagram-design 工作流
4.1 环境准备与工具链搭建
假设你从零开始,我推荐的最小工具链是这样的:一个文本编辑器(VS Code 就行)、一个支持声明式语法的渲染引擎、一个版本管理工具(Git)。渲染引擎的选择上,我倾向于那些能把文本描述转成 SVG 的,因为 SVG 是矢量格式,放大不糊,还能嵌进网页。
安装过程不复杂,以常见的包管理方式为例,初始化一个项目目录,安装渲染引擎的依赖,建三个文件夹:src放描述文件,styles放样式定义,dist放渲染输出。这个结构清晰,后面接自动化脚本也方便。
mkdir diagram-design-demo cd diagram-design-demo mkdir src styles dist # 初始化项目并安装渲染依赖(具体包名依所选引擎而定)注意:不要把所有图塞进一个文件。一张图一个描述文件,命名和图的主题对应。这样 diff 的时候一目了然,也方便按需渲染。
4.2 定义样式文件
样式文件是整个规范的核心。我通常定义一个基础样式,再定义各类图元的样式。基础样式里放字体、字号、颜色变量。图元样式里引用这些变量。
举个例子,颜色变量定义成--color-primary、--color-secondary这样的形式,图元样式里写“服务用 primary,数据库用 secondary”。这样换色时只改变量值。字体同理,定义一个--font-family,全局引用。
间距也要在样式里定死。我一般定义--spacing-sm、--spacing-md、--spacing-lg三档,分别对应 8px、16px、24px。布局时按需引用,不要写魔法数字。
4.3 编写第一张图的描述
描述文件的结构通常是:先声明图的元信息(标题、方向),再声明节点(组件),最后声明边(关系)。节点里写 id、标签、类型。边里写起点、终点、标签。
我拿一个简化的订单系统举例。节点有:客户端、订单服务、支付服务、订单数据库、支付数据库。边有:客户端到订单服务、订单服务到支付服务、订单服务到订单数据库、支付服务到支付数据库。
写的时候注意,节点的 id 用前面说的三段式命名,标签用人类可读的中文或英文。类型对应样式文件里的图元样式。边也要有 id,方便后续引用和调整。
# 伪代码示意,具体语法依引擎而定 diagram order-system: direction: top-to-bottom nodes: - id: client-web label: 客户端 type: external - id: svc-order label: 订单服务 type: service - id: svc-payment label: 支付服务 type: service - id: db-order label: 订单库 type: database - id: db-payment label: 支付库 type: database edges: - from: client-web to: svc-order - from: svc-order to: svc-payment - from: svc-order to: db-order - from: svc-payment to: db-payment4.4 渲染与验证
写完描述后,运行渲染命令,输出 SVG 到dist目录。打开 SVG 检查三件事:布局是否合理、样式是否统一、文字是否溢出。
布局不合理通常是因为分层分组没做好,引擎把不该挨着的元素排在一起了。样式不统一多半是样式文件里漏定义了某个类型,引擎用了默认值。文字溢出则是标签太长,需要换行或缩短。
我一般会迭代两到三轮,第一轮看整体结构,第二轮调细节间距,第三轮确认文字。不要指望一次成型,声明式布局也需要调优。
4.5 接入自动化与版本管理
图稳定之后,把它接入自动化流程。最简单的做法是写一个脚本,遍历src目录下所有描述文件,批量渲染到dist。这样每次改完描述,跑一下脚本,所有图都更新了。
版本管理用 Git。描述文件和样式文件都是纯文本,diff 起来非常清晰。谁改了哪个节点、加了哪条边,一目了然。评审时直接看 diff,比看图片高效得多。
实操心得:给渲染脚本加一个
--watch模式,监听文件变化自动重新渲染。这样你改描述的同时就能看到图的变化,调布局效率翻倍。
5. 常见问题与排查技巧实录
5.1 布局错乱的排查思路
布局错乱是最常见的问题,表现是元素重叠、连线交叉严重、层次混乱。排查顺序我总结为“一看分组、二看方向、三看约束”。
先看分组,确认每个节点都归属到了正确的组里。漏分组或分错组,引擎就不知道该怎么排。再看方向,确认图的整体方向(从上到下还是从左到右)和局部的方向是否冲突。最后看约束,有些引擎支持指定“A 必须在 B 左边”这类约束,约束写多了会互相打架,导致布局失败。
如果三看都没问题,那就是引擎的布局算法本身有局限。这时候可以手动指定某些节点的位置作为锚点,让引擎围绕锚点排布。这是妥协方案,但有效。
5.2 样式不生效的常见原因
样式不生效,九成是引用路径或变量名写错了。检查样式文件是否被正确加载,变量名是否和引用处完全一致(大小写敏感)。还有一种情况是样式优先级问题,图元自带的样式覆盖了全局样式,需要显式声明优先级。
我踩过的一个坑是,样式文件里用了中文注释,某些解析器处理中文注释时会出错,导致后面的样式全部失效。后来统一改成英文注释,问题消失。所以样式文件里尽量别写中文,要写就写在描述文件里。
5.3 多人协作时的冲突处理
多人改同一张图,冲突不可避免。纯文本的好处是冲突可读,坏处是合并麻烦。我的做法是,把图拆得足够细,一个人负责一张图,减少交叉。如果必须多人改一张,约定好各自负责的节点范围,改之前先拉最新代码。
冲突发生时,不要盲目接受某一方。打开冲突标记,逐段看,通常只是两个人在不同位置加了节点,合并起来就行。真正麻烦的是两个人改了同一个节点的同一个属性,这时候需要沟通确认以谁为准。
5.4 常见问题速查表
| 问题现象 | 可能原因 | 排查动作 | 解决方式 |
|---|---|---|---|
| 元素重叠 | 分组缺失或错误 | 检查节点分组声明 | 补全分组,重新渲染 |
| 连线交叉严重 | 布局方向冲突 | 检查全局与局部方向 | 统一方向或加锚点 |
| 样式不生效 | 变量名或路径错误 | 核对样式引用 | 修正引用,检查优先级 |
| 文字溢出 | 标签过长 | 检查标签长度 | 换行或缩短标签 |
| 渲染报错 | 语法错误 | 看报错行号 | 修正语法,注意特殊字符 |
| 版本冲突 | 多人改同一文件 | 看 Git 冲突标记 | 逐段合并,沟通确认 |
5.5 独家避坑技巧
第一个技巧,给描述文件加 schema 校验。在提交前跑一遍校验,能拦住大部分低级语法错误。第二个技巧,把渲染产物也纳入版本管理,但只作为参考,不作为事实来源。这样回溯历史时能看到图的实际样子。第三个技巧,定期做一次“图表审计”,检查所有图是否还在用最新样式,有没有人偷偷加了不在规范里的颜色。这个审计可以脚本化,扫描描述文件里的颜色值,和规范比对。
6. 图表即代码:diagram-design 的长期价值
6.1 从维护成本看收益
我算过一笔账。以前维护十几张图,每次系统变更,平均要花两到三小时改图,一个月变更两次,就是四到六小时。一年下来五十到七十小时。用了 diagram-design 之后,改描述文件加渲染,平均二十分钟,一年不到十小时。省下来的时间,够写好几篇技术文档了。
这还没算沟通成本。以前评审时大家对着图猜“这个框是不是最新的”,现在直接看 Git 记录,谁什么时候改的、改了什么,清清楚楚。沟通效率的提升,比省下的画图时间更值钱。
6.2 对团队协作模式的影响
diagram-design 带来的一个隐性变化是,图表从“个人资产”变成了“团队资产”。以前图在谁电脑里,谁就是图的 owner,别人不敢动。现在图在仓库里,任何人可以提 PR 修改,评审通过就合并。这种模式让图表真正活了起来,而不是画完就死。
另一个变化是,新人的上手成本降低了。新人不需要学某个绘图软件,只需要看懂描述文件的语法,就能改图。语法比软件界面简单得多,半天就能上手。
6.3 适用边界与不适用场景
diagram-design 不是银弹。它适合结构化的技术图,不适合需要精细视觉控制的图,比如品牌宣传图、需要手绘风格的示意图。也不适合一次性、用完即弃的草图,那种场景下直接拖拽更快。
判断标准很简单:这张图会不会被反复修改?会不会有多人参与?会不会需要追溯历史?三个问题里有两个答案是“是”,就值得用 diagram-design。如果都是“否”,那就怎么快怎么来。
6.4 后续可以扩展的方向
如果这套流程跑顺了,可以往几个方向扩展。一是接入 CI,每次提交自动渲染并部署到内部文档站,图永远是最新的。二是做一套模板库,常见架构模式(比如微服务、事件驱动、分层架构)预置好描述模板,新项目直接套。三是和文档系统打通,文档里引用图表的 id,图更新了文档自动更新。
我在实际项目里最先做的是模板库,因为收益最直接。团队里八成的图都是那几种模式,有了模板,画新图就是填空。后来才慢慢接 CI 和文档系统。建议你也从模板库开始,别一上来就搞大而全的自动化,容易半途而废。
最后分享一个小技巧:给每张图的描述文件头部写一段注释,说明这张图的用途、最后更新时间和负责人。别小看这段注释,半年后你回头看,会感谢自己写了它。图表和人一样,需要一点“身份信息”,才不至于在仓库里变成孤儿文件。