ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

从能看懂到设计过:架构图的工程化方法与视觉规范

从能看懂到设计过:架构图的工程化方法与视觉规范

干技术的这些年,我有个越来越深的体会:写代码容易,画图难。所谓画图,指的不是 UI 设计稿,也不是数据可视化报表,而是项目里几乎每天都要碰的架构图、流程图、时序图、部署拓扑图。diagram-design 这个名字听起来像个绘图小工具,但它背后其实是一整套被很多人忽略的工程方法论:用设计思维组织信息、用统一规范约束图形、把复杂关系画成一眼能看懂的结构图。很多人觉得图嘛,能看懂就行了,但"能看懂"和"设计过"之间的差距,恰恰是一次架构评审里别人能不能快速抓住重点的区别。

这篇文章我想把 diagram-design 这套方法论拆开来讲:图表的选型逻辑、视觉元素的设计规范、代码化绘图工具,以及一次完整的实操走查。适合谁参考?如果你是后端、前端、DevOps,经常要给团队画架构图;如果你是技术文档负责人,需要约束一群人产图的风格;又或者你是刚入行的新人,想系统提升画图水平,这篇文章都能给你一套可以直接落地的参考做法。文中所有的规则和步骤,都是我日常画图踩过坑之后沉淀下来的,不是教科书理论。

1. 先搞清楚:diagram-design 到底解决什么问题

1.1 代码里写逻辑,文档里画逻辑

写程序的时候,我们用代码表达逻辑。代码是线性、精确、可执行的,机器能跑,人也能读。但到了文档、方案评审、新人 onboarding 这些场景,代码反而不合适了。人的视觉系统处理图形信息的速度远高于逐行读文字,尤其当你要表达的是模块间的关系、一次请求的流转、一套系统的分层时,一张图比一千行说明都有效。

这里就引出一个核心问题:图的本质是什么。我的理解是,图是一个"信息压缩器",把多维的关系压进一个二维平面,让读者用眼睛扫一遍就能抓出结构。diagram-design 的价值不是把图画得好看,而是确保压缩的过程中不丢信息、不引入歧义、不增加认知负担。你画下的每一个方框、每一条箭头,本质上都是对信息的一次编码,编码规则越清晰,读者的解码成本就越低。

1.2 为什么"能看懂"和"设计过"差距巨大

两张内容一模一样的架构图,一张是随手把方框排开、连上箭头;一张经过设计,做了分组、对齐、留白、语义色。读者看第一张可能要花三分钟,看第二张可能只要三十秒。差距不在绘画技能,而在有没有设计约束。

设计过的图通常有四个特征:第一,有明确的层次,先看什么、后看什么,扫一遍就有顺序;第二,有合理的分组,相关的东西在视觉上靠在一起;第三,有统一的视觉语言,形状、颜色、线型都代表固定的含义,不会同一张图里一会儿方块、一会儿圆角、一会儿箭头乱指;第四,密度高但不累人,信息再多也靠留白维持呼吸感。

这些特征不是玄学,背后是认知心理学里的格式塔原则。比如接近原则:靠得近的元素会被看成一组,所以你把相关模块放在一起,读者天然就会认为它们属于同一个领域。还有对称、连续、闭环这些原则,在图上也都直接转化为视觉秩序。所以 diagram-design 的第一课不是学工具,而是建立"图上每个元素都有语义"的意识。你画的每一个边框、每一条线,都是在给读者发信号。信号一致,图就专业;信号混乱,图就廉价。

2. 图表分类与选型逻辑:先别动手,先选对图

2.1 按关系类型选图:先确定你表达的是哪种关系

很多人画图失败,不是因为不会画,是因为选错了图型。我见过有人想表达模块间的父子层级,结果画成一张流程图;有人想表达服务间的调用关系,结果画成一张部署图。图型不对,后面再怎么设计都是别扭的。

我平时会把技术图先按"要表达的关系类型"分成六类。选图之前先问自己一句:这张图的核心信息,是一种步骤推进,还是一种结构划分,还是一种时间顺序上的交互?答案不同,图型就完全不同。

