☰
图即代码:用文本化绘图打造可复用、可维护的架构图体系
2026/10/15 8:17:48 网站建设 项目流程

做技术写作这几年,我越来越觉得,给系统画图这件事的难度,一点都不比写代码低。diagram-design这个项目,就是我在反复踩坑之后沉淀下来的一套“画图方法论加工具链”。简单说,它要解决的是:当团队里每个人画的架构图都不一样,文档里的图只能用一次、改起来要人命的时候,我们怎么把“画图”这件事变得像写代码一样有规范、能复用、可维护。

diagram-design本身不是什么大型框架,它更像一套被实践验证过的做法。核心思路是图即代码,把图表用文本形式定义,再用命令行工具自动渲染成图片和网页。这样做最大的好处是图可以放进版本控制,修改什么内容一目了然,也能在文档站里统一管理。这篇文章主要写给三类人看:一是技术文档工程师,二是经常要给系统画架构图的后端和运维开发,三是团队里负责基础设施和研发规范的开发者。我自己就是从一个简单的工具脚本开始,慢慢补齐了布局规则、样式约束、导出流程和CI集成,最后形成了一整套可以复制到任何项目的方案。接下来我把整个过程拆开来讲,每一步都附上能直接落地的配置和参数。

1. 项目概述与核心设计思路

1.1 需要版本管理的不是图,而是图的“数据”

传统画图工具最大的问题,不是画得不好看,而是画完就结束了。一张架构图放到某个文档里,过了三个月系统改了,图只能重新打开编辑器手动拖线。更麻烦的是,团队里几个人各自画各自的,同一套系统可以有三四个版本的结构图,版本之间谁对谁错没人说得清。

diagram-design的起点就是把“图”当成“数据”来管理。我用文本格式描述节点和连线,比如“API网关连接订单服务,订单服务依赖数据库”,这些描述本身就是结构化的,可以定义成一个文件。这样一来,图的所有变更都能被版本管理工具记录下来,团队成员可以像评审代码一样评审图的改动。哪次提交改了什么模块、谁加的节点、连线逻辑是否正确,全部有迹可循。

这个思路听起来简单,但很实用。实际操作中,我把图源文件按业务模块拆分,一个系统一张主图,主图又通过引用方式关联子图。这样维护成本大幅下降,不会出现“改一处要动整个大文件”的局面。

1.2 统一渲染引擎,告别人人风格不同

第二个核心问题是风格不一致。团队里有人喜欢蓝底白字,有人喜欢深色背景,还有人把连接线画成交叉的曲线,图一多整个文档看起来非常杂乱。diagram-design的应对方式是:统一使用一套声明式绘图语法,配合固定的主题样式,所有图都在一个渲染引擎下生成。

所谓声明式绘图,就是我只关心“图里有什么”,不关心“图怎么画出来”。节点怎么摆放、线怎么走,都由渲染引擎自动处理,我只通过少量属性控制层级和方向。这样既保留了灵活性,又保证了整套图风格统一。当公司品牌色需要调整的时候,只需要修改一份主题文件,全站所有图表重新渲染一遍就全部更新了,这个优势在传统手绘方式里完全没法想象。

1.3 从手工到流水线,图也可以自动化构建

最后要解决的是产出环节。diagram-design整合了命令行工具,能够把文本源文件直接渲染成SVG、PNG、PDF等多种格式,还能输出便于网页嵌入的HTML片段。这意味着画图不再依赖某个人的电脑环境,而是可以接入持续集成流水线,提交代码后自动生成最新版图表并发布到文档站。

举个例子:某个同学修改了系统结构图,增加了一个消息队列,他把改动提交到仓库,流水线会立刻渲染出新版图片,并把改动自动展示到对应的文档页面里。整个过程不需要任何人工截图、粘贴、上传的操作。这种自动化构建的思路,是diagram-design和普通画图工具之间最关键的分水岭。

2. 方案选型与工具对比

2.1 三个方向,我为什么放弃了白板和拖拽工具

画图工具基本上分成三条路线。第一条是白板和手绘工具,上手最快,开会的时候随手就能画,但交付物很难持续维护。第二条是桌面拖拽类工具,功能强大,模板多,但要安装客户端,文件格式封闭,协作和自动化都受限。第三条就是文本化绘图,用代码描述图形结构,渲染引擎负责输出,我最终选的就是这条路线。

