☰
diagram-design实战:用代码画架构图,让图像代码一样可维护
2026/10/20 7:30:41 网站建设 项目流程

diagram-design,这个词如果只看字面,就是“画图设计”。但我在实际项目里和它打了这几年交道,越来越觉得,它真正考验的不是手绘能力,也不是工具熟练度,而是对业务结构的理解、对信息密度的控制,以及把复杂关系讲清楚的耐心。

一张好的架构图,能在三分钟内让新同学理解整个系统的运转逻辑;一张烂图,则能让一个团队反复开会、反复解释,最后还不断有人问“这个组件到底挂在谁下面”。所以这篇内容不打算只讲“用什么工具”,而是想聊清楚 diagram 设计完整的工作流:怎么选工具、怎么用代码生成架构图、怎么把图从“能看”做成“能用”,最后再聊聊那些文档里一般不写的坑。

内容里会涉及 Python 代码生成图表的实操,也适合那些完全没接触过的读者照着跑一遍。如果你最近正要画系统架构图、接口流程图,或者想把团队文档里那些烂掉的架构图重新治理一下,这篇应该能直接帮上忙。

1. 为什么要把 diagram 设计当成工程能力来练

1.1 图表不是“画出来”的,是“设计”出来的

很多同学一听到 diagram,第一反应是“用工具把节点框出来,然后连上线”。老实说,大多数人画图确实是这么干的:打开一个画布工具,拖几个方框,写几个组件名,再用箭头连起来。做完之后看着挺满,但过两天自己都不知道每条线为什么存在。

真正的 diagram 设计,前提是先把信息结构想清楚。你画的不是“方框和箭头”,而是在用视觉语言回答几个问题:系统分几层、数据从哪来、依赖到哪结束、故障的时候影响面是什么样。这些问题想明白了,画图只是把答案誊到画布上而已。

我用一个生活类比来解释这件事:你写接口文档,不会想到哪写到哪,而是先确定字段类型、边界条件、异常路径,然后才填文档模板。画架构图也是一样,先做信息架构设计,再做视觉呈现。这一步反了,后面全乱。

1.2 不重视图表设计会付出什么代价

把 diagram 当“画图”而不是“设计”的团队,最容易吃到几个苦头。

一是图里信息密度失控。一张 A4 宽的图塞了四十多个节点,连线像蜘蛛网一样交叉,关键路径被淹没在噪声里。新同学接手的时候根本不敢看图,只能去翻源码,翻半天还翻错了方向。

二是版本和维护完全失控。今天有人加了一个中间件,直接在图上用画图工具补了一个框;明天有人下线了一个旧服务,又懒得改图。两周之后,这张图和真实系统已经对不上了。更麻烦的是,因为源文件没有纳入版本管理,谁改过、为什么改,完全无迹可寻。

三是团队对“图”失去信任。一旦大家发现架构图不准,后面就再没人愿意看。这是最贵的代价——不是画图花了多少时间,而是团队失去了一致认知的锚点。

所以我在团队里一直强调,diagram-design 是一项工程能力,不是美工任务。它要有明确的信息架构、可复现的生成流程、可追溯的版本记录,以及最基本的视觉设计sense。

2. 工具选型:图即代码还是可视化画布

2.1 图即代码的核心优势

项目标题叫 diagram-design,那我先给一个明确的建议:只要是会频繁更新的架构图、拓扑图、链路图,优先考虑“图即代码”方案,也就是用一段描述性的文本来定义节点和连线,然后由渲染引擎生成图片。

这里面的逻辑和“代码即配置”完全一致。图即代码有什么好处?

第一,可版本化。源文件就是一个文本文件,可以放进 Git,和项目代码一起提交。每次修改都有 diff,可以 review,可以回溯。这是拖拽画图永远给不了的。

第二,风格统一。代码里可以定义节点形状、颜色、字体、连线样式,整套图生成出来风格是一致的。不会出现每个人画出来的图都不一样这种问题。

