☰
从画图到设计:用文本化DSL把架构图变成可维护的工程资产
2026/10/15 8:25:29 网站建设 项目流程

平时我见得最多的“图”,不是最终文档里那张漂亮的架构图,而是评审会上被临时画在白板上的方框加箭头。主讲人一边画一边改,台下的人一边看一边猜。等会议结束,没人记得箭头谁指向谁,只记得“好像讲了一个方案”。后来我在自己的项目里强制把画图环节前置,并且全部用文本化方式设计,才意识到一件事:diagram-design 不是美术工作,它是把复杂系统压缩成一张可讨论图纸的信息设计过程。这篇文章就想聊聊我怎么把“画图”变成“设计”、把“图片”变成“资产”的实操经验。适合经常画架构图、业务流程图、部署图的产品、研发和解决方案同学参考。

1. 从“画图一时爽”到“设计有章法”:diagram-design到底在解决什么问题

1.1 图是思考工具,不是汇报装饰

我先抛一个观点:一张图最脆弱的时刻,就是它画完的那一刻。因为画完以后大家马上盯着它提问,而你如果只是随手拖出来的方块,很难经得起连续追问。第一次产生这种感受,是某次讲解订单系统改造。白板上有五个服务、四条数据库、一堆消息队列,我画到第八个箭头的时候,自己都分不清有一条线是“调用”还是“订阅”。后来我把同样内容用文本DSL重新写了一遍,每条关系都必须写成一行明确语义的句子,结果发现问题出在有一项依赖实际上是双向调用,之前在白板上一条单向箭头完全表达不了。

diagram-design解决的不是美观问题,而是信息完整性与一致性问题。图上每一个图形都必须回答问题:这个对象是什么,和谁发生关系,关系是什么类型。做不到这一点的图,无论配色多好都是无效图。所以我更愿意把diagram-design看成一种思考工具:在画图的过程中,逼你把隐藏假设暴露出来。只要你的箭头含糊一次,设计就会含糊一次。很多开发者习惯先写代码后补图,图只是外置文档,但真正有效的做法是让图先诞生,用图来验证思路,代码只是图的具体实现。顺序反了,图的纠错价值就荡然无存。

1.2 文本化是工程化第一步

为什么强调文本化?因为图片格式很难做工程管理。想象一下:你收到同事发来一张架构图PNG,想提修改意见,只能在聊天里说“右下角那个框标错了”。对方改完发来一个新PNG,你根本不知道他改了哪里。如果图是文本源码,就能像代码一样逐行审阅、自动比较、留下评论。我所在的团队很早之前就约定:架构图、时序图、状态图全部以文本文件入库,不允许提交导出后的图片作为唯一真源。术语上,这种用特定语法描述图形的方式常叫DSL制图。它的核心思路很简单——用结构化文字定义节点和连线,渲染引擎负责画布布局。

下面是一段极简示意(text格式,不是某个具体工具):

[用户] --调用--> [订单服务] [订单服务] --发布--> [订单事件] [订单事件] --触发--> [库存扣减]

三行文字,表达了一个清晰链路。你能在代码评审里看到这三行改动,可以问“订单事件触发库存,是同步还是异步”。图一旦变成文本,就有了讨论的锚点。这就是工程化基础。更进一步,文本图还可以通过脚本批量检查:有没有孤立节点、有没有指向不存在的目标、有没有重复连接。这些检查写起来并不复杂,但用图片根本没法自动化。所以我认为,只要图需要长期维护,文本化就应该是默认选项,而不是备选。

2. 工具链与工作流:为什么我放弃了拖拽画布

2.1 拖拽画布的三个隐性成本

早期我也用通用绘图工具拖框,后来发现有三个成本长期被忽略。第一,维护成本。框和线的位置是一次性动作,只要需求变一次,布局就得重新调一次,一个二十节点的架构图每次改完都像玩一笔画。第二,评审成本。图片文件无法diff,两个版本之间只能肉眼对照,眼神差一点就会漏掉一条新增的虚线。第三,复用成本。每次都要从零重新画一遍类似的组件,没法抽取一个公共模块,更没法动态生成多张图的联动关系。这三个成本在单张图上感受不明显,一旦图的数量上到几十张,全部变成负资产。

文本化DSL则不同:布局是引擎自动算的,用户表达的只有语义。我修改一行文字,增加一个节点,引擎自动重排。有人担心自动布局不如手工排得好看,这很真实,但我接受的代价是:语义关系稳定,布局变化可接受。这类似于写代码和用Word排版写代码的区别——前者真正在构建逻辑,后者把大量精力耗在对齐美观上。时间长了你会发现,自动布局恰恰逼你放弃“用手摆放”的执念,转而关注结构本身,而结构才是图的灵魂。

2.2 适合文本化制图的典型场景