放弃前两条路线的主要原因在于自动化成本太高。手绘和白板类工具,就算能通过插件导出,也很难做到“图跟着代码走”。每次系统架构变化,都得有人记得去更新那张老图,这个“记得”本身就是最高的隐性成本。而且拖拽工具生成的文件大多是二进制格式,即便能放进版本控制,diff也做不了,评审时根本看不出改了什么。

2.2 几种文本化绘图语法,我的取舍

我系统研究过几种主流文本绘图语法,各有各的强项。这里直接说我的结论:

方案优势不足适用场景
A方案生态成熟,语法简单,能画时序图和用例图布局控制能力相对较弱,复杂图容易乱快速画中小型图
B方案布局算法强,适合节点密集型图,生成质量高语法偏底层,上手曲线陡一些大规模节点自动布局
C方案设计感强,语法干净,原生支持现代架构图生态较年轻,插件少架构图、流程图主力方案
D方案完全面向程序员,模块化能力强需要额外学习成本,周边工具少代码仓库内置图表

实际项目中,我把C方案作为主渲染引擎,用A方案补一些交互图和时序图场景。两个方案都支持输出SVG和PNG,画风差异不大,放在同一套文档里视觉上不会产生明显割裂。我建议不要同时引入超过两个方案,否则样式统一会重新变成难题。

2.3 渲染链路的工程化设计

工具选完之后,还需要把渲染过程工程化。现在的链路是这样的:源文件仓库存放所有一步到位的图源文件,按目录分层;命令行工具负责把源文件批量渲染成目标格式;做成一个仪表盘脚本,可以指定渲染哪些文件、输出到哪个目录、采用什么主题。最后再加一层自动化:每次代码合并之后,自动触发重渲染。

这套链路里最值得说的小设计,是渲染失败不阻断主流程。比如某一张图语法错误了,工具会跳过它并输出警告,其他正常图照常更新,这样不会因为一张出错的图让整个文档站发布失败。这个容错机制在实际运作里非常实用,我见过不少因为局部问题导致整体发布阻塞的案例,那体验简直灾难。

3. 核心细节解析与实操要点

3.1 布局逻辑:先分块,再连线,最后调方向

文本化绘图虽然自动布局,但初期画出来的图还是会乱。我的经验是,画任何一张图之前,先想清楚层级关系。对于系统架构图,我习惯把图分成三层:入口层、业务层、数据层。入口层放网关、负载均衡、客户端;业务层放核心服务模块;数据层放数据库、缓存、消息队列。建好这三层,连线的方向自然就有了,图的阅读逻辑也会清晰很多。

具体到语法实现,可以利用容器特性把三个层次圈起来。渲染引擎会自动把容器内的节点归拢到一块区域,这样整张图从视觉上就能看出分层关系。分层设计的时候要注意一点:尽量保证连线方向统一,从上到下或者从左到右,不要一会儿竖一会儿横,否则读者会迷路。

3.2 样式体系:一套主题走遍全套文档

样式是最容易被低估的部分,尤其是颜色。初学者容易把图画成彩虹,每个模块一种颜色,最后整个图面五彩斑斓,找不到重点。我在diagram-design里定了一套颜色约束:同一层级的模块只用同一个色系,核心服务用深色填充,辅助服务用浅色填充,外部依赖统一用灰色。

字体的选择同样重要。我实测下来,中文环境下黑体类字体渲染效果最稳,常规正文用无衬线字体,标题可以加粗处理,但不要在同一张图里混太多字种。字号方面,主节点名称控制在14到16像素,说明性文字控制在10到12像素,太小的字在网页上会糊成一团。这些样式参数全部定义在主题文件里,不随着具体图内容分散到各处。

除了颜色字体,连接线的设计也要遵循规则。主流程连线用较粗的实线,异步消息用虚线,失败回退用红色点线。虽然语法支持给每条线设置独立样式,我强烈建议用预置的类名来区分,而不是重复写样式代码,这样后期改线型只需要改一处。

3.3 图的命名与注释:没人教但必须养成的习惯

写代码大家记得起函数名、写注释,画图却常常忘了给节点起可读的名字。diagram-design项目里约定了命名规范:节点标识使用英文小写加连字符,展示名使用简洁中文,比如order-service对应“订单服务”。这样图源文件的可读性和可维护性都会好很多,代码里引用节点的时候也不容易打错。

每个节点还可以带一个说明字段,用来写这个模块是干什么的,或者指向详细的文档链接。这个字段默认不显示,但鼠标悬浮的时候会弹出来。我后来发现这个设计特别有用,相当于给架构图内置了注释系统。读者看图的时候,不用到处找模块对应的文档,直接悬浮就能看到一句话简介。