第三,可自动化。CI 阶段可以直接跑渲染脚本,图过期了还能通过 CI 卡住。我在实际项目中就把架构图的生成放进了一个独立目录,配合一些小脚本,每次业务变更后更新源文件,再重新渲染上传到文档站。

第四,入门成本其实比想象中低。对于大部分关系型图表——架构图、流程图、部署拓扑、ER 图——用代码描述“谁连谁”是很自然的事。

2.2 可视化画布工具适合什么场景

拖拽式画布工具有没有用?有,但适用场景要分清楚。

它真正擅长的是“不确定性的探索阶段”:比如头脑风暴画一张构思草图,几个人围着一块白板边聊边改;比如给客户演示一个方案,需要像素级控制摆位;再比如做一些非技术受众看的业务示意图,需要更强的美术表达。

这类工具的优点也很明显:所见即所得,鼠标拉一下就能调整位置,没有任何语法负担。缺点同样突出:布局精修完全靠手感,风格维持靠自觉,文件格式通常是私有格式,跨工具协作困难,也没有版本控制。

如果只是偶尔画一张一次性流程图,用画布工具没啥问题。但如果是团队知识库里的核心架构图,需要随系统迭代长期维护,我强烈建议换成代码化方案。两个方案的边界,用一句话总结:图可以是一次性的,但“图的维护”通常是持续性的,持续性工作就需要更好的工程化支撑。

2.3 一份适合不同场景的选型参考

图形类型更新频率推荐方式核心原因
云架构图 / 部署拓扑高代码化(diagrams 类)节点多、联动关系复杂、需要版本追踪
业务流程 / 时序图中文本 DSL(内嵌在 Markdown)写起来快、方便 review、git diff 干净
初期脑暴 / 口头方案低白板或画布心智自由,适合临时沟通
对外方案演示低画布精修后导出 SVG视觉可控,需要人肉调整布局
组件依赖 / ER 图中高代码化或自动生成可以直接从代码和元数据提取,避免手绘过期

你看这个表格你会发现,除了脑暴和对外演示这种场景,长期维护价值高的图,几乎都应该往代码化方向走。这也是我后面实操部分选择用 Python 的 diagrams 库做示例的原因。

3. 实操:用 diagrams 画一张可信的业务架构图

3.1 环境准备:别把 Python 包和系统依赖搞混

我先演示如何用 Python 的 diagrams 库快速生成一张架构图。这个库的核心思路是:你用 Python 对象描述节点,用>>符号描述连接关系,最后它调用 Graphviz 完成布局并导出图片。

环境安装有两个层面的东西,容易搞混:

一是系统级的 graphviz 二进制,它负责真正的布局和渲染。macOS 上一般用包管理器安装一个graphviz包,Linux 上也是系统包,Windows 需要下载安装包并加入环境变量 PATH。

二是 Python 侧的依赖,通过 pip 安装diagrams库。注意:pip 里也有一个叫graphviz的库,那是给 Python 提供 API 绑定的,不要只装这个就以为系统环境好了。

我一般在新的机器上这么验证:

# 检查系统 graphviz 是否可用 dot -V

如果dot命令能输出版本信息,说明系统依赖没问题。然后执行:

pip install diagrams

装完之后再跑一个简单的示例确认环境。

3.2 从需求到结构:先画出分层骨架

先拍一个模拟场景:某电商类业务下的一套订单系统。外部用户通过入口访问,链路经过网关和负载均衡,请求进入应用层的一组订单服务实例,服务依赖数据库、缓存集群和对象存储;另外还有一个异步任务处理器做一些批量操作。

这个场景故意设计得比较典型,因为是“分层思想”的标准样本。分层的好处是把同一职责的组件收拢在一个边界内,让依赖方向一目了然:接入层只做接入,应用层只做业务处理,数据层只做存储和查询。链路清晰之后,后面排查问题、画故障爆炸半径都会轻松很多。

