拓冰建站拓冰建站
首页 / 资讯中心 / 正文

代码化制图指南:用Mermaid实现可维护的架构图与流程图

画图这件事做了十年软件我都绕不开它。方案评审要画架构图代码注释里要放时序图README 里得补一张流程图连给运营同学讲数据链路时都得靠 diagram。diagram-design 说白了就是“把脑子里那幅图变成别人能看懂的一幅图”。这句话很朴素但能做到的人真的不多。我见过太多团队图是画了画完自己都改不动协作时更是灾难——有人用 Visio有人用 draw.io有人拿 PPT 拼方块最后文件全变成“最终版_v3_修改2”躺在网盘里。这一篇我会用实际踩坑换来的经验把从设计思路、工具选型到落地实现、常见坑位的完整路径都走一遍重点说说为什么我最终选择了代码化制图这个方向以及怎么让你的图能持续维护、能跟着代码演进。内容适合正在给项目画图、想用代码管理图表、或者刚接手一个没有文档的技术团队的人。不需要你有图形设计基础能写 Markdown 基本就能跟上。1. 先想清楚你画的到底是什么图1.1 图表不是装饰它是信息压缩的效率工具先给图找一个正确的定位。有人把图当交付物觉得画得越满越有工作量于是架构图里塞 80 个方块评审时没有一个人愿意认真看。有人把图当思维整理想到哪画到哪最后只有画图的人自己能看懂。还有少部分人把图当沟通媒介一切设计都围绕“对方能否在 20 秒内看懂核心结构”展开。我建议你采用第三种心态。为什么是 20 秒因为现代人的注意力和耐心都非常有限。评审会上大家扫一眼图能建立初步心智模型才有可能对细节提出有效问题如果这张图第一眼就是密密麻麻的节点和箭头绝大多数人只会礼貌性点头然后继续低头看手机。好的 diagram-design本质上是在做信息压缩把一段需要两千字才能说清的结构关系压缩成一张 20 秒能读完的图。但压缩一定有损失有损失就必须做取舍只保留目标读者当前最需要的信息层次。所以动手前第一件事不是打开工具而是判断这张图存在的理由是什么。是帮助新人理解主链路是评审时讨论模块边界还是上线前确认部署关系理由不同图的内容和抽象粒度完全不同。理由不清晰图画得再漂亮也只是自我感动。1.2 常见图型与适用场景速查在动手之前先知道自己要画的是哪一类图。不同图型解决的问题不一样选错图型表达效果直接打折一半。流程图flowchart主要表达“先做什么再做什么判断后走哪条路”。典型场景是业务流程、接口处理流程、部署发布流程。判断标准很简单如果文字描述里反复出现“如果、否则、然后”大概率就是流程图。时序图sequence diagram表达“谁在什么时候调用谁按什么顺序传什么参数”。典型场景是多系统交互、分布式链路追踪、SDK 调用过程。如果核心是多个参与者之间的先后顺序而不是流程判断就用时序图。状态图state diagram表达“一个对象在生命周期里有哪些状态事件触发后怎么转移”。典型场景是订单状态、微服务实例状态、审批状态。类图与 ER 图表达“数据结构与关系”。类图偏代码层ER 图偏数据库层两者侧重点不同但很容易混淆。架构图architecture diagram表达“系统由哪些模块组成、模块之间如何依赖、流量如何流转”。它其实是多种图型的组合也最考验设计师的抽象能力。数据图饼图、柱状图、折线图表达量化信息一般用于汇报和指标分析。图型核心问题典型场景选错时的表现流程图接下来按什么顺序执行业务流程、CI 流水线画成架构图后看不出先后顺序时序图参与者之间怎么交互接口调用、事务过程画成流程图后看不出调用方状态图对象如何迁移订单状态、实例生命周期大量箭头交叉可读性差类图/ER 图类和表之间如何关联领域模型、库表设计信息过载评审无人看架构图模块与依赖边界系统设计、部署方案忽略流量方向看不出主链路数据图数值关系变化报表、指标分析用流程图硬套信息失真选型时还有一个常见误区以为一张图能承担所有职责。实际上越是复杂的系统越需要多种图型配合使用例如用一张架构图展示全貌再用若干张时序图补充关键链路的交互细节各司其职比硬把所有信息塞进一张图里要清晰得多。1.3 设计之前先回答 5 个问题我每次画图前都会在脑子里过一遍这 5 个问题简单但非常有效。给谁看这决定了术语密度和信息分层。给技术团队看可以放心画 JVM、数据库连接池、消息队列给业务方看只画“入口、能力、出口”就够了连节点命名都要换成业务语言。想表达什么一张图只讲一个核心观点。常见陷阱是“想在一张图里既展示全貌又展示细节”结果两个都没讲清。如果发现自己正在补充很多旁支信息说明该拆图了。信息层级有多少如果一张图里超过 30 个节点我会强烈建议拆图。节点越多布局越难、连线越乱、改图越累读者接收信息的效率反而越低。布局方向是什么流程类一般从上到下时序类从左到右。方向在代码化工具里只是参数但在设计时要提前统一混用方向会让人迷失。这张图要活多久如果是临时涂鸦画多丑都行如果是长期文档就必须考虑可维护性。这个问题直接影响下面的工具选型。2. 工具选型为什么我最终选了代码化制图2.1 主流方案横向对比与适用边界市面上的画图工具五花八门按照“是否代码化”可以粗分成两大类拖拽类和代码类。拖拽类代表有 draw.io、ProcessOn、Excalidraw、Visio代码类代表有 Mermaid、Graphviz/DOT、PlantUML。两类我都深度用过下面这张表是我个人的直观感受。方案学习成本版本管理自动布局维护成本适合场景拖拽类draw.io 等低差手动高一次性草图、白板讨论Mermaid低极好自动低文档、README、团队规范图Graphviz/DOT中好强中复杂关系图、自动生成图PlantUML中好自动中UML 语义强、代码建模拖拽类工具的共同问题是图的背后没有一个清晰的数据模型你保存的只是一个视图工程文件。一旦结构发生变化要增加节点或者改连线就必须手动拖拽、重新对齐、调整跨线改一次至少 20 分钟。代码化制图则不一样你改的是声明式文本布局算法会自动重排。对高频变化的项目文档来说这个维护成本差异非常明显。Graphviz 的强项在于节点关系非常复杂时它的自动排版算法仍然能给出相对稳定的结果PlantUML 则更贴近软件工程语义类图、时序图、用例图都有专门语法。两者都有学习曲线。Mermaid 虽然功能不算最全复杂的美化效果也做不了但它是“文本 图”工作流里最顺滑的语法简单到像写 Markdown 一样这也是我日常选用它的原因。2.2 代码化给团队协作带来的三个隐性收益选代码化制图不只是自己改图方便更重要的是它改变了整个团队的协作方式。我有三个很深的体会。第一个是 diff 可读。拖拽图保存后通常是二进制或私有格式代码评审时根本没法逐行 review别人只能看到“哦图变了”但说不清哪里变了。Mermaid 这类纯文本图可以直接出现在 PR 的 diff 里改没改、改了什么一眼就能看出来。这一点对技术团队非常重要因为图常常是评审的重点对象。第二个是可复用、可生成。既然图是文本就可以在模板、脚本里动态生成。我做过从数据库元信息自动生成 ER 图也做过从接口清单自动生成依赖图这在拖拽类工具里几乎不可能实现。数据变化时图跟着重新生成永远比手工维护的图准确。第三个是和文档系统无缝集成。GitHub、GitLab 对 Mermaid 有原生渲染支持Markdown 文件里直接写代码块就能出图mkdocs、VitePress 也有相应插件。这意味着图不需要单独维护一个文件它可以作为文档的一部分提交和版本化图的“居住地”和代码在一起天然不会失联。3. 核心语法拆解以 Mermaid 为例画结构图与流程图3.1 最小可运行示例与基本方向Mermaid 是代码化制图方向上一个很有代表性的工具也是我日常用得最多的一个。虽然它不是功能最全的图工具很多复杂效果做不到但它在“文本 图”的工作流里体验最顺滑。先看一个最基础的 flowchart。flowchart TD A[解析请求] -- B{校验权限} B -- 通过 -- C[执行业务逻辑] B -- 拒绝 -- D[返回错误]第一行flowchart TD是图声明TD 表示 Top to Down从上到下。要改成左右布局就写flowchart LR也就是 Left to Right。后面的每一行都是一个节点或一条连线A、B、C、D 是节点 ID方括号表示普通矩形花括号表示菱形判断--是带箭头的实线。这就是 Mermaid 的核心模型声明节点再声明节点之间的边。剩下所有的语法都是在这两个动作上做扩展。方向的选择也有一点讲究。从上到下适合流程步骤相对线性、判断分支不复杂的图从左到右更适合表达“调用关系”因为调用顺序天然是从左到右逐层深入。我的习惯是业务流程图用 TD系统调用图用 LR这样第一眼的信息方向就符合直觉。3.2 节点写法与常用形状节点是图的基本单元。Mermaid 提供了多种形状每种形状在语义上都有对应角色我常用的几种如下。A[文本]矩形普通节点最常用。A(文本)圆角矩形适合开始或结束节点。A((文本))圆形适合子流程入口或出口。A{文本}菱形适合判断分支。A文本]非对称形状适合输出或外部实体。A[[文本]]子程序或模块的表示。A[/文本/]平行四边形适合输入输出节点。这些形状不需要硬记做图时按角色选用即可。我的习惯是菱形只用来表达判断矩形只用来表达数据处理圆角矩形表达起止点这样读者只需要看一眼形状就能猜到节点性质。节点 ID 建议只用英文和数字显示文本放在语法符号的括号里就好中文标签可以直接放进去但千万别在 ID 里放中文或空格否则解析很容易出问题。3.3 连线语义箭头、标签、虚线、子图图的信息量其实大部分来自连线而不是节点本身。连线的类型直接影响读者对依赖关系的判断。--实线箭头表达流向或依赖方向最常用。---无箭头实线表达关联或相邻关系。-.-虚线箭头表达异步、间接或弱依赖。加粗箭头表达强流程或重点链路。-- 文案 --或|文案|给连线加标签说明关系内容。A -- 创建订单 -- B A -. 异步通知 .- C A 核心链路 D需要给模块分组时用 subgraph 语法。凡是属于同一个模块的节点放进同一个 subgraph 里图的层次会清晰非常多。subgraph 订单模块 O1[创建订单] O2[订单查询] end需要注意的是subgraph 的 id 不能带空格标签要写在 id 后面某些旧版本写法差异会导致渲染失败团队里最好固定一种写法。另外连线标签不要写得像代码注释一样长控制在六到八个字以内否则线上文字比节点还显眼干扰视线。3.4 样式与主题定制样式层面的定制主要有两个入口classDef 和主题变量。classDef 是为某一类节点定义统一样式比如给“核心服务”和“外部依赖”用不同填充色。classDef normal fill:#e8f4f8,stroke:#333,stroke-width:1px class A,B,C normal主题变量则在图开头用%%{init: ...}%%设置可以调整整体配色、字体、连线曲率等。%%{init: {theme: base, themeVariables: {primaryColor: #fafafa, fontSize: 14px}}}%%我的建议是颜色是用来传达语义的不是用来好看的。定一套固定色板就够用了比如核心服务用蓝色系、外部依赖用灰色系、异常链路用红色系全图颜色种类不超过四种。颜色一旦太多图就变成了彩虹读者反而抓不住重点。团队规范图尤其要统一配色防止每人画一个版本。4. 实操案例给“在线订单系统”画一张可持续维护的架构图4.1 场景设定与最终效果目标假设你刚接手一个订单系统新同事问主链路时总不能从数据库表讲起。此时需要的是一张能让不熟悉系统的人在 1 分钟内看懂“用户请求是怎么进来、经过哪些模块、最终落在哪些存储上”的架构图。这个目标决定了抽象粒度只画主链路上的模块不画内部实现细节更不画每一行的具体处理逻辑。这个例子我选在线订单系统是因为它是典型的后端业务系统几乎所有读者都能理解它的业务背景。最终效果应该包含客户端入口、网关、核心服务、异步消息、数据库与缓存以及日志告警这些横切能力。不要一上来就追求完整先画出主干再逐步补充依赖。4.2 分步实现从文本草稿到完整图第一步把节点先列出来。这一步不排版、不连线只把概念打散到桌面上。比如Web 端、Nginx 网关、订单服务、库存服务、支付服务、消息队列、MySQL、Redis、日志系统、告警系统。这个环节如果发现概念粒度不统一比如既有“订单服务”又有“订单超时状态机”说明信息层级混了要先想清楚再继续。flowchart TD Web[Web端] Gateway[Nginx网关] Order[订单服务] Stock[库存服务] Pay[支付服务] MQ[消息队列] DB[(MySQL)] Cache[(Redis)] Log[日志系统] Alert[告警系统]第二步把主链路连出来。先画最关键的调用顺序Web 端请求到网关网关到订单服务创建订单需要同步调用库存服务和支付服务再发一条消息到 MQ。这一段不需要追求完整先把主干理清楚让它能表达“一条订单请求是怎么走完主流程的”。Web -- Gateway Gateway -- Order Order -- Stock Order -- Pay Order -- MQ第三步加依赖存储与旁路。订单服务读写 MySQL 和 Redis库存和支付也有自己的存储MQ 的消费方属于旁路比如订单超时关单它不是用户请求的直接路径但确实依赖消息队列。日志和告警是横切能力用虚线连接到相关服务即可。到这一步我开始意识到“Order 到 MQ”只画一条线很难表达“发送事件”和“消费事件”两个角色于是拆解成两个节点MQ 生产者侧和消费者侧。第四步用子图分组并调整视觉层次。把网关集群、订单域、基础组件各放进一个 subgraph再给核心服务加色外部依赖用灰色。完整代码基本长这样flowchart TD subgraph Client[客户端] Web[Web端] end subgraph GatewayLayer[接入层] Gateway[Nginx网关] end subgraph OrderDomain[订单域] Order[订单服务] Consumer[关单消费者] end subgraph Deps[依赖服务] Stock[库存服务] Pay[支付服务] end subgraph Middleware[中间件] MQ[(消息队列)] DB[(MySQL)] Cache[(Redis)] end Web -- Gateway Gateway -- Order Order -- Stock Order -- Pay Order -- MQ MQ -- Consumer Order -- DB Order -- Cache classDef core fill:#e8f4f8,stroke:#1a73e8,stroke-width:2px classDef dep fill:#f5f5f5,stroke:#999,stroke-width:1px class Order,Gateway core class Stock,Pay,Consumer dep到这一步图已经能说明问题了。如果还想再严谨一点可以把“订单超时关单”这个异步链路的标签写清楚比如Order -- 发布超时事件 -- MQ再把MQ -- 投递事件 -- Consumer补上读者就不会产生“这消息是发给谁”的疑问。4.3 把图接进文档工作流README、CI 与团队协作图画完只是开始真正难的是让它一直保持更新。我见过不少项目架构图在评审当天很漂亮半年后和代码已经没有关系了。要解决这个问题必须把图嵌进文档和开发流程。首选做法是放在仓库根目录的docs目录下命名成architecture.md在 README 里加一个链接。由于 GitHub 和 GitLab 都能直接渲染 Mermaid 代码块图不需要导出成图片文件直接以源码形式存在仓库里。每次代码结构变化顺手更新这个文档如果依赖关系改了但图没改代码评审时其实很容易发现因为 diff 里能看到图文件没有变化。如果需要导出图片给非技术同事或者放进对外方案书可以用 mermaid-cli 的命令行工具例如npx mermaid-js/mermaid-cli -i input.mmd -o output.png这条命令会启动一个无头浏览器完成渲染导出的效果和本地预览一致。还可以把它写进 CI在文档变更时自动生成 PNG 并作为构建产物。团队协作时再补两条约定一张图只有一个 owner改动由 owner 负责提交 PR 时如果涉及模块依赖必须在同一个 PR 里更新图。这些约定不需要额外工具写在 CONTRIBUTING 文档里就够了。5. 常见问题与排障技巧实录5.1 渲染与语法问题速查表我整理了一张速查表都是实际使用中遇到频率最高的问题。遇到图渲染不出来先对照这张表排查一遍。症状原因解决办法节点内容变成纯文本没有渲染成图Markdown 代码块语言标识写错在文档里把代码块语言标识为 mermaid本地 CLI 用 mmdc 处理图渲染时报语法错误节点 ID 里放了空格或中文ID 只用英文、数字、下划线显示文本放在括号里中文标签乱码旧版本 Mermaid 或导出环境缺中文字体升级工具版本导出时安装中文字体并指定 font-family箭头方向画反混淆了 A -- B 的方向语义记住箭头指向的就是流向目标从源到目标书写subgraph 没有显示成矩形分组subgraph id 含空格或 id 大小写不匹配subgraph 的 id 不含空格后续引用大小写保持一致classDef 风格不生效class 语句写在了 classDef 定义之前先定义 classDef再写 class 赋值主题变量初始化报错init 里的 JSON 格式不对JSON 用双引号不要加注释写完检查括号图很大时渲染卡顿单图节点过多拆成总览图加局部详图一张图不超过三十个节点5.2 我踩过的三个典型坑第一个坑本地渲染正常推到 GitHub 上却报错。原因是不同平台的 Mermaid 版本不一致旧版本对某些语法和新特性支持不好尤其像、、这类特殊字符处理方式差异很大。后来我强制要求团队统一版本文案里避免特殊字符需要展示时用 HTML 实体写法这个问题就很少再出现了。第二个坑用 mermaid-cli 导出 PNG 时中文全部变成方块。排查下来不是代码问题是容器里没有中文字体。解决方法是给导出环境安装中文字体比如 Noto Sans CJK SC然后在 CSS 里指定font-family: Noto Sans CJK SC。这里要提醒一下本地编辑器预览正常不代表 CLI 导出正常两条链路要分开看。第三个坑一张图塞了 100 多个节点布局算法跑出来交叉线多到没法看。我把锅甩给工具后来才明白是设计问题。节点太多时任何自动布局都救不了可读性。正确做法是拆图总览图只画模块和主链路局部详图单独展开节点之间用 click 跳转关联起来读者需要看细节时再进去。5.3 团队落地阶段的三条建议最后说三条团队落地建议都是我实践过觉得比较有性价比的约定。第一单一图单一职责。一张图只表达一个核心观点节点数量控制在三十个以内。如果超过三十个节点说明这张图承担了两个以上职责拆开反而更清晰。第二图随代码走。图文件放进代码仓库的 docs 目录和 README、接口文档一起版本化。代码改了图也必须跟着改把“更新图”养成肌肉记忆。第三固定语义色板。全团队统一颜色规则核心服务用什么色、外部依赖用什么色、异常链路用什么色。视觉一致性看似小事长期维护时能省掉大量沟通成本。我在实际项目里有个朴素习惯每次画完图会找一个不懂这个系统的人来看只看 20 秒然后让他描述自己看到了什么。如果他说的和我最初想表达的差不多说明这张图合格如果他张口就问“这是什么、那是什么”说明图里的职责边界和信息层级还没理清楚。这个测试成本很低但比任何工具技巧都管用。diagram-design 说到底不是艺术比赛它是让团队少开几次无效评审、少写几段重复解释的技术动作。希望这篇文章能让你下次画图时少走我走过的弯路。
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门