3.4 工程化输出:格式选择与清晰度控制

输出格式的取舍也值得单独说一下。我的默认配置是双格式输出:SVG给网页用,PNG给离线文档和PPT用。SVG的优势是无限缩放,文字是矢量的,放大多少倍都清晰。PNG则需要在导出时指定合适的DPI,我一般设置150到200之间,太低了文字模糊,太高了文件体积大,页面加载慢。

如果目标平台对SVG支持不好,也可以让工具在渲染时一次性输出两种尺寸的PNG,一种用于缩略图,一种用于详情页。我踩过一个坑是直接把缩略图当成详情图用,文字小到完全看不清,后来才知道好的做法是分别控制导出尺寸。这些输出参数也都统一写在配置文件里,普通同学拿到仓库后不需要了解底层细节,直接一条命令就能产出规范图表。

4. 实操过程:从零构建一张系统架构图

4.1 先画信息架构草图,再转到文本语法

这一步是很多人跳过的,所以画完总翻车。我每次画图都会先在草稿纸上或者白板上把信息关系捋一遍,确认清楚系统里有哪些模块、模块之间什么关系、哪条是主链路、哪些是旁路依赖。草图不需要好看,只需要把事实理清楚。

举个例子,假设要画一个典型的电商下单系统。我手里的素材是:前端应用、API网关、用户服务、商品服务、订单服务、支付服务、数据库、缓存、消息队列,外加第三方物流接口。先把这些实体全部列出来,然后在草图上划箭头标关系:前端接网关,网关分发到三个业务服务,订单服务依赖支付和物流,所有服务共用数据库和缓存。箭头之间如果有多对多的关系,也用高亮笔画出来,方便后续检查有没有遗漏。

4.2 用声明式语法搭出骨架

信息草图完成后,照着草稿用声明式语法写源文件。以下是我实际用的代码示例,这个语法非常直观,不需要专门学习就能读懂七八成:

frontend: 前端应用 api_gateway: API网关 user_service: 用户服务 product_service: 商品服务 order_service: 订单服务 payment_service: 支付服务 logistics_system: 物流系统 dir: TB frontend -> api_gateway api_gateway -> user_service api_gateway -> product_service api_gateway -> order_service order_service -> payment_service order_service -> logistics_system user_service -> db: 读写用户数据 product_service -> db: 读写商品数据 order_service -> db: 读写订单数据 order_service -> cache: 缓存热点数据 product_service -> cache: 缓存商品信息 order_service -> mq: 发送订单事件

第一版先把所有节点和连线堆上去,不做任何美化。这里的关键是,连线关系必须和草图完全一致,不要边写边改,否则后面排查问题会分不清是逻辑问题还是语法问题。写完之后先跑一次渲染,看看整体结构是否符合预期。

4.3 分组建容器,控制图层关系

核心模块之间没有层次感,是我初次渲染出来的常见问题:所有节点挤在一起,反馈是很扁平。此时引入容器把它们按层聚合:

directory: { label: 接入层 frontend api_gateway } service: { label: 业务层 user_service product_service order_service payment_service logistics_system } data_store: { label: 数据层 db cache mq }

容器设定之后,渲染引擎会优先归拢容器内的节点,再处理容器之间的连线。这一步做完,整张图的阅读结构立刻清晰了。我常用的排版方向是dir: TB,也就是从上到下布局,符合人们浏览网页和文档的视线习惯。如果你的系统交互特别多,横向的dir: LR也可以,但整套文档里尽量保持一种主方向。

容器还有一个好处,可以给它们统一加备注和颜色。比如数据层整体用深色边框,业务层用浅色背景,视觉系统就建立起来了。这些样式在事先准备好的主题里已经预置,只需要按类名引用即可。

4.4 标注关键链路与异常分支

架构图仅仅画出模块和连线还不够,必须让读者一眼看出主链路是什么。diagram-design里我用样式区分路径重要程度。比如核心下单链路,连线上加粗、颜色加深;异步事件发送,用虚线表示;支付失败时的回调路径,用红色点线标记。

order_service -> payment_service: 发起支付 {style.stroke: "#1f6feb", style.stroke-width: 3} payment_service -> order_service: 支付结果回调 {style.stroke: "#e0245e", style.stroke-dash: 4} order_service -> mq: 发送订单事件 {style.stroke-dash: 4}

这一步做完,输出图片信息量就完全不同了。读者能看出系统里正常的业务流转方向,也能看出哪几条是异步的、哪条是异常路径。对于文档审查来说,这样的图比只看模块连线的图有用得多。