图型表达的关系典型场景常见工具
流程图随时间或条件推进的步骤业务处理、异常分流、审批流程通用绘图工具、代码绘图
时序图时间顺序上的交互与消息API 调用链、跨服务协作PlantUML、专用时序工具
架构图系统的静态结构与分层模块边界、部署拓扑绘图工具、架构专用工具
层级图父子、上下位归属关系组织架构、目录结构树状结构工具
关联图实体间的多对多关系数据模型、依赖关系实体关系工具
状态图状态迁移与事件触发订单状态机、设备状态机状态机专用工具

2.2 选型实战:同一个需求,图为什么不一样

举个例子。给你一个需求:"用户下单后,订单系统需要校验库存、扣减库存、通知物流。"

围绕这个需求,你可以画三张完全不同的图。第一张画流程图,表达的是流程按照什么顺序推进,先校验、再扣减、再通知,读者关注的是先后步骤;第二张画时序图,表达订单服务、库存服务、物流服务三个角色之间消息的时间顺序,读者关注的是谁在什么时刻调用了谁;第三张画架构图,表达订单服务在整个系统里处于什么位置、和哪些外部系统对接,读者关注的是模块边界和数据流向。

选图的关键是:你心里清楚希望读者获得哪种认知。"什么时候做什么"选流程图;"谁在什么时候调用谁"选时序图;"系统是怎么被切分的"选架构图。一张图解决一个问题,是 diagram-design 的第一条纪律。我见过太多人想把流程、状态、部署、数据模型全都塞进一张图里,结果谁也没看明白。克制,永远比全面重要。

3. 图上视觉元素的设计规范:靠细节拉开差距

3.1 节点:形状、边框、阴影都有语义

节点是图的基本单元。很多人做第一件错事,就是全图只用一种矩形,然后纯靠文字去区分节点类型。这个做法相当于把本可以靠视觉立即识别的信息,硬生生变成了逐个文字阅读,读者累,信息密度也低。

我给团队立的规矩是固定一套语义映射:圆角矩形代表功能模块,直角矩形代表外部系统或第三方服务,平行四边形代表数据库或存储,菱形代表判断分支。这套映射一旦定下来,全团队复用,谁画的图读起来都像出自一个人。边框粗细也有讲究:核心模块用粗边框,次要模块用细边框,灰色虚线框代表规划中或未上线的部分。这样读者哪怕不读文字,扫一眼也能感觉到主次差异。

还有个建议:技术图里尽量不要用阴影和立体效果。图是二维信息图,不是三维渲染图。阴影会干扰视觉分层,让边框的粗细、颜色的差异都变得不明显,在部分渲染环境里还会造成图片体积膨胀。保持扁平,让你的语义靠形状、颜色和位置来表达。

3.2 连线:箭头方向、线型与拐角的秩序

线是图上被忽略得最严重、又最影响可读性的元素。我见过一张图全是斜线,节点之间绕来绕去,箭头还双向乱指,读者根本没法快速追踪流向,这张图基本就报废了。

几条硬规则,都是我实测下来最有效的。第一,连线保持正交,横平竖直,不画斜线。如果工具支持设置拐角为直角,立刻打开。斜线在视觉上暗示"混乱",而正交线暗示"有序",这个感知差异非常直接。第二,箭头方向统一,主流程从上到下或从左到右,尽量不要出现向上或向左的主流线,更不要双向箭头乱开。第三,线型做语义区分:实线代表常规调用,虚线代表异步、弱依赖或者可选路径,粗线代表核心链路和关键请求路径。第四,所有连线不能穿过节点,绕一点路可以,穿过去不行,一穿,读者的视线就断了。

3.3 颜色与字体:克制是最高级的专业

颜色是最容易被滥用的设计元素。一张图超过五种彩色,读者的注意力就全部被色块抢走,根本还在读图说话,而不是吸收信息。我的调色策略是:背景用灰色白色中性色,节点最多三种语义色,连线不超过两种颜色,强调色只用于异常路径或核心链路。