并不是所有图都适合文本化。如果核心诉求是自由表达、随意涂鸦,拖拽画布反而更好;如果要输出规范化模型,文本化胜出。我给自己定的选择标准是三条:是否要长期维护,是否会被多人修改,是否要嵌入技术文档。满足其中两条,就优先使用文本化。典型的适合场景包括:系统架构图、部署拓扑图、时序图、状态机图、业务流程图。这些图都有明确节点和连线,适合用结构化描述。不适合的场景:产品概念草图、手绘风的用户旅程地图、需要大量自由注释的灵感板。这类图重点在“感觉”,而不是“准确”,即便强行文本化也只是收获一个难用的玩具,我不建议在工具上给自己找不痛快。

另外还有一个容易被忽视的维度:图的“生命周期”。一次性的临时讨论图,白板效率最高;要持续演进的系统蓝图,文字化几乎是唯一可靠载体。我的建议是两类图分开管理,临时图拍完照就让它消失,正式资产必须进入版本库。很多人把临时图截图贴在文档里,半年后没人知道它是临时的,才酿成误导。

2.3 图谱文件工程化管理:目录、命名、版本

选完工具,更重要是组织文件。很多人的图都躺在“未命名00.png”“最终版01.png”里,这等于没有管理。我的做法是开辟独立的diagrams目录,按业务模块分文件夹。每个文件命名包含场景和作用,例如:

  • order-core/architecture-overview.txt
  • order-core/flow-order-create.txt
  • order-core/state-order-status.txt

文件内第一行写目标读者,第二行写关键图例,然后再写正文。每次改动随代码分支提交,PR里可以看见图片内容的变化。这里有个小技巧:文件头加一行last-review: 2024-03-20,逼着团队定期检查过期图。这个习惯让我少被很多旧架构图误导。版本管理我完全依赖代码仓库的分支和tag,而不是复制“最终版副本”。当业务大版本升级时,我会把当前目录复制为archive-2024-v1,给老图一个完整归宿。清楚知道老图在哪里,新图才敢放手改。

3. 一张高质量diagram的完整设计流程

3.1 动图前先回答三个问题

拿到需求,先不要急着画,先回答三个问题:这张图给谁看?想让他看完做什么决定?他需要知道多细?这三个答案不同,出来的图完全不同。例如:给新同学看的模块概览,可以把中间件都合并成一个“基础设施”节点;给运维看的部署图,则必须画出每个实例、端口和依赖顺序。层次也可以分:系统上下文图(所有外部角色和系统)、容器图(主要技术模块)、组件图(内部模块交互)。大多数人的问题不是信息太少,而是把三个层次的图揉在一张图里。画图之前先选好层次,能避免一半的布局灾难。

我见过太多“全图”:一个框里塞了十几个微服务,每个下面又列了数据库、缓存、消息队列,最后连作者本人都不敢保证每条线的方向是对的。正确做法是先画一张上下文图,只表达“用户、系统、外部依赖”三者关系;再按业务域分别画内部图。图层级之间用链接互相引用,而不是复制粘贴。记住,一张图只负责说服一个读者做出一个判断,其余信息全部留给其他图。

3.2 布局与连线:语义优先于美学

布局的目的是让读者不费劲地找到阅读路径。我看图时优先遵守几条原则:上下方向表达调用链或时间顺序,同一水平的节点表示并列;核心服务放中间,外部依赖靠边;箭头永远指向数据或控制流方向,而不是“相关”这样的暧昧关系。以下格式是我常用的文本化写法:

[客户端] --HTTPS--> [网关] [网关] --RPC--> [订单中心] [订单中心] --事件--> [消息中心]

每条线都明确标注传输方式,不让读者猜。如果节点超过十五个,我用大括号把同类节点包成组。比如“中间件组”内部有缓存、消息队列、日志,对外只显示为一个组,细节另画子图。这既是布局技巧,也是信息过滤技巧。连线标签也要讲究,尽量用一句话主谓宾描述,而不是只写“数据”“调用”这种没营养的词。标签写到哪里,往往就逼着你把这个问题想清楚:这俩到底是怎么发生的?同步还是异步?协议是什么?写不出来,说明关系还没定义好。

3.3 视觉规范:颜色、字体、图例一个都不能少

技术图不需要五彩斑斓,但必须有稳定的视觉语言。我建议定义一套极简色板:主色表示核心模块,中性灰表示基础设施,黄色表示需要关注的风险项,蓝色表示外部集成。全图颜色不超过四种,也不要用太接近的两种颜色,否则色盲读者会直接失明。字体统一,标题字号比正文大一号即可。每个diagram的右下角固定放一个图例,解释实线、虚线、彩色节点分别代表什么。这样新读者不用靠上下文猜。如果团队有前端组件库或品牌色,直接沿用,保证图和产品对外视觉一致。没有强制要求时,从系统里复制已有的颜色值,不要靠肉眼取色。