下面把结构翻译成 diagrams 代码。

from diagrams import Diagram, Edge, Cluster from diagrams.generic.internet import Internet from diagrams.generic.network import Firewall from diagrams.generic.compute import Rack from diagrams.generic.database import SQL from diagrams.generic.storage import Storage from diagrams.generic.blank import Generic with Diagram("某订单系统架构", direction="LR", show=False, outformat="png"): user = Internet("用户入口") with Cluster("接入层"): gateway = Firewall("API 网关") lb = Generic("负载均衡") with Cluster("应用层"): app_1 = Rack("订单服务实例 1") app_2 = Rack("订单服务实例 2") task = Rack("异步任务处理器") with Cluster("数据层"): db = SQL("订单主库") cache = Storage("缓存集群") storage = Storage("对象存储") user >> Edge(label="HTTPS") >> gateway gateway >> lb lb >> [app_1, app_2] [app_1, app_2] >> db [app_1, app_2] >> cache task >> db app_1 >> task app_2 >> task [app_1, app_2] >> Edge(label="上传/读取") >> storage

保存为order_arch.py,运行:

python order_arch.py

一段时间后,当前目录会生成一张某订单系统架构.png。这段代码里几个细节值得讲一下。

direction="LR"表示从左到右布局,外部用户在最左边,数据层在最右边。对于这种“请求从左往右流”的架构图,LR 方向比默认的上下方向更符合阅读直觉。show=False是让脚本不要在渲染完成后自动打开图片,这在服务器或者 CI 环境里特别有用,否则程序会尝试调用系统图片查看器。

Cluster用来画分组边界,也就是架构图里那个虚线框或者花括号,它表达的是“这些节点属于同一层”。分层之后,视觉上会立刻形成“先看边界、再看边界内部”的阅读节奏。这是架构图区别于乱画连线图的关键点。

箭头部分用了>>的连续调用。diagrams 库比较灵活,既可以链式写,也可以用列表批量连。比如lb >> [app_1, app_2]表达的是从负载均衡同时连到两个应用实例。这样写比逐个连线省代码,也更容易看出是“扇出”关系。

Edge(label="HTTPS")给连线加了文字说明,这很重要。很多人画图只顾着连线,但这条线背后是 HTTP 还是内部 RPC,是同步还是异步,只有在线上标明,读者才不需要翻代码确认。

3.3 细节雕琢:节点命名、边界和样式控制

图跑通只是第一步。diagram-design 的价值体现在后面的细节调整上。

节点命名是一个常见问题。很多刚接触的同事习惯用order-app-1这种内部主机名,或者干脆用 IP 当名字。但看图的业务同事、新同学,不理解这些代号指什么。我在命名上的原则是:节点名称写业务语义,比如“订单服务实例 1”,技术细节放到图下方的注释或者文档里。这样一张图不需要额外解释,业务同学也能大致看懂全链路。

边界表达上用 Cluster 做“逻辑分组”。Cluster 的嵌套可以表达更强的从属关系,比如某个应用层内部再拆一个“支付子模块”边界,但这属于更复杂的场景。我建议初期先把“接入层/应用层/数据层”这种粗粒度边界画清楚,不要一上来就在一层里塞五六个 Cluster,空的边界框多了反而增加视觉噪声。

样式控制也是一个可以长期打磨的方向。diagrams 支持在构造节点时传样式参数,也可以在 Diagram 全局统一设置。比如如果希望整张图使用更清晰的中文字体,以及更宽松的间距,可以这样写:

from diagrams import Diagram with Diagram( "某订单系统架构", direction="LR", show=False, graph_attr={ "bgcolor": "white", "pad": "0.5", "splines": "ortho", }, node_attr={ "fontname": "Microsoft YaHei", "fontsize": "14", }, edge_attr={ "color": "#666666", "fontname": "Microsoft YaHei", }, ): ...