我这里给一套可以直接抄的语义色定义:蓝色代表正常模块,绿色代表已上线或稳定状态,橙色代表需要关注或告警,红色代表异常和高风险。这个语义全团队统一,不要这次用蓝代表模块、下次用蓝代表外部系统。换了语义,读者就得重新学习一次,图的效率就下降一分。

字体方面也是一样。一套中文字体加一套英文等宽字体就够用,不要为了"丰富"混五六种字体进去。字号分三级:图标题最大,核心节点次之,说明性文字最小,每级之间要有肉眼可辨的倍数差,不要靠一两个像素去区分。另外,节点里的文字长度也要控制,一般来说不超过四到六个字,太长就拆到注释里。

3.4 布局与分组:把"看起来能读"提升到"一眼看懂"

布局是 diagram-design 里最体现功力的一环。布局做得好,读者从左上角进入,顺着视线流看完右下角,中途不需要回头;布局做得不好,读者在图上四处找线,找到后还要确认自己没走错,阅读体验极差。

第一个技巧是分组。相关模块外面套一个大圆角框,框顶部写组名,也就是我常说的"容器化"。分组之后,读者先看到几大块,再进入每一块看细节,认知层级瞬间拉开。这个技巧对超过十个节点的图几乎是强制性的。第二个技巧是对齐。同一层级的节点顶部要对齐,左右间距要一致,手工拖拽做不到就花时间用工具里的对齐功能。不对齐的图会产生一种"草稿感",哪怕内容是对的,读者也会下意识觉得不可信。第三个技巧是留白。节点之间、分组之间的距离要明显大于节点内文字到边框的距离,否则整张图就像一堵密不透风的墙。

我画图时有个习惯:草图完成,先看三秒。如果三秒内我说不出这张图可以分几大块,说明布局失败了,必须重新分组。这个习惯帮我快速揪出布局问题,比对着细节调半天高效得多。

4. 用代码驱动图形:从手画到工程化

4.1 为什么我推荐代码驱动画图

手绘工具适合临时头脑风暴,不适合放仓库长期维护。原因有三个:第一,版本管理困难,同事改了你都不知道改了什么,图文件也没有 diff 可说;第二,多人协作风格难以统一,每个人拖拽出来的结果都不一样;第三,没有自动化的可能,代码改了文档还是旧图,维护全靠自觉。

代码驱动绘图解决的就是这三个问题。图只是一份文本文件,改动天然可以 diff,评审的时候能看到改了哪个节点、加了哪条线;风格可以通过共享样式约束,团队用同一份主题配置;还可以接入 CI,在文档构建时自动渲染图片。diagram-design 要进入工程化阶段,代码绘图基本是必选项,这不是时尚,而是可维护性要求。

4.2 适合工程文档的几种代码绘图方案

先说 Graphviz,这是老牌布局引擎,用 DOT 语言描述节点和边。它擅长树形结构、依赖关系、流程图,布局算法很强,连线放置基本不用操心。缺点是布局不可精确控制,想手工微调某条边的位置时会比较费劲。下面这个例子描述了一个简单的部署关系:

digraph deploy { rankdir=TB; node [shape=box, style="rounded,filled", fillcolor="#EEF2FF"]; edge [color="#64748B", arrowhead=normal]; gateway [label="API 网关"]; order [label="订单服务"]; stock [label="库存服务"]; db [label="订单数据库", shape=cylinder]; gateway -> order; order -> stock; order -> db; }

你只需要描述节点和边的关系,布局算法是 Graphviz 自己的责任。这种"只描述关系不描述坐标"的思路,正是代码绘图的核心优势。

再说 PlantUML。它最擅长时序图和活动图,语法接近自然语言,评审的时候直接在 PR 里读代码就能理解图的内容,这是它最大的价值。比如下面这段时序图,读起来和讲话差不多:

@startuml actor 用户 participant "订单服务" as O participant "库存服务" as S 用户 -> O: 提交订单 O -> S: 扣减库存 S --> O: 扣减成功 O -> 用户: 下单成功 @enduml