这里要特别说一句:图例不是可选项。很多人觉得大家都懂,所以省略图例,但不同人对虚线有不同理解。有人认为虚线是异步,有人认为虚线是“可选调用”。一旦图例缺位,这些歧义会长期潜伏。我的习惯是在文件头部写死了五种线型定义,引用其他文件时也一致。如果有人私自发明新线型,评审阶段就会被打回。

3.4 导出交付:从源码到文档的无缝衔接

完成图以后,很多人的做法是“截图发群里”。我建议多走两步。第一步,选择格式:如果是网页或技术文档,导出SVG;如果是聊天和演示,导出PNG,dpi要设成150以上,避免发出去变糊。第二步,嵌入文档时写清楚这张图对应的源码路径。比如文档配图下写一行“源码见 diagrams/order-core/architecture-overview.txt”。读者看到老图时可以顺藤摸瓜改源码,而不是复制到画图工具里重画。需要特别注意隐私:导出前检查节点名、IP、Token等敏感信息,历史上有过把内网地址画进去的错误。还有,图里不要用看不懂的缩写,如果不得不用,在第一次出现处标注全称。

交付物不只是一张图,而是一组配套信息:图片、源码路径、适用版本、审查日期。我自己在发布文档前会跑一遍渲染脚本,把生成的SVG和PNG都留档。这样即使有人改了源码导致渲染失败,文档里仍能显示上一次正常版本,避免线上文档突然图裂开。

4. 我在实际项目中踩过的坑(问题速查与排查思路)

4.1 布局乱成蜘蛛网怎么办

大概率是节点数量超过工具自动布局的合理范围。单个图里超过二十个具体节点,自动布局基本就会乱。我的处理步骤:先数节点,如果超了,拆成多层图;如果没超,改成按业务流程从上到下或从左到右排列;仍然乱,就强制指定节点分组,把关系紧密的放进一个子图。自动布局不是万能,它不懂业务。比如两个模块逻辑相邻,但业务上应该分属两个泳道,这时候需要手动分组。在DSL里显式声明分组是布局的第一步,不要指望引擎能理解“这个接口属于前端,那个接口属于后端”这类领域知识。

一条很实用的经验:当图被反复调整布局都难看,往往不是布局算法的问题,而是节点数量或分组错了。我见过最严重的案例,一张支付链路图有四十多个节点,十几个跨线,怎么看都像意大利面。后来拆成“下单流程”“支付渠道”“对账任务”三张图,问题立刻消失。少即是多在diagram设计里不是美学口号,而是认知规律:人的工作记忆只容得下少量元素。

4.2 连线复杂到看不清是谁指向谁

连线乱通常有两个原因:一是关系表达粒度太粗,一个节点与几十个节点都有连线;二是没有区分关系类型。第一种情况引入中间集散节点,比如把“所有服务都发邮件告警”简化成“服务 --> 告警中心 --> 渠道适配器 --> 邮件”,一下子从多对多变成一对多。第二种情况强制自己为每条线写标签,写着写着就会发现有些线根本不需要画出来,因为标签解释不清楚。线实在太多时,不要试图在一张图里表达完,切一个“数据流视角”和一个“控制流视角”,读者更容易接受。

还有一个经常被忽略的技巧:把双向箭头拆成两条单向边,并且标注不同颜色或线型。很多人用一条双箭头表示“调用并回调”,这其实是两个独立交互,混在一起永远说不清。我在设计接口时,要求每条边必须有明确发起方和接收方,这样渲染出来的图天然清晰,也顺便帮我发现了很多双向依赖的设计坏味道。

4.3 多人协作后风格开始失控

几个同学分别画三张图,色号不同、箭头含义不同,整合到一起非常痛苦。我们后来做了几件事:第一,在公共模块定义统一主题,颜色、线形、字体全部走公共变量;第二,把图例做成模板文件,每个新图必须复制模板头部;第三,code review时增加检查项“图例是否完整、是否与规范一致”。让规范长在公共文件里,而不是写在文档里,后者没人看。另外,当一个人总是修改另一个人图的布局时,停下来看看是不是图太拥挤,往往调整信息层级比调整坐标更有效。

协作中最怕的就是“我觉得好看”。好看是非常主观的,规范才是客观的。我把规范做成模板文件后,新人出图的效率提升了非常多,而且不需要我逐条标注“虚线不要用红色”“字体用统一字号”,模板直接约束住。图例变了,模板一变,所有引用模板的图全部跟随。这就是文本化的红利:可以定变量,可以继承,可以模板化。

4.4 渲染和导出永远差最后一步

