ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

图表设计之道:如何用Mermaid画出清晰易懂的架构图与流程图

图表设计之道:如何用Mermaid画出清晰易懂的架构图与流程图 我先说个事儿刚做技术分享那两年我特别喜欢画图。架构图画得满满的一个模块恨不得用五种颜色标出来每根箭头都加上数字编号导致最终的图连我自己过两天看都得反应半天。后来被一个老前辈“点醒”了一次他扫了一眼我精心设计的架构图只说了句“你这张图需要阅读说明书才能看懂那它就不是一张好图”。这件事直接扭转了我对 diagram-design 的态度。其实好的设计图,跟写代码一样,本身就是一种沟通语言,该讲究的地方一样不能少。这篇文章想和你聊的就是 diagram-design 这件事,不单纯推荐工具,也不只讲套路,而是把“把复杂的东西画清楚”这套方法论拆开讲透。无论你是程序员要画架构图、产品经理画流程图,还是做 PPT 画逻辑图,这里面整理的内容应该都能帮你少走不少弯路。1. 内容整体设计与思路拆解1.1 diagram-design 到底在设计什么很多人觉得 diagram-design 就是“把元素拖到画布上、连线、加个颜色”,工具用得越熟,图就越好看。实际上把这个词拆开看,Diagram 的“设计”解决的从来不是画得漂亮,而是“让看图的人花最少的时间,理解最多且正确的信息”。我见过不少团队内部文档里的“高规格”架构图:信息密度极大,每个框里恨不得写三行注释,字体缩小到 8pt,箭头颜色六种起步。这样的图,其实已经脱离了 diagram 的本质。Diagram 的本质是结构化信息的可视化表达,换句话说,它是在帮读者省力,而不是炫技。在设计阶段,真正要做的第一件事是确定这张图的“唯一主题”。一张架构图就是为了说清楚系统分几层、依赖关系怎么样;一张流程图就是为了讲明白某个流程在什么条件下走左、什么条件下走右。如果把“系统整体架构”和“核心链路时序”塞进同一张图,那读者一定会迷路。1.2 从思维方式出发,而不是从工具出发我自己踩过最大的坑,就是“工具导向”。Mermaid 用得越来越熟之后,我一度养成了一个坏习惯:随手打开 Mermaid 编辑器,一边画一边想“现在还有什么语法可以用”。这个习惯非常危险,因为它把“表达什么”让位给了“能表达什么”。后来我调整了做图的流程:先花 80% 的时间把信息结构想清楚,再花 20% 的时间让它在画布上变得清楚。如果信息本身是混乱的,再强大的工具也救不回来;反过来,只要结构设计得足够清晰,哪怕用最朴素的文本画框(比如只用等宽字体加横竖线),也能非常有效地传递信息。具体执行的时候,我一般会先做四件事:列出所有要表达的信息点,一张便签只写一条;给信息点分组,找它们的归属关系(上下级、并列、流程先后、依赖关系);确定主视觉流,也就是读者的视线应该先看哪、再看哪;然后才打开工具,根据上面梳理出来的结构去选最匹配的图型。1.3 选择图型:不是所有关系都适合用同一种图画做 diagram-design 最容易犯的错,就是把所有信息都用“方框 箭头”的方式画出来。实际上,不同的信息关系对应不同的图型:信息关系类型推荐图型典型场景层级/隶属关系树状图、组织架构图团队结构、目录结构、类继承关系时间顺序/分支流程图、泳道图业务流转、审批流程、状态迁移比例/构成关系饼图、堆叠图、矩形树图数据占比、资源分布依赖/调用关系架构图、依赖图微服务调用、模块依赖时间线上多角色交互时序图、序列图API 交互、订单状态流转概念之间的交叉韦恩图职能边界、需求交集选对图型,等于画图成功了一半。因为它直接决定了读者的认知成本:比如你想表达“多个微服务之间怎么互相调用”,选时序图就远比选树状图要直观得多。2. 核心细节解析与实操要点2.1 可视化设计五要素:框、线、字、色、布局如果非要把一张 diagram 拆成最小的组成单元,其实就五样东西:框、线、字、色、布局。所有看起来高级的架构图、流程图、脑图,本质上都是这五样东西的组合与排列。框:承载一个概念实体。它的形状有含义,方框一般表示“系统/模块/组件”,圆角矩形通常表示“状态/过程”,菱形表示“判断”,圆形常用来强调“起点/终点”。线:表达元素之间的关系。直线表示“强关联/调用”,虚线表示“弱关联/可选依赖/异步”,箭头方向代表流向,双向箭头代表交互。字:最容易被低估。字号层级必须分明,主标题 模块名 说明文字,同一层级字号必须统一。色:最大作用是“分组”和“强调”,而不是“装饰”。同一个颜色覆盖的元素,读者会下意识认为它们属于同一类。布局:主导视线流动。好的布局是“从上到下,从左到右”的主干清晰,有主干道也有旁支路。这里我特别想提醒一句:颜色是做图的放大器,而不是做图的本体。有时候让你觉得一张图很专业,不是因为它颜色多,而是它用颜色把不同的逻辑域切得非常干净。我个人建议一个画布上最多出现 3 到 4 种色系,每种色系只承担一种逻辑角色。2.2 Mermaid 语法的关键细节与避坑搞定了设计思路,接下来聊聊实操工具。Mermaid 是一个基于文本描述的图表生成工具,最大的好处是可以用代码管图、进 Git 版本管理、自动参与 CI/CD 渲染。对于写技术文档的人来说,这对维护成本是质的降低。用 Mermaid 画图,最基本的语法结构是“类型声明 实体定义 关系/流程定义”。flowchart LR A[前端应用] --|HTTP 请求| B[网关服务] B -- C[用户服务] B -- D[订单服务] C --[(用户数据库)] D --[(订单数据库)]这段代码对应的就是最常见的一张简单架构图。但实际落地时,有几个特别容易踩的坑:坑 1:节点 id 用中文还是英文?我的建议是内部 id 一律用英文(比如 A、B、C,或者有语义的 user-service),展示出来的标签用中文,通过A[前端应用]这种语法赋值。这样一个好处是即使后面要调整显示文案,不需要动节点之间的连线关系;另一个好处是如果图特别复杂,id 用英文可以避免某些老版本 Mermaid 解析器在中文路径下出现编码问题。坑 2:关系语句里不要忘了区分箭头形态Mermaid 支持--(实线箭头)、---(实线无箭头)、-.-(虚线箭头)、(粗箭头强调)、--o(带空心圆点的线表示聚合)等不同形态。语义一定要统一,不能随便用。比如弱依赖就用-.-,强调用就用--,主流程强调就用,别为了“好看”把箭头混着乱用。坑 3:子图的作用不是装饰,是分域当图里的节点超过七八个,人眼的认知负担就会陡增。此时优先用subgraph把节点按逻辑域包起来。flowchart TB subgraph 接入层 A[API 网关] B[负载均衡] end subgraph 业务层 C[用户中心] D[订单中心] end A -- C A -- D B -- A这样即使节点很多,读者也容易抓到“接入层和业务层是平行的两块”这个关键信息。subgraph 的命名其实就是一个引导读者阅读的框架,也不要随便起名。坑 4:方向选择 LF 还是 TBMermaid 第一行的方向声明很重要。LR(Left to Right)适合展示系统横向分层(用户端在左、服务端在右);TB(Top to Bottom)适合展示纵向依赖(上层调用下层)或时间线流程。我自己的经验是,只要是画“系统架构/依赖关系”,首选用 TB;只要是画“流程/时序/管线”,首选用 LR。不要问为什么,先按这个约定跑一年,你会发现读者的理解速度明显变快。2.3 配色与字体的落地建议关于配色,曾经有朋友问我:“为什么我照着网上的高级架构图配色抄,画出来还是觉得脏?”问题不出在“颜色值”上,而在于颜色应用的规则不统一。比如你定了#4A90E2(蓝)给“业务模块”,那所有“业务模块”就必须严格用这个色,连透明度都不要变;如果一会儿用深蓝、一会儿用浅蓝,视觉上就脏了。我用过一套在自己项目里跑得很稳的规范,分享给你参考:主色(用于核心模块/主链路):单色系,如深蓝#2B5B9C辅助色(用于非核心但有关系的模块):同色系的浅色,如浅蓝#DCE7F5强调色(用于告警、重点、异常分支):偏暖色,如橙红#D9534F,但要用克制,一张图尽量不要超过 5 处文字色:统一深灰#333333,标题可加粗,注释用浅灰#666666字体方面,中文字体我用的是系统默认的“微软雅黑”或“苹方”,英文字体用 Helvetica 或 Arial 都行。有一个原则强推:同一张图里,字体家族不要超过两种。字体一多,配出来的图立刻“业余味”就出来了。3. 实操过程与核心环节实现这一部分我用一个具体的案例,把上面的设计思路和实操细节串起来。假设我们要为“用户下单后,订单系统与库存系统的交互”画一张状态时序图,目标读者是后端开发同事。3.1 动手前先想清楚的问题画图前,我不急着打开编辑器,先问自己三个问题:这张图要回答的问题是什么?——答案是:一次下单请求在订单服务和库存服务之间经历了哪些步骤,失败时如何回滚。核心对象有几个?——订单服务和库存服务,再加一个数据库作为参与者。主时间线是什么?——用户发起下单 → 订单服务创建订单 → 扣减库存 → 回写状态 → 返回结果。这三个问题想通了,图型基本就锁定了:时序图。因为信息的主轴是“时间顺序 跨对象交互”。3.2 用 Mermaid 实现时序图的完整过程Mermaid 里画时序图的语法不算复杂,我直接贴完整的代码,并逐段解释:sequenceDiagram autonumber participant U as 用户 participant O as 订单服务 participant S as 库存服务 participant DB as 数据库 U-O: 提交订单请求 O-O: 校验订单参数 O-S: 请求扣减库存(商品ID, 数量) alt 库存充足 S-DB: 执行库存扣减 DB--S: 扣减成功 S--O: 扣减成功响应 O-DB: 创建订单记录 DB--O: 订单创建成功 O--U: 下单成功 else 库存不足 S--O: 库存不足异常 O-DB: 主动回滚订单状态 O--U: 提示库存不足 end这段代码里,有四个特别值得说的细节:细节 1:participant U as 用户是给自己看的,也是给 Mermaid 看的你写代码时可以用 U/O/S/DB 这种短 ID 来操作,但最终显示给读者的是as后面取的别名。这一招在元素多的时候非常好用:代码里的 ID 越短越好,展示出来的名字越通俗越好。细节 2:alt...else...end是时序图的分支表达很多初学者以为 Mermaid 时序图只能画一条直线下来的流程,其实时序图里可以写分支表达。上面这个例子中,alt 库存充足和else 库存不足把两条完全不同的路径放进了同一个时间轴里,读者一眼就能看到“什么情况下走哪条路”。这是时序图表达状态分叉的经典实现。细节 3:实线箭头与虚线箭头的语义区分我在这里定义了一个约定:发送请求用-,返回响应用--。这个约定一旦定下来,不只在这一张图里用,我的所有文档里都统一采用。这样一来,读者只要习惯了你的符号体系,后面看任何一张新图都能秒懂。细节 4:加入专注上下文与说明在复杂一点的图里,光靠人眼去追链路是不够的。这里可以补充注释:比如Note over S,DB: 幂等扣减,防止重复扣减。我在真实的项目里会在关键节点旁边用 Note 注一行业务说明,这对后来接手的人帮助极大。sequenceDiagram participant S as 库存服务 participant DB as 数据库 Note over S,DB: 扣减接口需支持幂等 S-DB: UPDATE stock SET countcount-1 WHERE id? AND count?3.3 实操中 Mermaid 的渲染与嵌入实践这里再说一个对技术博主和文档维护者特别有用的实践:把 Mermaid 图嵌进 Markdown 文档,可以高效复用与更新。现在很多平台(比如 GitHub、GitLab、各类知识库系统)已经原生支持 Mermaid 语法渲染。也就是说,你在.md文件里直接写:mermaid flowchart LR A[输入] -- B[处理] B -- C[输出]保存后,文档系统会自动渲染成图,不需要导出任何图片文件。这意味着你做架构图再也不需要“画一张、导出一张、上传一张”的重复劳动,而且改图时只需要改对应的文本内容,再重新提交一次文档即可,每一次改动都被记录在版本历史里。 如果你的知识库系统暂时不支持 Mermaid(比如某些传统 Wiki),常规做法是用 mermaid-cli 在本地把 .mmd 文件导出成 SVG 或 PNG: bash mmdc -i input.mmd -o output.svg -b transparent -w 1600这里有个小经验:-b transparent是把背景设为透明,这样即使在深色主题的 PPT 里也不会出现白色方块,非常实用;-w 1600指定输出宽度,保证在 Retina 屏幕上不至于模糊。实测下来,这个 CLI 方案在自动化文档流水线里非常稳定。3.4 从 Mermaid 到其他图形语言的迁移思路Mermaid 并不是唯一的选择。实际项目中我见过不少团队用 PlantUML、Graphviz/Dot、D2、以及基于网页的 draw.io/Excalidraw 来画图。这里边没有绝对的“最好”,只有“最合适”。如果你要问我的建议:追求代码可控、版本管理和自动化渲染,Mermaid 是对多数技术团队最友好的选择;追求矢量图布局自动优化,Graphviz 的 Dot 语言更强大,但学习曲线陡一点;追求“模型代码和文档双向同步”,PlantUML 的 C4 模型模板值得参考;追求灵活的手工微调和视觉美观,draw.io 或 Excalidraw 更方便,但不利于版本管理。我的建议是:不要轻易让团队成员同时用三套不同的画图工具,否则文档里的图会风格混乱、难以统一维护。选定一套作为“默认标准”,其他工具作为个人画草稿的辅助就够了。4. 常见问题与排查技巧实录4.1 为什么 Mermaid 渲染出来和预览不一样这个问题我遇到过不下五次。最常见的原因是平台端 Mermaid 的版本和本地 CLI 版本不一致。比如,本地用 10.x 画的语法,老平台还在跑 8.x,某些新引入的语法(比如block-beta这类实验性图型)就会解析失败。排查思路很简单:先确认平台支持的最低版本,再在本地用对应版本渲染一次。如果本地 OK 但平台上不行,直接在例子里%注释掉有问题的部分,逐步二分排查,定位到底是哪一行的语法引发了解析失败。4.2 节点一多,图就乱成一团怎么办这是所有 diagram 使用者必然会遇到的一道坎。节点数量到 20 个的时候,横七竖八的箭头会让整张图的可读性急剧下降。解决思路其实很朴素:拆图。一个复杂系统画一张大图,往往会“什么都说了,什么都没说清”。更实用的做法是:先画一张“总览架构图”,节点控制在 10 个以内;再针对每个核心子系统分别画“子模块依赖图”。打个比方,这就像看城市地图——你先看全局交通图,再点进某个商圈看街道明细,这种分层设计远比把整座城市所有道路压在一张大图纸上要清晰得多。4.3 箭头方向的语义不统一,经常引发歧义有同事曾经兴致勃勃地画了一张微服务调用图,在他眼里粗线代表强依赖,细线代表弱依赖,虚线代表异步。但看图的人并不知道他设定过这套规则,于是每个人都会按自己的直觉去理解,结果就是一张图引发三场误会。所以我强烈建议:在每一张交付出去的 diagram 上,用图例把符号语义解释清楚。这一步非常小,成本极低,但收益巨大。图例可以直接放在图上方或者右下角,哪怕只是三行小字:实线 同步调用虚线 异步通知双向箭头 双向交互4.4 画完发现逻辑有误,改图太费劲怎么办如果你用 Mermaid,这个问题其实已经被极大缓解了,因为图是“代码生成”的,改逻辑就是改文本。但如果你用的是纯手工拖拽的 draw.io,改一次布局可能比重画一次更费劲。我的建议是:不要直接在 draw.io 里精修一张复杂图。先用 Mermaid 把逻辑结构梳理和验证通过,再导入 draw.io 继续细化视觉呈现。先保逻辑,再谈好看,顺序不能反。这一条是真实经验,不是空话。4.5 常见语法速查与避坑清单最后整理一个简单的速查表,方便日常使用的随手翻阅:需求Mermaid 推荐写法避坑提醒画流程分支flowchart TDif/else结构条件分支用菱形节点Q{条件}画跨模块时序sequenceDiagram每个参与者用短 ID as别名画分层架构flowchart TBsubgraph同层模块保持同一色系画依赖关系flowchart LR 虚线箭头-.-弱依赖用虚线,强依赖用实线画状态流转stateDiagram-v2不要漏掉初始和终止状态5. 从画图到设计:进阶技巧与心法5.1 让看图的人第一眼就知道“该看哪”一张 diagram 是否有设计感,有一个很微妙但极其关键的评判标准:读者扫第一眼时,视线重心是否落在你想强调的那部分内容上。在视觉排版上,我常用的做法是“中心聚焦法”:把最重要的模块放在画布的正中央,或者把最重要的链路设计成从上到下的最粗主线;次要的内容退到两侧或底部,用浅色处理。这样读者虽然还没有逐字阅读整张图,但视线已经被你引导到核心区域了。5.2 花同样时间,不如把图“养”起来最后想分享一个比较个人化的观念:养成在项目中**维护“图文档”**的习惯,而不是维护“一张张的图”。什么意思呢?就是在项目的文档中心专门建一个diagrams/目录,每个核心模块对应一个.mmd源文件,并配套一张 README 说明每张图的用途与更新时间。之后无论是新同学 onboarding,还是架构评审会前的临时找图,你都能在两分钟内定位到正确的版本。既然图已经从“图片”进化成“代码”,那就应该像对待代码一样对待图:进 Git、命名规范、留下变更注释。这比任何花哨的工具都更能长期地改善技术文档的质量。踩过这么多坑之后,我现在的体会是:diagram-design 这件事情,门槛不高,天花板也不低。它考验的不只是工具的熟练度,更是对信息结构的思辨能力。哪怕只是从今天开始,画图时先想清楚“这张图到底要回答什么问题”,你就已经跑赢了 90% 的人了。
返回列表