第三类是基于 JSON 或 JavaScript 的绘图库。这类方案适合把图嵌进前端页面做交互展示,可以点击、折叠、联动数据,很适合数据可视化和动态分析场景。但缺点是依赖前端渲染链路,通常不能直接放进 Markdown 文档离线阅读,对普通技术文档来说有点重。对大部分技术团队来说,Graphviz 和 PlantUML 已经覆盖了绝大多数需求。

4.3 代码绘图的可维护性

代码绘图的优势,只有配上工程规范才能真正发挥。一个常见的坑是:图代码放进仓库了,但后面没人维护,代码改了好几版,图还在原地踏步,三个月后这张图就变成了负资产,新人照着理解系统,方向全错。

我的建议有三条。第一,图代码跟随对应模块的代码存放,不要收进一个独立的"总图目录",这样谁改了模块代码,就会在自己的目录里看到图文件,顺手更新的概率高很多。第二,图文件头部写清楚信息:这张图对应哪个版本、上次更新日期、维护者是谁,把维护责任落到人。第三,尽量让图和文档在同一个构建流水线里出产物,文档发布时自动渲染图片,避免手工导图导致的过期。这三条不一定能做到完美,但每做到一条,图的寿命就能延长一大截。

5. 实操过程:从需求到成图的一次完整走查

5.1 需求与信息收集:真正要画的是什么

我给自己定了一套流程,每次画图都走一遍,已经有几年了。第一步不是打开工具,而是先收集信息。拿"订单提交流程"举例:先列出所有参与方,用户、订单服务、库存服务、支付服务、物流系统;再列出所有关键动作,下单、校验库存、扣库存、发起支付、通知物流;最后列出分支条件,库存不足怎么办、支付失败怎么办、超时怎么处理。三类信息都列出来,图的骨架也就有了。

这一步最容易犯的错是"知道的都往上放"。我理解,画图的时候总想展示自己对系统了解全面,但信息收集阶段允许多,设计阶段必须做减法。先确定这张图当前版本必须表达的最小集合,其他内容放到"后续版本"的待定区,不要试图在一张图里装下整个系统。

5.2 草图与信息分层

信息骨架确定后,我在草稿纸上做信息分层。第一层是主链路,只有一条主线,从左上角往右下角走,这是读者一定要跟着走完的路;第二层是分支和异常路径,放在主线下方,用不同颜色标注;第三层是外部系统和辅助说明,放在两侧,用容器框框起来。

画草图的时候我会刻意用"容器化"思维:同一参与方的所有节点放进一个容器,容器之间再画交互。比如订单服务相关节点放一个容器,库存服务相关节点放另一个容器,容器之间只有几条粗连线。这个习惯能避免最典型的布局混乱——子细节和主结构搅在一起,整个图变成一张分不清主次的网状结构。

5.3 用代码落地与迭代

草图满意之后,我会用 Graphviz 落地第一版。这里有个关键操作习惯:不要一次写完所有内容。先只写骨干节点和连线,把主链路跑通,渲染出来看看布局;觉得方向不对,就调整 rankdir(方向设置)或者增加 cluster(分组容器);骨架稳了,再往里加细节节点,再加异常分支。每加一轮,渲染一次,确认没有破坏整体结构,再继续下一步。

这个分阶段迭代的方式,能帮你省下大量时间。如果一次性写完二十个节点和三十条线再渲染,大概率得到一张布局混乱的图,然后你花两小时手工调结构,最后还是一团乱麻。画图和写代码一样,小步快跑永远比憋大招稳妥。我在这个环节最常在"一次到位"上栽跟头,后来强制自己每轮只改一个维度,才把问题压住。

5.4 导出与嵌入文档,统一风格

图在本地验证通过,就进入文档体系。我通常输出 SVG 而不是 PNG。SVG 是矢量格式,放大不糊,在 HTML 文档里还可以加链接、支持交互;PNG 适合聊天工具里快速分享,正式技术文档还是 SVG 更专业。如果平台不支持 SVG 上传,那至少把源文件保留好,下次改图不要从 PNG 反推。