常见现场:本地渲染正常,导出PDF后发现边界截断;或是在PR里看是好的,发到聊天工具里被压缩成一团糊。原因是画布尺寸和字体渲染差异。我的排查顺序:先检查文本是否过长,超过一定字数会被截断,改为缩写加图例;再检查画布边界设置,预留5%-10%的padding;最后检查字体——中文字体在某个渲染器里行高不同,会导致上下错位。如果所有都正常,换一个渲染后端试试,很多DSL制图工具支持多渲染后端,不同后端的布局有差异,需要统一在CI里固定渲染版本,避免“昨天能跑今天不行”。

下面把高频问题整理成速查表,方便现场排查:

现象可能原因典型排查动作
布局乱节点过多或缺少分组拆图、加子图分组
线重叠多对多关系未收敛引入集散节点中间层
风格混乱多人各自定义颜色使用公共主题和模板
导出截断画布padding不足调整边界余量,缩小文本字号
中文乱码/错位字体缺失或行高差异固定字体资源,统一渲染环境
渲染结果不稳定工具版本升级锁定CI中的版本号

这张表看起来很简单,但我自己在实际项目里至少每条都踩过两遍以上。尤其是“渲染不稳定”,版本升级以后旧图布局完全变样,差点让文档配图全部失真。从那以后,我把渲染环境写进容器镜像,任何机器构建结果一致。

5. 把 diagram 当代码维护:从单张图到图像资产

5.1 用“组件化”思想拆图

图多了以后,你会发现自己重复画了很多相似组件。比如“网关”“鉴权”“日志”几乎出现在每张架构图里。把它们抽到公共模块,一张图通过几个引用拼接而成。这样改一次,所有引用都会更新。这和写代码抽函数完全一样。但要注意过度抽象:如果公共模块参数太多,调试成本反而上升。我的经验是公共组件只放稳定不变的默认样式和结构,各业务特有的细节留在各自文件里,通过覆盖机制调整。

举个例子,网关这个组件在十张图里都出现,但每张图里它的下游并不相同。公共组件只定义形状、颜色和标签,下游关系留在业务图中。这样当你决定把“网关”的展示名称改成“API入口”时,只改公共组件,十张图一起生效。如果不抽公共组件,十张图里会有十份手工拷贝,必定漏掉几个。组件化不仅省事,更重要的是保证同一概念在不同图里长得一样,减少认知割裂。

5.2 给图写注释、元信息和图例

文本图比图片图天然多了“注释”这个表达通道。我习惯在每个节点后加上职责描述,例如:

[订单中心] : 负责订单创建与状态流转 [订单中心] -- 创建 -> [订单持久化] : 事务性写入

这比单独的一张“组件说明表”更贴近图,读图者不用来回切换。还可以在文件头部写三个元信息:目标读者、最近确认者、上次审查时间。有位置标注TODO也行,保证图能被持续维护。图例也是元信息的一部分,放最顶部或右下角,线型说明不要太长,能区分实线虚线即可。

注释还有个独特作用:当图要转交给其他人维护时,注释就是交接文档。很多图之所以很快腐烂,不是因为画错了,而是因为当初的设计背景没有留下来,后人不敢动。有了注释,至少能知道“这里为什么是异步”,后人才能判断是否仍然适用。我会在关键节点写上一句“如果此服务拆分,需要同步修改XX图”,让引用关系变成显式约束。

5.3 评审、合并与多版本维护实操

我们现在的流程是:任何涉及架构变动的PR,必须带一张更新后的diagram源码。CI里跑一遍渲染,把生成的SVG附到PR评论中,评审人直接看图提意见。合并后源码归档,老版本随代码仓库天然留存。如果线上系统架构演进,要保留至少当前版本和上一版本两张图,方便对比。这里最重要的一个心得:不要通过“新建副本”维护版本,要相信版本管理工具。新建的“最终版2”越多,仓库越乱,最后没人知道哪张是真的。放弃人类记忆,全部交给系统记录。

日常修改时,我也尽量让一次PR只改一张图的核心信息。如果一张图动了大半,评审人会很难看出实质性变化。必要时用脚本生成前后两版图并排预览,高亮差异区域。这种“视觉diff”能力是图片工作流根本无法实现的。现在我们把diagram-design做成了团队基础设施的一部分,新同学入职第一周就要学会提交一张能通过CI渲染的架构图,这不是炫技,而是确保所有设计决策都有据可查。

我自己踩过很多次坑后才慢慢理解,diagram-design 最先服务的其实是绘图者本人。画图的过程逼我把对象和关系一条条写清楚,很多模糊不清的设计在写箭头时就会暴露。现在不管多急的方案,我都会先花十几分钟写一版图形源码,哪怕只有三个节点,也比空口讲更扎实。如果你也在被“评审讲不清、文档图过期”困扰,建议下次试着把图当代码来设计。工具只是载体,真正的价值是让图成为一种可讨论、可追溯、可复用的工程资产。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询