Diagram as Code:用代码管理架构图与流程图的实践指南

发布时间:2026/9/9 2:08:38
Diagram as Code:用代码管理架构图与流程图的实践指南 “diagram-design”这个项目标题乍一看很简洁但我第一反应是这不就是把“画图”这件事重新定义了一遍吗接触过架构图、流程图、思维导图的人应该都有同感——我们真正需要的不是一张静态的图而是一套能改、能查、能复用、能多人协作的图表设计体系。diagram-design本质上就是把这个诉求产品化通过代码或结构化文本来描述图表结构再交给渲染引擎生成可视化结果。它能解决的问题很明确版本混乱、协作低效、图表与代码不同步、大图改起来费劲。这篇文章适合正在为团队搭建技术文档体系的人也适合做后端、前端、DevOps甚至产品经理和架构师——只要你的工作里绕不开图表这套思路就能帮你省掉大量重复劳动。1. 从“画图”到“设计”diagram-design的思路拆解1.1 传统绘图方式为什么撑不住了很多团队一开始用的是Visio、ProcessOn、draw.io这类拖拽式工具。刚接触时确实方便拉一个框、连一根线十分钟就能出一张像样的流程草图。但用久了问题就出来了——最典型的是版本管理彻底失控。我见过一个真实案例架构组把系统部署图存在共享网盘里第二周发现有三个不同时间的备份谁也说不好哪张才是最新。更麻烦的是图里的某些模块已经下线了但画图的人离职了后面接手的人只能对着旧图猜。拖拽式工具还有个隐蔽的坑一旦图变得复杂微调就是灾难。框和线是绝对定位的挪动一个节点旁边跟它关联的十几根线全要手动画一遍为了躲开文字重叠又要逐个调整坐标。这个过程的重复劳动率极高而且每一轮改动都可能引入新的错位。Slack上对着一张图来回截屏沟通往往比重新画一张还慢。再往后当代码仓库里开始用Markdown写文档时大家发现了一个更大的别扭图和文是割裂的。文档在Git里图在网盘里代码更新了架构图没人更新审PR的时候必须单独下载附件才能看。这就像写代码的时候把函数实现放在另一个神奇的外部文件里调用了却没有任何引用检查——早晚要出事故。1.2 diagram as code的核心思路把图表当代码管理diagram-design走的路线简单说就是“diagram as code”——图表即代码。不再用鼠标拖拽而是用文本语言描述图表的结构和样式然后通过解析器生成SVG、PNG或交互式HTML。图表从那一刻开始就有了和普通代码一样的生命周期可以提交到Git可以diff可以code review可以自动渲染可以嵌入文档系统可以参与CI流程做一致性校验。这个转变的底层逻辑和当年从“手写HTML”到“组件化开发”是一样的——把重复性强、容易出错的部分交给工具把表达和设计留给人类。以前画图的核心动作是“调整坐标”现在核心动作变成“描述关系”。我只需要说“服务A调用了服务B服务B依赖数据库C”渲染层会自动完成布局、对齐、连线的计算。这个抽象层级的变化才是diagram-design真正值钱的地方。对我个人来说最上头的点是所有图表都可以review了。以前架构评审会几个人围着投影仪看一张静态图现在直接在评论里人指出“这个模块依赖方向画反了”改一行文本渲染结果立即更新。图表和代码长在同一个仓库里散落在同一个PR里谁改了模块调用关系一并更新架构图谁也不会忘。这个思路适配的场景非常广而且不限行业。研发团队画系统架构、数据流、网络拓扑可以用业务团队画用户旅程、业务流程图也可以用做知识管理的人画概念图、思维导图同样顺滑。你只需要掌握一套足够表达关系的文本语法剩下的事交给引擎去排。2. 核心语法再拆解diagram-design里必须掌握的四大表达2.1 节点与连线图表的“名词”与“动词”在任何图表语言里节点是最基础的单位它对应的就是实体概念——一个系统、一个模块、一个人、一个决策点。连线则是实体之间的关系服务调用、数据流转、审批通过、消息通知等等。节点和连线的关系可以理解成句子里面的名词和动词没有它们图表就啥也不是。以Mermaid为例最简单的流程图长这样graph LR A[用户请求] -- B[网关] B -- C[认证服务] C -- D[(用户数据库)]这段文本里有四个节点三条连线方向是LR从左到右。渲染出来就是一张非常标准的横向调用链图。这里有个容易被忽略的点方括号和圆括号决定了节点的展示形状。方括号是矩形圆括号是圆角矩形还有个括号形状是六边形可以用来表示决策点比如graph TD A{是否通过校验} --|是| B[进入业务逻辑] A --|否| C[返回错误码]这行代码里花括号“{}”表示菱形判断节点连线上的“|是|”和“|否|”给关系增加了分支标签。这个表达能力恰好覆盖了大部分流程图、状态图、时序图的场景。用熟了以后你会发现绝大多数图表问题都只是在想清楚“有哪些实体、实体之间什么关系”这两个问题而已。不过别急着炫技我建议一开始不要把所有符号都背下来。把节点、连线、方向、标签这四个基础表达能力用熟已经能覆盖日常工作里八成以上的图表需求。剩下的高级语法都是按需查文档补充的没人能一次全都背下来。2.2 分组与容器让图表的层级感立起来节点一多扁平排布就会变成一锅粥。20个节点平铺在画布上光看连线就是一团乱麻。diagram-design给了两个层级组织工具子图和分组。子图在Mermaid里是这样用的graph TB subgraph 网关层 G1[API网关主节点] G2[API网关备用节点] end subgraph 服务层 S1[订单服务] S2[支付服务] end G1 -- S1 G2 -- S2子图的作用就是给多个节点圈一个可视化边界渲染出来外面会多一个框框上有标题。这一招在架构图里极其好使——你可以把“接入层”“服务层”“数据层”分别圈起来整个系统的层次一眼就能看明白。相当于建筑图纸里的楼层线让人能快速理解哪些组件属于同一逻辑分区。分组则是另一种思路在PlantUML或D2里用得更频繁它不改变渲染布局只是给一组元素打上标签方便统一施加样式或者后续做过滤。在设计图表的时候我习惯先把节点分成“核心调用链节点”“辅助监控节点”“外部依赖节点”三类然后用颜色深浅区分主次。这样看图的人能快速把注意力放到主线而不是被一堆旁支细节淹没。2.3 样式与主题视觉规范统一比想象中更重要图表的“丑”和“乱”本质上都是样式失控。色号五花八门、节点大小随缘、字体忽大忽小图的信息密度再高也会因为视觉噪音过大而丧失可读性。diagram-design工具天然适合做样式规范化因为样式是写死在文本里的——比在GUI里手动点几百次鼠标要可控得多。Mermaid里做条件样式大概是这个手感graph LR A[前端应用] --|HTTPS| B[网关] C[监控系统] -.-|metrics| A style A fill:#e6f7ff,stroke:#1890ff style B fill:#fff7e6,stroke:#fa8c16给节点手动指定填充色和边框色就能在一张复杂图里快速区分不同类型的模块。我自己的习惯是核心业务组件用冷色系外部依赖用暖色系监控运维类组件用灰色系。这样一张图扫过去第一眼看到的是核心链路第二眼看到的是外部依赖边界最后才查看监控细节。另外一个容易被忽略的是“主题统一”。同一份文档里五张图五种配色给人的观感就是杂乱。建议在项目根目录里维护一个统一主题定义。Mermaid支持通过init指令设置主题颜色、字体、连线风格。团队完全可以约定一套标准背景色、主色、连线粗细、字体大小全部写成固定配置任何人画新图都基于这套配置开始。时间久了整个文档站里的图表风格会收敛得非常好专业度直接拉满。2.4 自动布局与交互能力工具帮你省掉最苦的活刚切换到diagram-design方式时我对自动布局是既爱又恨。爱的是不用手动挪节点了恨的是自动布局偶尔会给出“正确但难读”的结果——比如一张三个子网互相调用的拓扑图工具默认的排序可能会让连线交叉得很难受。这时候需要理解一个底层事实布局算法的本质是解决一个有约束的最优化问题它优先保证节点不重叠、连线尽量短、层级尽量一致但它并不知道你的业务语义里A和B的关系最重要。所以diagram-design不是完全不需要排版思维而是把排版从“体力活”降级成了“策略配置”。遇到自动布局不理想的情况我通常先检查有没有不合理的依赖关系比如循环依赖会让引擎很难受然后是明确方向graph TD和graph LR的阅读顺序差异很大再然后是考虑要不要拆图一张图超过30个节点之后就别硬塞了拆分成分层图和模块图效果更好。至于交互能力这是diagram-design另一个大杀器。基于Mermaid.js可以在HTML里生成支持点击跳转的图节点点击某个服务节点可以跳到对应的监控面板或代码目录支持hover高亮相邻节点还有一键展开折叠子图的交互插件。这些能力传统静态导出的图片是完全无法匹敌的。在技术文档里插入一张可交互的架构图读者的体验和看一张jpeg截图完全是两码事。3. 完整实操从零搭一套可复用的diagram-design方案3.1 工具选型Mermaid、PlantUML、D2到底选哪个聊完思路和语法到了选型环节。这个决策会直接影响团队的接入成本值得认真比较。市面上主流的diagram as code工具就那么几款Mermaid、PlantUML、D2还有AntV X6这类更偏重前端交互的库。我的建议是——大多数技术团队直接选Mermaid理由我在下面详细说。先放一张对比表方便一览维度MermaidPlantUMLD2学习曲线低Markdown风格中伪代码风格低声明式语法原生渲染场景流程图、时序图、甘特图、状态图、饼图等UML全系列面向软件设计更专业架构图、网络拓扑、通用图表生态绑定GitHub、GitLab、Notion、语雀都原生支持Jenkins、Confluence等老牌平台支持好年轻但CLI体验出色有Terraform集成中文支持需要设置字体大部分情况OK需要处理字体容易乱码默认支持体验较好扩展性有丰富的插件支持自定义主题和交互偏向静态图片导出支持多文件、变量、布局参数自动布局很优秀适合场景写Markdown文档为主的团队软件设计文档和UML重度用户对布局和视觉细节挑剔的团队对比完你会发现Mermaid赢在生态和上手速度。GitHub直接渲染、Notion里写代码块就能出图、VS Code装个插件就能预览这种“写文档随时配图”的顺畅感是其他工具很难比拟的。如果你团队已经重度使用MarkdownMermaid就是零成本接入。PlantUML的强项在于UML语义更严格。如果你们要做严肃的类图、时序图、部署图PlantUML的那些语法更接近UML规范。但我个人用下来的感受是它的语法略微啰嗦而且默认排版风格比Mermaid老旧一些。D2是很值得关注的新生代工具。它的布局引擎是我见过的默认效果里最好的连线基本不交叉尤其是画网络拓扑和系统架构图的时候视觉质感明显比Mermaid强一个档次。但它生态还在积累中GitHub等平台不能原生渲染团队接入需要额外搭一套CI渲染管线。3.2 实测流程一条命令把文本变成图这里我以Mermaid为例走一遍从零到一的全流程因为它在终端里的体验足够轻量。你不用先搭什么重型平台只要有一个装了Node.js的环境就能开始。第一步全局安装Mermaid的命令行工具npm install -g mermaid-js/mermaid-cli第二步写一个最简单的图表文件命名为architecture.mmdgraph TB subgraph Client Web[Web前端] Mobile[移动端] end subgraph Server API[API服务] Auth[认证服务] end DB[(PostgreSQL)] Web -- API Mobile -- API API -- Auth API -- DB Auth -- DB第三步渲染成PNGmmdc -i architecture.mmd -o architecture.png -b white如果一切顺利当前目录下会生成一张排版整齐的架构图。这张图的整个生命周期都在这一个文本文件里你把它放进Git仓库团队里的任何人随时可以clone下来改、重新渲染、对比历史版本。这里我踩过一个小坑新装的mmdc第一次渲染可能会因为缺少Chromium而报错因为底层是无头浏览器渲染的。解决方案是装一下依赖npx puppeteer browsers install chrome或者用系统自带的Chrome指定路径mmdc -p puppeteer-config.json -i architecture.mmd -o architecture.png其中puppeteer-config.json里可以指定executablePath指向你本机装好的Chrome。这种事情看起来很小但第一次配置的时候容易卡住半小时提前知道能省不少力气。3.3 进阶玩法把图表接入文档站和CI/CD流水线单机渲染只是入门diagram-design真正发挥威力在集成环节。首先是文档站集成。如果你的团队用VuePress、Docusaurus、MkDocs这类静态站点生成器Mermaid基本都是原生支持或有一等插件。VuePress里最简单的启用方式是在config.ts里加markdown: { mermaid: true }然后在Markdown里直接写## 系统架构图 mermaid graph LR A[前端] -- B[网关] -- C[服务] 页面构建的时候图会被自动渲染成SVG读者看到的不再是静态截图而是可缩放、可点击的活图。这里我强烈建议打开交互式功能读者在文档里点击节点跳转到对应代码模块体验真的会提升一大截。然后是CI/CD校验。图也是代码那它就应该过lint和解析检查。在我们的工程实践里把图表检查并入了PR流水线每当有.mmd或者Markdown文件变动CI就跑一遍语法检查解析不通过直接让PR失败。做法是在GitHub Actions里加一个步骤- name: Validate Mermaid diagrams run: | for file in $(find docs -name *.mmd); do mmdc -i $file -o /dev/null done这个步骤看起来简单但能挡住绝大多数手误——比如漏了一个括号、写错了一个箭头方向。更重要的是CI里也顺便生成了最新版的PNG图片产物直接发布到文档站确保文档站上永远展示的都是“最新且合法”的图。这已经不只是画图工具了而是图表治理体系的一部分。再分享一个我们正在用的技巧结合Git subgraph做图表的“多环境”管理。比如同一个部署架构开发环境、测试环境、生产环境只是节点数量不同。不用维护三份文件而是把公共部分抽成一个基础文件再用Mermaid的!include指令引入模板块加一层变量替换就生成不同环境的图。这样架构图跟着环境配置走永远不会出现“开发环境更新了生产环境还是旧的”这种问题。4. 常见问题与排查技巧实录4.1 语法看着没问题渲染出来却错乱这是diagram-design新手上路最常见的挫败点。文件里的字都打对了箭头方向也没毛病但渲染出来的图就是“丑”要么连线交叉要么层级错位。先说一个最容易忽略的原因方向声明。Mermaid里的TD、TB、LR、RL不是装饰它决定引擎的布局方向。默认的TD从上到下适合流程图但画架构图时我通常会改成LR从左到右因为大部分系统的数据流是从上往下还是从左往右跟你描述的边界高度相关。一个常见的错误是把一个带横向依赖的图配了TD方向引擎被迫把所有节点按纵向堆叠结果自然是天女散花。接着是子图与节点归属混乱。子图嵌套子图、节点跨子图连线这些都会显著增加布局难度。引擎不是不能处理而是处理得比较吃力。建议是子图之间尽量通过子图入口节点连线不要在子图内部直接调用另一个子图内部节点。这就像模块化代码一样保持接口干净布局引擎才会给你干净的排布。还有一种情况比较隐蔽使用特殊字符没转义。中文括号、一些特殊符号尤其是带引号或冒号的节点文本尽量用引号包起来或改成全角符号否则解析器可能意外截断文本。我在写数据库节点的时候经常出现这种问题比如DB[(PostgreSQL: 主库)]里面的冒号容易触发解析异常要么报错要么渲染残缺。规避方法是简单写DB[(PostgreSQL主库)]不写冒号。4.2 中文显示乱码或字体发虚很多从英文文档切过来的人第一次渲染带中文的图就踩坑了。Mermaid CLI默认加载的字体可能不支持中文渲染出来要么是方块、要么是乱码。这个问题不是Mermaid专属PlantUML、D2多多少少都有。解决思路无非两种要么指定系统里已有的中文字体要么把需要的字体文件嵌入到PUPPeteer渲染环境里。第二种比较可控我推荐。在项目里放一个puppeteer-config.json{ args: [--no-sandbox, --font-render-hintingnone], executablePath: /usr/bin/google-chrome }然后在CSS文件里定义好字体栈font-face { font-family: NotoSansSC; src: url(./fonts/NotoSansSC-Regular.otf) format(opentype); } /* 或者直接用系统字体 */ :root { --mermaid-font-family: NotoSansSC, PingFang SC, Microsoft YaHei, sans-serif; }更省事的方式是直接用系统字体把mmdc命令的配置里加一个--font-family参数指向系统已装好的中文字体。在Linux服务器上一般装一下fonts-noto-cjk就解决了。4.3 单张图规模失控拆解还是压缩一个场景我已经踩过三次了架构图越画越大最后变成一张巨型地图。节点四五十个、连线上百条渲染SVG文件能达到几兆打开文档页面浏览器都卡顿自动布局完全失效图的可读性几乎为零。这个时候最有效的操作不是“继续调样式”而是“拆分语义层”。我的拆分原则是图表类型合适规模超出后的建议系统架构全景15-25个节点拆成“接入层/平台层/数据层”三张图时序图5-8个参与者按业务场景拆成多张场景图流程图不超过15个节点拆成主流程异常分支两张图数据模型ER图不超过20张表按限界上下文拆成多个领域图拆分之后再用链接把各张子图串起来。比如在全景图里的某个子模块节点上加上点击链接指向对应的详细图。Mermaid支持给节点设置click事件这样既保持了全局视野又能下钻到细节。这才是架构文档该有的交互形态。还有一种做法是利用Mermaid的zoom插件让用户可以在页面上缩放查看大图。但这只是治标图上承载信息太多读者还是抓不住重点。记住一句话一张图讲一个故事讲得好比讲得多重要得多。4.4 多人协作时如何维护图表规范diagram-design落地之后最大的挑战不是技术而是“人的一致性”。团队里有5个人都在用每个人写的图风格都不一样有的用TD有的用LR有的喜欢在节点里写英文有的写中文时间长了文档库还是一片混乱。我的做法是三层规范第一层是项目模板。每个人新建图表文件时直接以团队样板文件为起点里面已经预置了主题、方向、常用子图结构。人都有惰性给模板比给规范好用得多。第二层是自动检查。CI里不只是跑语法检查也跑风格检查——节点是否都给出了明确文本、是否使用统一颜色映射、连线是否有标签。这些可以写成一个简单的脚本解析.mmd文件做规则检查不通过的给出警告。虽然不能做到100%自动化但能在流程上逼一下。第三层是定期Review。我每两个星期会做一次图表专项Review把新增和修改过的图全部过一遍重点检查两件事图的主题是否符合当前系统现状图的表达方式是否符合团队的阅读习惯。这个Review的重要性被很多人忽略——图是写给人看的定期站在读者角度去审视才能让规范真的发挥作用。5. 一点真实的项目体会做diagram-design这套体系不是一蹴而就的。最开始我也只是在文档里零星嵌入几张图觉得方便。后来在一次大版本重构中需要同时产出十几张架构图和流程梳理我把整套流程打磨成了现在的标准化方案。从那以后我对“图即代码”的理解开始变得具体它的价值不是省掉拖拽鼠标的动作而是彻底改变了图表在团队协作中的生命周期。图不再是某个人的个人产物而是像代码一样可以被检视、被评审、被追溯。如果让我给刚接触diagram-design的人一句最实在的建议那就是先不要追求语法全面覆盖也不要急着搭复杂流水线。挑一个你手头正在写的文档把里面需要画图的部分用Mermaid重写一遍渲染出图看看效果感受一下“改一行文本、图就变了”的过程。这种即时的正反馈比我在这里说一万字都管用。等你在两三个项目里都用顺了再回头去考虑主题统一、CI集成和团队规范。工具是可以替换的工作流才是真正的复用资产。diagram-design真正教会我的不是怎么画图而是怎么让图在项目里活起来并且持续保鲜。