嵌入文档之后,我还做一次全局风格检查。同一份文档里有多张图的话,背景色、节点形状、箭头样式、色板必须一致。最理想的做法是把样式定义抽到共享配置里,不同图复用同一份 style 定义,这样改一处,全部图同步更新。风格统一是 diagram-design 的终局目标,也是判断一个技术团队文档成熟度的重要指标。你去看那些文档体系做得好的开源项目,图的风格一定是一致的,这不是巧合。

6. 常见问题与排查技巧实录

6.1 连线乱飞?先回到底层重新分层

谁都有过这种经历:图改着改着,节点越来越多,连线开始乱飞,想挪一个节点,结果牵一发而动全身。我的对策是不要去修补乱图,回到草图层面重新分层。连线交叉严重,百分之九十的原因是层次过多或分组不清晰。把骨架重新画一遍,把外部系统和内部模块分开层,大部分交叉线会自己消失。

还有个排查技巧:数一数每个节点的连线条数。如果某一个节点连出六条以上的线,说明它承担了太多职责,要么把它拆成几个节点,要么在它前面引入一个中间层。图里的"单一职责"原则和代码里一样重要,一个节点连太多线,读者根本分不清哪条是主链路,哪条是次要依赖。

6.2 信息过载?给图做减法

图里塞了太多文字,每个节点都是一大段描述,这种情况经常出现在新人画的架构图里。解决办法是文字分层:节点里只写名称,详细说明放到图下方的注释区,或者用脚注关联到具体模块。如果一张图超过了二十个节点,就考虑拆成两张子图,母图画结构,子图画细节,各司其职。

我给自己定的红线是:一张图让一个完全不了解背景的新读者看十五秒,如果他说不出大致结构和主链路,就算过载,必须做减法。减到什么程度?减到只保留表达最小核心信息为止。那些"以后可能有用"的节点,暂时拿掉,等到真正需要的时候再放回去。

6.3 风格不统一?把规范固化成模板

同一个项目里,有人用蓝色方框,有人用绿色圆角,有人画箭头用直头,有人用弯头,多张图摆在一起,视觉上完全像是不同公司的人画的。根治方法不是开会喊口号,而是把风格规范固化成代码模板。颜色色值、形状映射、线型规则全部写进项目文档,Graphviz 里用共享样式文件,PlantUML 里用 include 公共主题。

容易被忽视的是箭头风格这个小细节。箭头用直头还是 V 形头,团队必须统一。这种细节读者未必能说出来哪里不舒服,但整篇文档读下来,这种不统一感会在潜意识里降低内容的可信度。别小看视觉一致性,它是在给文档的整体专业度加分。

6.4 图和代码不一致?用工程手段治理

这是我最痛恨也最普遍的问题。图刚画完是准确的,后面代码改了,图没人更新,三个月后这张图就成了负资产。新人照着它理解系统,方向全错。除了前面说的代码和图就近存放,我还建议在文档里标注这张图的生成时间和对应的代码提交哈希。另一个更彻底的做法是,把图纳入代码评审范围:PR 里有代码改动却没有同步更新图,评审人应该主动问一句"这张图是不是也改了?"

画图能力不是天生的,它跟写代码一样可以被刻意练习。我自己的体会是,练习的关键在于每次画完都复盘一次:这张图哪里让读者困惑了?连线是不是乱?颜色是不是吵?一遍遍复盘,设计约束就会慢慢内化成直觉,以后画图不用再翻规范,落笔就是有序的。

最后再分享一个小技巧:每次画完图,把它拿给一个完全不了解背景的同事看十秒,然后问他这张图讲了什么。如果他能说出个大概,说明图合格了;如果他说不出来,别解释,别补充背景,直接重新设计。这个测试成本极低,但比你自己盯着图看半小时更能反映真实的可读性。我现在每张正式对外发布的图,都要过一遍这个测试,过不了的图,坚决不发出去。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进