
1. 从一张草图到一套系统diagram-design 到底在解决什么问题第一次看到 “diagram-design” 这个标题很多人会以为它只是一个画图工具或者某个模板库。但真正做过系统设计、技术方案评审、产品架构梳理的人会立刻意识到它指向的是一个更底层、更磨人的问题如何把脑子里那些零散、跳跃、半成品的结构关系稳定地转化成一张别人能看懂、能评审、能落地的图。我做了十多年一线项目画过的架构图、流程图、时序图、部署图、数据流图加起来少说也有大几百张。早期我用的是最笨的办法打开绘图软件拖方框、拉箭头、调对齐、改配色一张图折腾两三个小时改到第三版的时候自己都不想看了。后来我开始琢磨一件事——图不是画出来的是设计出来的。diagram-design 这个项目标题背后核心就是这套“设计先行”的方法论先定义图的语义结构再定义视觉规则最后才动手渲染。它解决的不是“怎么画”而是“怎么让图自己长成该有的样子”。这套东西适合谁如果你是后端开发、架构师、技术负责人需要频繁输出系统设计文档那它是刚需如果你是产品经理、项目经理需要把业务流程讲清楚它同样适用甚至你是写论文、做汇报的学生只要涉及“把复杂关系可视化”这套思路都能直接抄作业。它不依赖某个特定软件而是一套可以迁移到任意工具里的设计系统。我先把结论放在这里diagram-design 的本质是用工程化思维管理图的语义层、结构层和视觉层让图从“一次性手工作品”变成“可维护、可复用、可批量生成”的资产。下面我按自己实际落地的顺序把这套东西拆开讲透。2. 核心思路拆解为什么大多数人的图越画越乱2.1 图的三个层次语义、结构、视觉大部分人画图失败不是因为审美差而是因为把三个层次混在一起同时处理。你一边想“这个模块该放哪”一边想“这个框用什么颜色”一边又想“箭头怎么绕过去”大脑的多线程能力瞬间被榨干结果就是图越画越乱。diagram-design 的第一个核心思路就是强制分层语义层这张图要表达什么关系是调用关系、依赖关系、数据流向还是状态迁移语义层只关心“谁和谁之间发生了什么”不关心长什么样。结构层这些关系如何组织是分层、分簇、分时序还是分区域结构层决定图的骨架比如分层架构图天然是上下结构时序图天然是左右结构。视觉层颜色、线型、字号、间距、图标。视觉层只负责“让结构层更容易被眼睛解析”它不承担任何语义职责。我踩过最大的坑就是早期把语义和视觉绑死。比如我用红色表示“核心服务”结果后来核心服务变成了三个红色不够用了整张图就得重画。正确的做法是语义层用标签和分组表达重要性视觉层只是把标签映射成颜色。这样语义变了只改映射规则图的结构不动。2.2 为什么选择“声明式”而不是“拖拽式”拖拽式绘图比如传统画图软件的问题是你画的是像素结果不是关系描述。一旦某个节点要挪位置所有跟它相连的线都要手动重连。图越大维护成本呈指数上升。diagram-design 走的是声明式路线你用文本或结构化数据描述“有哪些节点、哪些边、哪些分组”渲染引擎负责自动布局。这跟写代码是一个道理——你声明“我要一个按钮”而不是手动去画一个按钮的每一个像素。声明式带来的直接好处有三个。第一版本可控图的定义就是一份文本文件可以进 Git可以 diff可以 code review。第二批量生成同一套结构定义换一套视觉主题就能输出适配不同场景的图。第三一致性所有图共用同一套布局规则不会出现这张图方框圆角、那张图方框直角的混乱。我实测下来用声明式方式维护一套包含 30 多个节点的微服务架构图改一个服务名只需要改一行文本重新渲染 3 秒出图。而用拖拽方式同样的改动至少要 10 分钟还容易漏改连线标签。2.3 设计系统的四个支柱把 diagram-design 落地成一套可复用的系统我总结出四个必须提前定义的支柱支柱作用不定义会怎样语义词汇表统一节点和边的类型名称同一种关系出现三种叫法读者懵布局规则决定自动排版逻辑每次布局靠手感图与图之间风格断裂视觉主题颜色、字体、线型映射改一次品牌色要重画所有图导出规范分辨率、格式、命名文档里图糊成一片评审时被吐槽这四个支柱里语义词汇表是最容易被忽略但最重要的。我见过太多团队A 画的图里叫“服务”B 画的图里叫“模块”C 画的图里叫“组件”其实说的是同一个东西。diagram-design 要求你在动手之前先把这张图里会用到的所有名词和动词列出来定义清楚。这一步花 20 分钟能省后面 2 小时的扯皮。3. 核心细节解析语义层怎么定义才不返工3.1 节点类型别超过七种心理学上有个经典结论人短期记忆能同时处理的信息块大约是 7±2 个。图的节点类型如果超过七种读者就需要频繁回看图例阅读体验断崖式下跌。我在实际项目里把节点类型控制在5 到 6 种比如服务Service可独立部署的单元存储Store数据库、缓存、对象存储队列Queue消息中间件外部系统External不在本系统控制范围内的依赖用户角色Actor触发流程的人或系统每种节点类型对应一个固定的视觉形状。比如服务用圆角矩形存储用圆柱体队列用平行四边形外部系统用虚线框。这样读者不用看图例光看形状就能猜出大概。注意节点类型一旦定下来整个项目周期内不要轻易增加。如果实在需要新类型优先考虑用“标签”而不是“新形状”来表达。比如“这个服务是核心服务”用加粗边框或角标表达而不是新造一个“核心服务”形状。3.2 边类型方向、线型、标签三要素边比节点更容易乱。我见过一张图里同时出现实线、虚线、点线、双线、带箭头、不带箭头、带菱形、带圆形……读者直接放弃。diagram-design 对边的定义只有三个维度方向有向还是无向。绝大多数技术图都是有向的无向边只在表示“关联”时使用。线型实线表示同步调用或强依赖虚线表示异步消息或弱依赖点线表示可选或未来规划。标签边上必须写清楚“发生了什么”。比如“HTTP 调用”“写入”“订阅”“推送”。我强烈建议每条边都要有标签。没有标签的边等于没说清楚关系评审的时候一定被问。标签的写法也有讲究用“动词名词”结构比如“查询订单”“写入日志”而不是只写“调用”。3.3 分组与边界让图有“房间感”一张没有分组的架构图就像一间没有隔断的大仓库所有东西堆在一起找什么都费劲。分组的作用是给图建立“房间感”让读者知道哪些东西属于同一个逻辑单元。常见的分组维度有三种按部署边界分组比如“客户端”“网关层”“服务层”“数据层”按业务域分组比如“订单域”“支付域”“用户域”按团队归属分组比如“基础架构组”“业务中台组”分组不要超过两层。一层大分组里面最多再套一层小分组。三层以上的嵌套读者会迷失在框里框外。实操心得分组框的标题放在左上角用比节点标题小一号的字号颜色用中性灰。这样分组框不会抢节点的视觉焦点但又能清晰界定范围。3.4 命名规范让图能“读”出来图不仅要能看还要能读。什么叫能读就是你把图上的文字按顺序念出来能形成一句通顺的话。我给自己定的命名规范是节点名用名词短语首字母大写比如“Order Service”“User Store”边标签用动词短语小写开头比如“queries”“writes to”“subscribes”分组名用范围名词比如“Data Layer”“Payment Domain”这样一张图读下来就是“Order Service queries Order Store, Order Service publishes to Payment Queue, Payment Service subscribes from Payment Queue……”逻辑链条清清楚楚。4. 实操过程从零搭建一套可复用的图设计系统4.1 第一步建立语义词汇表文件我习惯在项目根目录建一个diagram-vocab.md把所有节点类型、边类型、分组类型列出来。格式大概是这样## 节点类型 - service: 可独立部署的服务单元圆角矩形 - store: 数据存储圆柱体 - queue: 消息队列平行四边形 - external: 外部依赖虚线圆角矩形 - actor: 用户或触发者圆形 ## 边类型 - sync: 同步调用实线箭头 - async: 异步消息虚线箭头 - write: 写入实线箭头标签必填 - read: 读取实线箭头标签必填 - optional: 可选依赖点线箭头 ## 分组类型 - layer: 部署层次浅灰背景 - domain: 业务域浅蓝背景 - team: 团队边界浅绿背景这个文件是整个设计系统的“字典”。后面所有图的定义都只能引用这里出现过的类型不允许临时发明新类型。如果确实需要新类型先改字典再改图。4.2 第二步定义布局规则布局规则决定了图的“骨架”。我常用的三种布局模式分层布局Layered适合架构图、部署图。节点按层从上到下排列层与层之间用边连接。层内节点水平排列层间间距固定。力导向布局Force-directed适合关系网络、依赖图。节点根据连接关系自动散开连接多的节点自然聚在一起。缺点是每次渲染位置可能不同需要固定随机种子。时序布局Sequential适合流程图、时序图。节点按时间或步骤从左到右排列边表示流转方向。在声明式工具里布局规则通常通过属性指定。比如layout: layered direction: top-to-bottom layer-gap: 80 node-gap: 40这几个参数我调过很多次最后稳定在层间距 80px节点间距 40px节点宽度 160px节点高度 60px。这个尺寸在 1080p 屏幕上缩放 100% 时文字清晰可读整体又不至于太散。4.3 第三步配置视觉主题视觉主题是一组映射规则把语义类型映射到具体的颜色、字体、线宽。我通常定义两套主题一套浅色用于文档一套深色用于演示。浅色主题的核心参数元素颜色字号线宽service 填充#E8F0FE14px1.5pxservice 边框#1A73E8--store 填充#E6F4EA14px1.5pxstore 边框#34A853--queue 填充#FEF7E014px1.5pxqueue 边框#F9AB00--external 填充#F1F3F414px1.5px 虚线external 边框#5F6368--边颜色#5F636812px1.5px分组背景#F8F9FA12px1px 虚线这套配色我用了三年最大的优点是打印成黑白也不会糊。因为不同节点类型的填充灰度不同边框虚实不同即使没有颜色也能区分。注意不要用纯红、纯绿、纯蓝这种高饱和度颜色。高饱和色在投影仪上会刺眼在打印时会变成一团黑。用低饱和度的“粉彩系”颜色专业感更强。4.4 第四步编写图定义文件有了词汇表、布局规则、视觉主题就可以写具体的图定义了。我以一张典型的微服务架构图为例展示定义文件的结构title: 订单系统架构 layout: layered theme: light nodes: - id: user type: actor label: 用户 layer: 0 - id: gateway type: service label: API Gateway layer: 1 - id: order-svc type: service label: Order Service layer: 2 - id: payment-svc type: service label: Payment Service layer: 2 - id: order-db type: store label: Order DB layer: 3 - id: payment-queue type: queue label: Payment Queue layer: 3 edges: - from: user to: gateway type: sync label: HTTPS - from: gateway to: order-svc type: sync label: 路由 - from: order-svc to: order-db type: write label: 写入订单 - from: order-svc to: payment-queue type: async label: 发布支付消息 - from: payment-svc to: payment-queue type: async label: 订阅支付消息 groups: - id:>