4.5 渲染导出,并嵌入文档页

图源文件写好后,运行渲染命令,把所有图一次性导出:

diagram build --input ./src --output ./dist --theme light

命令执行完,输出目录里会按源文件的目录结构生成对应格式的图片。网页端我一般优先挂SVG文件,因为可以在浏览器里直接缩放,悬浮注释也能保留。如果文档系统不支持SVG,走PNG输出即可,记得在配置文件里把图片缩放比例调到位。

导出的SVG可以直接用普通的Markdown图片语法引用到文档里。由于文件由CI系统自动生成,文档站每次发布时拿到的都是最新版,不需要人工备份。到这里,一张图的完整链路就走通了:信息整理、文本化定义、分层归类、样式标注、渲染输出、自动发布。

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

5.1 中文乱码与字体缺失

中文环境最常遇到的问题是乱码,原因基本都是渲染环境里缺少对应字体。排查思路:先看本机有没有装中文字体,再检查主题文件里是否指定了正确的字体名。有的渲染引擎直接写宋体能识别,有的只能识别字体文件,需要到系统目录确认具体名称。

我的解决方式是在项目仓库里固定附带一个字体子集文件,渲染时显式指定这个字体路径,而不是依赖操作系统字体。这样任何机器上跑渲染命令,产出的图都能正确显示中文。这个做法要多占用几兆仓库空间,换来的是环境一致性,值。

5.2 节点重叠与连线交叉

文本化绘图多数时候布局很聪明,但图特别大或者连线特别多的时候,还是会出现密集节点重叠、连线交叉成蜘蛛网的情况。这种事很简单:不要指望引擎全自动搞定,手动干预更靠谱。

手动干预有两个层面。一个是逻辑层面,看看是不是某些并不相关的节点被连在了一起,能否用分组容器把无关节点隔开。另一个是物理层面,可以显式指定某些节点的相对位置,把它们固定到特定方向上去。我一般只在图确实乱到影响阅读时才手动干预,平时尽量信任自动布局。自动布局算法做过大量优化,比人随手摆放的效果稳定得多。

5.3 重复样式导致维护噩梦

画图频率高起来之后,最大的坑变成样式重复。如果每个图都单独写一遍颜色和连线样式,时间一久,冲突和修改量会成倍增长。

正确做法是维护一个统一的主题文件,把常用模块的类样式放在里面,在具体图里通过类名引用。曾经有一次我需要调整所有图里的数据库节点图标,之前分散写样式的版本改了几十处,后来统一主题文件之后只改一处,所有图全部刷新,省下的精力不言而喻。这个教训我给每个使用者都会讲一遍。

5.4 CI构建失败但文档还想照常发布

把画图接入持续集成之后,会遇到一种很尴尬的情况:某张图语法写错导致构建失败,如果阻断整个流水线,文档其他部分的更新也被拖住。我实测后的容错方案前面提过,渲染任务独立执行、失败只报警告、成功的图照常发布。虽然听起来像偷懒,但实际工程里确实让协作顺滑很多。

另外一个常见问题是构建机网络受限,下载不了依赖。建议把渲染引擎和所需字体全部打进容器镜像,或者存到内网仓库,离线也能构建。这些问题不复杂,不提前处理会反复折腾人。

6. 踩坑实录与个人体会

这套项目我自己用了一年多,最大的体会是:画图这件事,真正难的不是工具,而是把图的“结构”理顺。工具只是帮我把理顺的结构稳定落地。很多时候拿到一张混乱的图,根本原因是画图的人还没想清楚系统之间的关系,再好的工具也拯救不了逻辑上的空缺。

第二个体会是,样式统一带来的舒适感远超预期。现在我看自己的文档,所有图一眼能分辨出层级,配色也符合品牌规范,整个站点的专业感提升了一大截。这种改变不是某一幅图变好看了,而是所有图叠加起来形成了一致的体验。之前一位同学评价说,看了这些图再去看别的项目手绘风格图,会明显觉得信息获取速度差了很多。

最后想分享一个扩展建议。diagram-design这套链路不只是画架构图,也可以用于画数据流图、部署拓扑图、网络结构图。日常画图需求能覆盖九成以上。你要是也想给自己的文档体系引入这套做法,从一个小场景开始就好,先画一张核心架构图,跑通渲染和发布,再逐步推广到整个团队,整个过程会远比想象中顺畅。

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

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

立即咨询