这里pad控制图边界留白,splines="ortho"让连线尽量走直角,视觉上有种“总线式”的整齐感,会明显提升专业度。不过要注意,splines="ortho"在关系特别复杂的图上可能导致连线绕路变多,具体要看渲染结果再定。

关于字体的fontname,在 macOS 上通常换成PingFang SC,Linux 可以装中文字体后用Noto Sans CJK SC。不设置的话,中文很容易乱码,这个问题我会在后面的排查小节专门展开。

4. 让 diagram 真正传达信息的四个设计原则

4.1 先定信息层级,再画节点

画图最忌讳的是“自下往上凑”:先有一堆节点,再想怎么连,最后变成一张工具生成的毫无重点的大杂烩。我自己的习惯是先问一个问题:“这张图想让人看完记住哪一条主链路?”

如果是架构总览图,主链路通常是从用户请求到核心服务到数据存储;如果是排查流程图,主链路就是“问题现象 -> 判断分支 -> 处理动作”。把这条主链路定下来,其他所有内容都是它的支撑和背景。

信息层级决定了你要怎么安排空间:最重要的路径走最顺的位置,通常是图的中央主线;次要的支撑组件放上边或者下边;从一个层横向跨到另一个层的关系,如果能避免尽量避免,因为它会破坏分层叙事。

4.2 控制视觉噪声:别把一张图塞成蛛网

人眼一次能够有效跟踪的关系数量有限,一张图里同时出现超过七八个互相缠绕的连线,绝大多数人就看不过来了。所以我自己有一个不成文的“主节点少于七个”原则:单层级的核心节点尽量控制在七个以内,再多就考虑分组或者拆图。

比如应用层有十二个微服务,硬画一定是一团乱麻。我会先画一个“应用服务集群”节点,把十二个服务的清单放到另一个表格或者附录里;或者画一张总览图,再画一张应用层细节图。总览图讲边界,细节图讲实现,各司其职。

这个原则做起来其实比想象中难,因为总有人觉得“一次画完最省事”,但结果往往是图里的信息全被噪声淹没。记住一件事:图是给人看的,不是给“完整性”看的。缺失的细节可以通过链接和文档补充,视觉上的清晰一旦被破坏就很难修复。

4.3 对齐与间距:图的“排版感”也是信息

我见过很多架构图,节点大小不一、间距忽宽忽窄、连线斜穿整张图。这种图的本质问题不是“不够好看”,而是“没有秩序感”——读者无法快速判断节点之间的亲疏关系。

在 diagram 设计里,间距就是语义。同层节点间距一致,会让读者直觉上认为它们是并列关系;边界框之间的留白足够,会让层级切换更明显;连线尽量走水平和垂直方向,语义上比任意角度连线更“稳定”。

代码化布局工具一般会自动计算位置,但这不代表可以完全躺平。你可以通过调整 Cluster 内容、节点的出现顺序、方向参数等方式影响布局结果。画完之后,退后一步,眯着眼看整体结构:如果节点之间的连线交叉明显,就需要重新调整分组或拆分图,而不是硬着头皮发出去。

4.4 图例、版本和元信息:让图像代码一样可维护

这个建议看似不起眼,但我认为是最容易提升团队好感度的一条。在图的角落或者文档中留下几个元信息:这张图对应哪个版本的系统、最后更新时间、维护人、源文件路径。

为什么要这么做?因为架构图最大的坑就是“过期”。读者看到一张图,第一反应不是“这图画得对不对”,而是“这是不是旧图”。如果图上有明确的版本号和时间戳,这个问题就直接消失了。

我在某个项目里甚至直接在 README 里规定:架构图必须有版本号字段,否则不允许合入主流程。听起来有点较真,但效果立竿见影,团队讨论图的时候再也不用问“这张图还准不准”这种问题。

5. 高频踩坑与排查实录

5.1 中文乱码:方框和豆腐块

