1. 从一张草图到一套系统:diagram-design 到底在解决什么问题
第一次看到 “diagram-design” 这个标题,很多人会以为它只是教你怎么把图画得好看一点。但真正做过系统设计、写过技术方案、跟产品经理吵过架构图的人都知道,图好不好看只是最表层的事,真正要命的是:图画完了,信息没传达到位;图画完了,改一个节点要动五张图;图画完了,开发看完还是不知道从哪下手。
diagram-design 这个项目,核心就是围绕“图”这件事,把设计、表达、协作、维护串成一条线。它不是一个单纯的绘图工具教程,也不是某个软件的说明书,而是一套关于“如何用图来驱动设计决策”的方法论加实操体系。说得再直白一点:它要解决的是“图”和“设计”之间的断层问题。
我见过太多团队,架构图是架构图,代码是代码,文档是文档,三者之间没有任何强关联。图是画给领导看的,代码是写给机器跑的,文档是写给审计查的。结果就是,图上的模块和实际代码里的模块对不上,新来的同事照着图去读代码,读了两天发现完全不是那么回事。diagram-design 要做的,就是让图成为设计的“第一现场”,而不是事后补的“装修效果图”。
这个内容适合谁看?如果你是刚入行的开发,想学会怎么用图把自己的思路讲清楚,那它适合你。如果你是带团队的技术负责人,想解决“图文档代码三张皮”的问题,那它更适合你。如果你是做产品、做设计、做咨询的,需要频繁用图来对齐认知、推动决策,那这套东西你直接拿去就能用。
我自己的体会是,图这件事,门槛在“画”上,但天花板在“设计”上。会画流程图的人一抓一大把,但能用一张图把系统边界、数据流向、异常分支、扩展点全部讲明白的人,少之又少。diagram-design 的价值,就在于它把后面这层东西拆开了、讲透了、给出了可复用的套路。
2. 核心思路拆解:为什么是“设计”驱动“图”,而不是反过来
2.1 图的本质是信息压缩,不是美术创作
很多人一上来就纠结用什么工具、配什么颜色、用什么字体。这就像写文章先纠结用什么笔一样,方向错了。图的本质是信息压缩:把几百行代码、几十个接口、一堆边界条件,压缩成一张人脑能一次性处理的视觉结构。
diagram-design 的思路很明确:先想清楚你要压缩什么信息,再决定用什么图。你要表达的是时序关系,那就用序列图;你要表达的是状态流转,那就用状态机图;你要表达的是模块依赖,那就用依赖图。图种选错了,信息压缩就是失败的,画得再漂亮也没用。
我自己的经验是,一张图如果不能让一个没参与过项目的人在五分钟内说出“这个系统大概是怎么跑的”,那这张图就是失败的。diagram-design 里反复强调一个观点:图是给人看的,不是给工具看的。工具能解析的图,不一定人能看懂;人能看懂的图,工具不一定能解析。这两者之间的平衡,就是 diagram-design 要解决的核心矛盾。
2.2 从“画图”到“建模”:图是设计的副产品
传统做法是:先设计,再画图。设计在脑子里、在白板上、在文档里,图只是最后呈现的一个结果。diagram-design 反过来:图就是设计本身。你画图的过程,就是设计的过程。你改图的过程,就是改设计的过程。
这个思路的转变带来的最大好处是:图和设计永远同步。因为图不是“画”出来的,而是“长”出来的。你定义好节点、关系、约束,图自动生成。你改一个节点,所有相关的图自动更新。这就解决了“改一个地方要动五张图”的痛点。
我试过用纯文本的方式来做这件事。比如用类似 DSL 的语法描述系统结构,然后用工具渲染成图。这样做的好处是:图可以进版本控制,可以 diff,可以 code review。坏处是:学习成本高,不是所有人都愿意写代码来画图。diagram-design 在这两者之间找了一个平衡点:用结构化的方式来描述图,但描述方式尽量接近自然语言,让非技术人员也能参与。
2.3 图的“单一数据源”原则
这是 diagram-design 里最核心的一条原则:一个系统里,同一个信息只能有一个来源。如果你的架构图里写了“用户服务”,那“用户服务”这个节点的定义、职责、接口、依赖,只能在一个地方定义,其他地方都是引用。
这条原则听起来简单,做起来极难。因为大部分团队的图是“散装”的:架构图在 PPT 里,时序图在文档里,状态图在代码注释里,部署图在运维手册里。每个地方都有一份“用户服务”的定义,但每份定义都不一样。时间一长,没人知道哪份是对的。
diagram-design 的做法是:建立一个图的“元模型”。这个元模型定义了系统里有哪些类型的节点、哪些类型的关系、哪些类型的约束。所有的图都从这个元模型里实例化出来。你改元模型,所有图跟着变。你加一个新节点类型,所有图都能用。
这个思路跟数据库设计里的“范式”很像。第一范式是消除重复,第二范式是消除部分依赖,第三范式是消除传递依赖。图的单一数据源,本质上就是图的“第三范式”:每个信息只出现一次,且只依赖于主键。
2.4 为什么选择“设计驱动”而不是“工具驱动”
市面上画图的工具太多了,从最基础的画板到专业的建模工具,从纯文本的 DSL 到拖拽式的 GUI,每个工具都有自己的拥趸。diagram-design 不绑定任何特定工具,它讲的是一套方法,工具只是实现这套方法的载体。
为什么这么设计?因为工具会过时,方法不会。你今天用这个工具画的图,明天换工具就废了。但如果你掌握的是“如何用图来表达设计”的方法,换什么工具都能快速上手。
我自己的做法是:先用纸笔把图的结构想清楚,再用工具去实现。纸笔的好处是快、自由、没有工具的限制。你可以在纸上随便画,画错了划掉重来,没有任何心理负担。等结构想清楚了,再用工具去“誊抄”。这个过程看起来多了一步,但实际上省了很多时间。因为你在纸上改十遍,比在工具里改一遍还快。
3. 核心细节解析:图的类型、要素与表达技巧
3.1 四种核心图类型及其适用场景
diagram-design 里把图分成了四大类,每类解决不同的问题。这个分类不是拍脑袋定的,而是根据“信息维度”来划分的。
| 图类型 | 核心维度 | 适用场景 | 典型问题 |
|---|---|---|---|
| 结构图 | 空间/组成 | 系统模块划分、部署架构 | 系统由哪些部分组成 |
| 行为图 | 时间/流程 | 业务流程、状态流转 | 系统怎么跑起来 |
| 交互图 | 角色/消息 | 接口调用、协议交互 | 模块之间怎么通信 |
| 数据图 | 关系/约束 | 数据模型、依赖关系 | 数据怎么组织 |
结构图回答“是什么”,行为图回答“怎么跑”,交互图回答“怎么连”,数据图回答“怎么存”。这四类图覆盖了系统设计的全部核心维度。你不需要每类都画,但你需要知道在什么阶段该画什么图。
我见过很多团队,一上来就画架构图,结果画了半天发现业务流程没理清,架构图改了又改。正确的顺序应该是:先用行为图把流程跑通,再用交互图把接口定下来,然后用数据图把模型建好,最后用结构图把部署定下来。这个顺序不是绝对的,但大方向是这样。
3.2 图的五个核心要素:节点、边、标签、分组、注释
任何一张图,不管多复杂,拆到最底层都是这五个要素。把这五个要素用好,图就成功了一半。
节点是图里的“名词”,代表一个实体。节点可以是一个服务、一个模块、一个数据库、一个用户角色。节点的命名要遵循“单一职责”原则:一个节点只代表一件事。如果你发现一个节点里塞了太多东西,那说明你需要把它拆开。
边是图里的“动词”,代表节点之间的关系。边可以是有向的,也可以是无向的。有向边表示依赖、调用、流向;无向边表示关联、协作、通信。边的方向很重要,它决定了信息的流向和依赖的方向。
标签是图里的“形容词”,用来补充节点的属性或边的条件。标签要精简,能用一个词说清楚就不要用一句话。标签太多,图就变成了文字堆砌,失去了视觉压缩的意义。
分组是图里的“容器”,用来把相关的节点放在一起。分组可以按层次分、按功能分、按部署单元分。分组的好处是降低认知负荷:人脑一次能处理的元素是有限的,分组可以把复杂度控制在可接受的范围内。
注释是图里的“旁白”,用来解释特殊的设计决策或例外情况。注释要克制,只在必要的地方加。注释太多,图就变成了文档,失去了图的优势。
3.3 图的布局原则:从左到右、从上到下、从外到内
布局是图的“语法”。同样的节点和边,不同的布局,传达的信息完全不同。diagram-design 推荐三种基本布局:
从左到右适合表达流程和时序。左边是起点,右边是终点,中间是过程。人眼习惯从左到右阅读,所以这种布局最自然。
从上到下适合表达层次和依赖。上面是上层,下面是下层,中间是接口。这种布局适合表达“谁依赖谁”的关系。
从外到内适合表达边界和领域。外面是外部系统,里面是内部模块,最里面是核心领域。这种布局适合表达“系统边界”和“领域划分”。
我自己的经验是:一张图里不要混用多种布局。要么全从左到右,要么全从上到下。混用布局会让读者迷失方向,不知道从哪里开始看。
3.4 图的抽象层次:C4 模型的借鉴与简化
C4 模型是软件架构图的一个经典框架,它把架构图分成了四个层次:Context(上下文)、Container(容器)、Component(组件)、Code(代码)。diagram-design 借鉴了这个思路,但做了简化。
在 diagram-design 里,图的抽象层次只有三层:系统层、模块层、实现层。系统层回答“系统跟谁交互”,模块层回答“系统由哪些模块组成”,实现层回答“模块内部怎么实现”。
为什么要简化?因为大部分团队根本用不到四层。你画了 Code 层的图,没人看,也没人维护。与其画一张没人看的图,不如把系统层和模块层的图维护好。
我自己的做法是:系统层和模块层的图必须维护,实现层的图按需维护。什么叫按需?就是当某个模块的逻辑特别复杂,光看代码看不懂的时候,才画一张实现层的图。画完就归档,不强制更新。这样既保证了核心图的准确性,又避免了维护负担。
4. 实操过程:从零开始设计一套图体系
4.1 第一步:定义图的元模型
元模型是图的“宪法”。它定义了系统里有哪些类型的节点、哪些类型的边、哪些类型的属性。元模型不需要很复杂,但必须清晰。
我通常用一张表格来定义元模型:
| 元素类型 | 名称 | 属性 | 说明 |
|---|---|---|---|
| 节点 | 服务 | 名称、职责、负责人 | 一个可独立部署的单元 |
| 节点 | 数据库 | 名称、类型、容量 | 一个数据存储单元 |
| 节点 | 外部系统 | 名称、协议、SLA | 不在本系统控制范围内的系统 |
| 边 | 调用 | 协议、同步/异步 | 服务之间的调用关系 |
| 边 | 依赖 | 方向、强弱 | 模块之间的依赖关系 |
| 边 | 数据流 | 格式、频率 | 数据在节点之间的流动 |
这张表就是元模型。它定义了“你可以画什么”。任何图里的元素,都必须能在这张表里找到对应的类型。找不到的,要么是元模型不完整,要么是你画错了。
定义元模型的好处是:图有了“语法”。不同的人画出来的图,风格可能不同,但结构是一致的。新人一看图,就知道每个元素代表什么,不需要额外的解释。
4.2 第二步:建立图的目录结构
图不是孤立存在的,它们之间有引用关系。所以需要一个目录结构来管理这些图。
我推荐按“系统-模块-场景”三级来组织:
diagrams/ ├── system/ │ ├── context.md │ └── deployment.md ├── modules/ │ ├── user-service/ │ │ ├── structure.md │ │ └── state.md │ └── order-service/ │ ├── structure.md │ └── state.md └── scenarios/ ├── user-login.md └── order-create.mdsystem 目录放系统级的图,modules 目录放模块级的图,scenarios 目录放场景级的图。每个图都是一个独立的文件,用 Markdown 或 DSL 编写。
这个结构的好处是:图的位置固定,引用方便。你在写文档的时候,可以直接引用某个图的路径,不需要复制粘贴图的内容。
4.3 第三步:用 DSL 描述图
DSL 是 diagram-design 的核心实操手段。它让你用文本的方式描述图,然后用工具渲染成图片。这样做的好处是:图可以进版本控制,可以 diff,可以 code review。
我常用的 DSL 语法是这样的:
service UserService { description: "用户服务,负责用户注册、登录、信息管理" owner: "用户组" } service OrderService { description: "订单服务,负责订单创建、支付、状态流转" owner: "交易组" } database UserDB { type: "MySQL" description: "用户数据库" } UserService -> UserDB: "读写用户数据" OrderService -> UserService: "查询用户信息" OrderService -> OrderDB: "读写订单数据"这段 DSL 描述了一个简单的系统结构。你可以把它渲染成一张架构图,也可以把它导出成其他格式。关键是:这段文本可以进 Git,可以 review,可以改。
我自己的体会是:DSL 的学习成本主要在前两天。前两天你会觉得别扭,觉得不如拖拽方便。但过了前两天,你会发现 DSL 的效率是拖拽的十倍。因为你可以用键盘完成所有操作,不需要在鼠标和键盘之间来回切换。
4.4 第四步:图的渲染与发布
DSL 写好了,下一步是渲染成图。渲染工具的选择取决于你的团队习惯。有的团队喜欢用命令行工具,有的团队喜欢用在线服务,有的团队喜欢集成到 CI/CD 里。
我推荐的做法是:把渲染集成到 CI/CD 里。每次提交 DSL 变更,CI 自动渲染成图,并发布到内部文档站点。这样保证了图永远是最新的,不需要手动更新。
渲染出来的图,我建议同时提供两种格式:SVG 和 PNG。SVG 用于网页展示,清晰度好,可以缩放;PNG 用于文档嵌入,兼容性好,不会因为字体问题显示异常。
4.5 第五步:图的评审与迭代
图不是画完就完了,它需要评审和迭代。评审的目的是:确保图表达了正确的信息,且没有歧义。
我通常用“三问法”来评审一张图:
第一问:这张图回答了什么设计问题?如果回答不了任何问题,那这张图就是多余的。
第二问:这张图的信息是否完整?有没有遗漏关键节点或关键关系?
第三问:这张图是否容易理解?一个没参与过项目的人,能不能在五分钟内看懂?
这三个问题问下来,大部分图的问题都会暴露出来。要么是信息不全,要么是表达不清,要么是根本没必要画。
迭代的频率取决于系统的变化速度。如果系统每周都在变,那图也要每周更新。如果系统很稳定,那图可以一个月更新一次。关键是:图不能落后于系统太多。落后太多的图,还不如没有图。
5. 常见问题与排查技巧实录
5.1 图太复杂看不懂怎么办
这是最常见的问题。一张图里塞了五十个节点、一百条边,密密麻麻像蜘蛛网。解决思路是“分层”和“分场景”。
分层的意思是:把一张大图拆成多张小图。系统层一张,模块层一张,实现层一张。每张图只关注一个层次的信息,不要把不同层次的信息混在一起。
分场景的意思是:把一张全量图拆成多个场景图。比如“用户登录”场景一张图,“订单创建”场景一张图。每张图只关注一个场景的流程,不要把所有的流程都画在一张图里。
我自己的经验是:一张图里的节点数量不要超过十五个,边不要超过二十条。超过这个数量,人脑就处理不过来了。如果确实需要画这么多节点,那就拆图。
5.2 图跟代码不一致怎么办
这是第二常见的问题。图上的模块叫“UserService”,代码里的模块叫“UserManager”。图上的依赖是 A 调用 B,代码里是 B 调用 A。这种不一致,时间一长就会导致图彻底失去信任。
解决思路是“自动化校验”。如果你的 DSL 和代码之间有映射关系,可以写一个校验脚本,定期检查图跟代码是否一致。不一致就报警,强制更新。
如果做不到自动化校验,那就退而求其次:在 code review 的时候,把图也纳入 review 范围。改了代码,必须同步改图。不改图,code review 不通过。
我试过最有效的方法是:把图的更新纳入 Definition of Done。什么叫 Done?代码写完不算 Done,测试通过不算 Done,图更新了才算 Done。这个规则看起来很严,但执行一个月之后,大家就习惯了。
5.3 图没人看怎么办
图没人看,通常是因为两个原因:要么图太难懂,要么图跟实际工作没关系。
图太难懂,就简化。简化到新人能看懂为止。图跟实际工作没关系,就把图嵌入到工作流里。比如:新员工入职,第一件事是读图;技术方案评审,第一件事是看图;故障排查,第一件事是查图。
我自己的做法是:把图放在最显眼的地方。内部文档站点的首页放系统图,每个模块的 README 放模块图,每个场景的文档放场景图。让图无处不在,大家自然就会看。
5.4 常见问题速查表
| 问题现象 | 可能原因 | 排查思路 | 解决方法 |
|---|---|---|---|
| 图太复杂 | 节点太多、层次混杂 | 数节点数量,检查是否混层 | 拆图,分层分场景 |
| 图跟代码不一致 | 缺少同步机制 | 对比图上的模块名和代码模块名 | 自动化校验或纳入 DoD |
| 图没人看 | 图难懂或与工作无关 | 问新人能不能看懂,问开发用不用 | 简化图,嵌入工作流 |
| 图改不动 | DSL 太复杂或工具太重 | 检查 DSL 语法,检查工具链 | 简化 DSL,换轻量工具 |
| 图风格不统一 | 缺少元模型 | 检查是否有元模型定义 | 定义元模型,统一规范 |
5.5 几个容易踩的坑
第一个坑:一开始就追求完美。图是迭代出来的,不是一次画好的。先画一版粗糙的,然后慢慢改。不要因为第一版不好看就不画。
第二个坑:用工具代替思考。工具只是手段,思考才是目的。不要因为工具好用就画一堆没用的图。每张图都要有明确的目的。
第三个坑:忽略图的维护成本。图是有维护成本的。画一张图容易,维护一张图难。所以不要画太多图,只画必要的图。
第四个坑:图跟文档脱节。图是文档的一部分,不是独立存在的。图要嵌入文档,文档要引用图。两者要一起维护。
6. 工具选型与团队落地建议
6.1 工具选型的三个维度
选工具的时候,不要看功能多少,要看三个维度:学习成本、维护成本、集成能力。
学习成本决定团队能不能用起来。如果一个工具要学一周才能上手,那大部分团队成员会放弃。学习成本越低越好。
维护成本决定图能不能持续更新。如果一个工具每次更新图都要手动操作,那图很快就会过时。维护成本越低越好。
集成能力决定图能不能嵌入工作流。如果一个工具不能跟 Git、CI/CD、文档站点集成,那图就是孤岛。集成能力越强越好。
基于这三个维度,我推荐的工具组合是:DSL + 命令行渲染 + CI/CD 集成。DSL 学习成本低,命令行渲染维护成本低,CI/CD 集成能力强。
6.2 团队落地的四个阶段
第一阶段:试点。选一个模块,用 diagram-design 的方法画图。画完之后,让团队成员评审。收集反馈,调整方法。
第二阶段:推广。试点成功后,推广到其他模块。每个模块指定一个“图负责人”,负责该模块的图维护。
第三阶段:制度化。把图的更新纳入开发流程。改代码必须改图,不改图不算完成。
第四阶段:自动化。把图的渲染和发布集成到 CI/CD。每次提交自动渲染,自动发布。
这四个阶段不是线性的,可以并行。但大方向是这样:先试点,再推广,再制度化,再自动化。
6.3 我自己的实操心得
我自己的体会是:diagram-design 最难的不是画图,而是让团队接受“图是设计的一部分”这个观念。大部分团队习惯了“先写代码,再补图”,要让他们改成“先画图,再写代码”,需要时间和耐心。
我的做法是:从最小的场景开始。不要一上来就画系统架构图,先画一个简单的流程图。让团队感受到图的好处:画完图之后,讨论效率提高了,返工减少了。有了正反馈,再推广到更大的场景。
还有一个心得是:图要“活”的,不要“死”的。什么叫活的图?就是能跟着代码一起变的图。什么叫死的图?就是画完就扔在那,没人管的图。活的图才有价值,死的图只是负担。
最后再分享一个小技巧:给图加“时间戳”。每张图的头部写上最后更新时间。这样大家一看就知道这张图是不是最新的。如果时间戳是半年前的,那这张图的可信度就要打折扣。这个小小的习惯,能大大提升图的可信度。