用 diagrams 渲染中文图,最容易遇到的是节点里的中文变成一个个方框。这个问题的根源不在 diagrams,而在 Graphviz 找不到能渲染中文的字体,于是用缺省字体兜底,自然显示不了。

解决思路非常简单:明确告诉 Graphviz 使用哪一款中文字体。Windows 常见用Microsoft YaHei,macOS 用PingFang SC,Linux 装好fonts-noto-cjk之后用Noto Sans CJK SC。

如果设置了字体还是乱码,多半是字体名称没对上。可以用系统自带的字体管理工具查一下准确的字体名,比如 Linux 上可以用fc-list | grep CJK看已经安装的中文字体名称。这个操作我做过无数次,每次都管用。

5.2 连线交叉和布局失控

图里连线密密麻麻、交叉成麻花,这是代码化布局最常见的问题。Graphviz 的布局算法是通用的,它不会知道你业务上“谁和谁更亲近”。

我一般按下面顺序排查:先确认方向设置合理,比如请求流向是 LR 还是 TB;再看 Cluster 分组是不是太粗糙或太细碎;最后给不想要交叉的边加强约束。如果某些节点之间的顺序想固定,可以用不可见边去“占位”,比如加一条隐藏的连线先把位置定住,这条线设置style="invis"即可。

实在不行就拆图。一张图超过三层嵌套和二十个节点,无论怎么调布局算法都很难优雅,这时候拆分才是正确的工程决定。

5.3 导出清晰图与透明背景

经常有人在文档里贴一张白底截图,字体发虚,放到深色主题下还有一圈白色边框。diagrams 默认导出 png 时可以用outformat指定格式,也可以输出 SVG,矢量图在文档站里放大缩小都不会糊。

with Diagram(..., outformat="svg", show=False): ...

如果需要在深色背景下使用,可以把graph_attr里的bgcolor设为transparent。注意 SVG 本身是矢量格式,文件可能比 PNG 大,但是文档站一般都能直接渲染,优先推荐。

5.4 常见问题速查表

现象可能原因处理办法
运行提示找不到 dot / Graphviz 可执行文件系统级 graphviz 没有安装或不在 PATH先安装 graphviz,再验证dot -V
中文变成方框缺少中文字体配置设置node_attr中的fontname为系统中文字体
图片边缘被截断没有设置pad在graph_attr中加pad,如"0.5"
节点之间交叉严重布局方向或分组不合理调整direction、精简 Cluster、拆分图
输出文件不是最新内容同目录有同名旧图,缓存未更新删除旧图后重新渲染,或让脚本每次都清理输出目录
图内容太多,根本看不完信息层级没有收敛拆成总览图 + 细节图,控制主节点数量

还有一个我自己踩过很多次的坑:在 CI 环境里运行渲染脚本,CI 机器很可能没有安装中文字体,导致本地渲染正常、服务端渲染出来乱码。解决办法是把字体安装步骤写进 CI 脚本,或者在 CI 里提前执行一次字体验证,别等到文档上线才发现。

6. 最后再分享一个小习惯

回到开头说的这个标题:diagram-design。很多人以为画图的关键是学会某个工具,但工具三个月换一代,真正不变的是信息设计的能力。

所以我最后想分享一个坚持了很久的习惯:每次画完一张图,我会把生成它的源文件放进和代码同一个仓库,和文档放在同一级目录,并在图旁边固定写一行版本号和更新日期。下次任何人要改架构文档,都是从源文件改起,再重新渲染,而不是对着导出的 PNG 用画图工具涂改。

这个习惯带来最大的改变是,团队终于开始把架构图当成“活代码”来维护,而不是一个一次性的交付物。如果你之前只是顺手画图,我建议从下一张图开始,试着用代码的方式去描述它。哪怕只是从一张简单的三层架构图开始,坚持一段时间之后,你会明显感受到 diagram 设计这项能力的价值。

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

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

立即咨询