
每次看到那种塞了二十多个节点、五颜六色还带各种虚线实线的“大杂烩”架构图我都替画图的人捏一把汗。这种图通常没人能一眼看懂更要命的是过两个月连作者自己都得靠猜。这也是我坚持维护 diagram-design 这个项目的原因——它本质上不是一套画图工具而是一套关于“如何把复杂逻辑变成清晰图示”的工程化方法。简单说就是把画图从“靠感觉”变成“靠规范和结构”让每一张图都能被快速阅读、容易维护、甚至放进代码库里做版本管理。这篇文章会从 diagram-design 的思路出发讲清楚我为什么从一堆画图工具里最终沉淀出这套流程平时是怎么设计一张图的、遇到布局混乱又怎么排查也会分享两个我在真实项目里反复用到的成图案例。不管你是写技术方案的架构师、要画流程图的开发还是做产品文档的同学这篇文章都能帮你在下一次画图的时候少走弯路。1. 先搞清楚 diagram-design 到底在解决什么问题1.1 一句话定位不是画图是把复杂逻辑结构化很多人一听到 diagram-design第一反应是“学个工具不就行了”。但工具从来不是核心矛盾。你打开 draw.io 或者 Figma拉几个框、连几条线五分钟就能出一张看起来像模像样的图。可问题在于这张图的阅读成本、维护成本和修改成本往往被严重低估了。diagram-design 的思路恰好反过来先把逻辑结构化再考虑怎么画。也就是说在你动手拖拽方块之前你得先想清楚这个图里到底有哪些元素、元素之间的依赖方向是什么、哪些是核心链路、哪些是旁支信息。这个过程很像写代码之前的“设计数据结构和接口”底子打好了图层、配色、连线都只是表达手段。所以 diagram-design 更像是一套“图表表达方法论”它要求你在画图前先完成一次信息架构的梳理。这一步做扎实了后面无论用 Mermaid 还是手绘草图产出的图都会比临时起意画出来的清晰好几个档次。1.2 为什么我最终把项目收敛到“代码化图表”这条路我早期也试过用白板、Figma、draw.io 这类可视化工具后来发现一个致命问题凡是需要多人协作的图最终都要靠“人肉同步”。架构调整了、接口改了、节点新增了但图还是旧版。很多时候代码都重构完了文档里的架构图还停留在三个月前直接看谁都看不懂。后来我把 diagram-design 的思路收敛成了“代码化图表优先”。主流程用 Mermaid、PlantUML 这类文本化方案来表达图和代码一起提交、一起评审、一起改版。图的每一次变化都有 diff谁改了什么一目了然图永远不会和文档脱节。有朋友问我“文本画图多麻烦拖拽画图不是更快吗”我的回答是拖拽画图快在“第一次”代码化画图快在“每一次”。你只要遇到一次“改了接口导致整张图推倒重画”的场面就能明白文本化方案有多省心。1.3 这个项目适合谁能少走哪些弯路diagram-design 适合以下几类人写技术方案、做架构评审的开发者和架构师他们需要产出能被快速评审的图做技术文档、Wiki、README 的工程师他们需要让图示跟着代码版本走带新人、做培训的团队骨干他们需要画出新人一眼能看懂的流程图或链路图维护多套系统的运维和平台工程师他们需要把复杂的部署关系图化。如果你只是偶尔画一张私人备忘录式的手绘图那 diagram-design 对你的增益有限。但只要你画的图需要给别人看、需要反复修改、需要长期维护这一套“先结构化 代码化表达”的思路就能帮你省下大量沟通成本。2. 工具选型解析文本化图表工具怎么选才不踩坑2.1 Mermaid最适合嵌入文档和代码库的轻量方案Mermaid 是我在 diagram-design 里的首选工具没有之一。它的优势非常明确语法足够简单10 分钟能上手生态足够成熟GitHub 能直接渲染 Markdown 里的 Mermaid 代码块跨平台VS Code、Obsidian、Typora 都有插件支持。拿最常见的流程图举例你只需要写graph TD然后用--表示节点连接一张最基本的图就出来了。时序图、状态图、甘特图也都有自己的专属语法块。对大多数日常技术沟通场景来说Mermaid 的表达能力完全够用而且因为它就是纯文本放进 Git 里做 diff 非常自然。提示Mermaid 官方支持 10 种左右的图类型我最常用的只有 flowchart流程图、sequenceDiagram时序图、stateDiagram状态图和 C4 相关插件。2.2 从 Mermaid 到 PlantUML状态复杂时的升级选择如果你的图涉及大量“条件分支”、多人协作起来对格式有强约束Mermaid 有时候会显得“太自由”导致团队里每个人画出来的风格各不相同。这时候 PlantUML 是个很好的升级选项。PlantUML 的语法比 Mermaid 更工程化尤其在时序图和 UML 类图上的表达更严谨。它还有一个吸引人的特性支持通过 include 文件复用公共定义比如每个服务节点的高亮配置、统一的样式变量可以抽到公共文件里团队统一引用避免每张图各写各的。不过 PlantUML 的渲染通常需要依赖 Java 环境本地配置成本比 Mermaid 高。我在 diagram-design 里的建议是默认 Mermaid遇到复杂状态模型和 UML 需求再切换到 PlantUML不要把两个工具混在同一条文档里维护成本会翻倍。2.3 兜底方案Graphviz、Excalidraw、draw.io 各有用武之地我平时还会用到三类兜底工具各有各的典型场景GraphvizDOT 语言适合自动布局的复杂依赖图、调用链图。它的布局算法非常强节点一多也能算出相对合理的排布。但缺点是语法比较“底层”想要好看需要调很多属性不适合交互式创作。Excalidraw手绘风格图适合画概念草图、团队工作坊里快速产出“不那么严肃”的图。它的手写体风格能降低心理门槛让人更愿意给反馈。draw.io适合画“必须要拖拽、但又不想装重型软件”的图形。它支持本地文件、Git 存储还支持导出为各种格式。这些工具我都不排斥它们和代码化方案不是对立关系。我的实际经验是用 Mermaid/PlantUML 作为“可版本化图”的主力用 Excalidraw 和 draw.io 做“一次性草稿图”的输出端。2.4 我最终的组合方案和选择逻辑我现在维护项目文档时遵循这样一套简单规则图表类型工具理由流程图、功能链路图Mermaid轻量、可内嵌 Markdown、版本管理友好时序图、UML 类图、复杂的条件状态图PlantUML语法严谨适合复杂模型节点多、依赖复杂的调用链Graphviz自动布局能力强概念草图、头脑风暴Excalidraw协作门槛低、风格自由右键拖拽型临时图draw.io易上手、通用格式友好这个组合的核心逻辑是凡是需要长期维护的优先选择“文本可 diff”的方案凡是临时的、探索性的优先选择“交互自然”的方案。3. 先画对图再画好图我在设计原则上的几条硬标准3.1 一个图只表达一件事高内聚低耦合同样适用于图示很多图之所以难懂就是因为它既要表达调用链路又想表示部署拓扑还想顺手标出权限关系。结果读者根本不知道视线该往哪放。我在 diagram-design 里立了一条规矩一张图只回答一个问题。如果你想表达“用户请求从浏览器到数据库的完整链路”那这张图就聚焦在链路和节点上别把监控告警体系也塞进来。如果还有第二层信息要表达就再画第二张图不要怕图多图多但每张都清晰比一张图把所有人绕晕高效得多。这套原则在多人协作时尤其重要。我曾经接手过一张“万能架构图”里面包含应用服务、网络设备、中间件、数据存储、定时任务、消息队列……信息全得可怕但评审会开了半小时大家还在争论图上 ”Kafka 到底接的是哪条链路“。后来拆成三张图分别画部署、数据流和定时任务十分钟不到就对齐了。3.2 箭头的方向就是阅读的顺序别让读者猜箭头是图示的“语法”它的方向决定了读者理解信息的顺序。常见的设计混乱就是同一张图里箭头方向一会儿从上到下、一会儿从左到右甚至出现环状交叉读者得自己想办法找起点。我的经验是先确定主体方向。处理一件事的流程用从上到下天然符合阅读习惯表达系统之间调用用从左到右符合我们读代码时从左往右理解依赖的习惯。除非有极强的理由否则不要在同一个图里混用两个方向。另外用实线箭头表示“确定调用关系”用虚线箭头表示“异步或可选依赖”用无箭头的线段表示“关联”。这套语义如果在团队内形成共识图的表达能力会强非常多。注意任何箭头语义都要有图例说明。别觉得“这不明摆着吗”过两星期你自己都会忘了虚线是什么意思。3.3 颜色和标注是留给“重点”的不是用来装饰的我见过很多图一个系统里五种颜色每种颜色代表什么不说图例也不写。读者看了半天只觉得“五彩斑斓”但信息密度并没有因为颜色而提升。颜色在 diagram-design 里的定位只有一个标记重要维度。最常见的用法是区分“新增、不变、废弃、高风险”其次用来区分“核心链路、旁路依赖”。如果你非要给不同系统上不同颜色请务必先回答一个问题这个颜色差异对读者理解图有帮助吗没有帮助的颜色选择不如直接全用黑白灰。标注同理。节点边的文字注释应该是对“连接关系”的解释而不是重复节点名。比如两个服务之间的连线写着“调用订单接口”这个是有效标注写着“A服务到B服务”这就是废话。3.4 节点命名要能定位问题一张图要能当“关键词索引”用好的节点命名不仅用来阅读还便于沟通和排查问题。比如你在图上把一个服务命名为“订单中心”出了问题团队开会能直接说“订单中心的超时时间需要调”但如果你把它命名为“service-a”那沟通成本就显著提高了。我给节点的命名建议是用真实系统名或通用名词不要用缩写到只有自己懂的代号。如果对方看你的图是为了决策或排查问题那他应该能直接引用图上的名字去代码库或者监控系统里找到对应模块。这相当于把图示变成了“信息索引”一张图的价值就不仅仅是一张图了。4. 实操过程从需求到成图五步产出一张能直接用的架构图4.1 第一步先列清单把图里的“人、事、物”全写出来我画图从来不会直接打开编辑器开画。第一步一定是“列清单”把图里可能会出现的关键元素全部先写下来。拿订单系统举例清单可能是这样的用户触发入口订单服务核心处理节点商品中心依赖数据支付服务外部依赖消息队列异步解耦数据库持久化这一步的关键是“只做加法不做减法”宁可多列也不要漏。你会发现在列清单的过程中很多原本模糊的边界会逐渐清楚起来。比如你突然意识到支付回调也涉及一条链路那就顺手把它写进清单。4.2 第二步判断关系类型确定图类型和主体流向清单列完接下来是判断这张图应该用什么类型。如果元素之间是“请求—响应”关系用 Mermaid 的流程图就行如果是多个角色之间的消息往来用时序图如果侧重状态迁移用状态图。同时要确定流向。我通常的做法是从“用户”或“外部触发源”开始顺着请求方向一路梳理到最终数据落点。中间遇到“分流”就加条件判断节点遇到“异步”就用虚线并明确标注。这一步非常关键。因为很多图画得乱就是画图的人没搞清楚关系和流向就急着连线画到一半发现关系理不清又开始大改。先定流向能大幅降低返工率。4.3 第三步写 Mermaid 代码按分层思想组织初始脚本到这一步才真正进入编码环节。拿一个最简单的流程图示例来说不要一上来就写一长串先从主链路写好再慢慢补旁支。graph TD A[用户] -- B[订单服务] B -- C{库存是否充足} C -- 是 -- D[创建订单] C -- 否 -- E[返回库存不足] D -- F[发送消息] F -- G[消息队列] D -- H[(数据库)]这个例子里我用到了方形节点、菱形判断节点、圆角异步节点、数据库节点的不同形态。写代码时先保证逻辑正确再考虑视觉美化顺序别颠倒了。然后把其他旁支逻辑继续加进来。如果分支开始变多就需要思考是不是已经超过了“一张图只表达一件事”的边界如果超过了就果断拆分。4.4 第四步本地渲染预览做“结构走查”而不是“美观走查”渲染预览的作用不只是看“好不好看”而是做一次结构走查。我会对着成图逐项核对每个节点是不是都在清单里出现过清单里有没有元素被漏掉箭头方向是否符合真实调用方向有没有画反判断条件是否覆盖了所有分支有没有逻辑盲区这整张图的起点和终点是否一目了然一个从没接触过的读者能不能在 10 秒内看懂主链路这一步建议站在“第一次读这张图的人”的视角来检查而不是站在作者视角。作者会因为熟悉而默认很多内容合理但读者没有这个背景他们只能靠图上的信息来理解。4.5 第五步加上必要的注记和图例提交到版本库图的结构走查完最后一步才是加注记和图例。图例的位置我习惯放图下方和图的说明文字放在一起。注释不追求多但一定要让对方知道“括号里的是什么意思”、“虚线是什么含义”、“颜色是怎么区分的”。然后就是提交到版本库。把.md文件和代码一起提交走同样的评审流程这样图的变更就不会孤立在文档站之外。团队看到 diff 里的图代码变化自然会顺带检查逻辑是否同步更新。5. 真实案例拆解两张图两个典型场景5.1 案例A给新人讲清楚订单系统的核心链路这张图的场景是“新人入职培训”目标是让新人在 15 分钟内理解订单从创建到履约的最短链路。我在设计时做了三件事第一砍掉了所有非核心细节。支付回调、失败的补偿机制、超时关单逻辑都先不画只保留下单主链路。第二用颜色区分了“用户侧操作”“服务端处理”“外部依赖”三个层级并在图例里明确标注。第三所有节点命名都用系统真实名称方便新人之后去查代码。下面是简化的示意代码graph TD U[用户] -- O[订单服务] O -- P[支付服务] P --|支付成功回调| O O -- S[履约中心] S -- Q[消息队列] Q -- W[仓库系统]这张图的反馈效果很好。新人看完后能直接说出“用户下单后订单服务先调支付支付成功后才推到履约中心最后异步通知仓库系统”。而这个回答其实就是这张图的全部内容——它达到了“一张图讲清一件事”的目标。5.2 案例B技术方案评审中的部署架构图另一张图是操作系统上线方案的部署架构图读者是参与评审的资深工程师。这种图的难点在于既要让读者快速把握整体拓扑又要能看到关键交互点。我采用的方案是“横向分层 纵向分组”从上到下分别是接入层、应用层、数据层每层内部用虚线拆成不同子系统分组核心调用链用实线箭头加粗非核心关联用弱化样式。在实际画图时我还会刻意把图中不直接相关的网络设备简化成一个“网络边界”节点避免画一堆防火墙、负载均衡把读者注意力拉偏。评审会上大家能直接围绕图上的分组讨论“接入层这块的容错怎么保障”说明图的层级设计是成功的。5.3 这两张图背后通用的套路是什么把两个案例放在一起能总结出一个通用套路先定问题和读者再定主链路最后才排布细节。新人培训图的读者是“一无所知的人”所以细节全部让路评审图的读者是“经验丰富的人”所以要留出分层的结构和讨论的抓手。这就是 diagram-design 和普通画图最大的区别它要求画图的人在动手之前想清楚“这张图到底要帮助谁、辅助什么决策”。有了这个前提后面所有关于节点、线条、颜色、布局的选择都会变得特别顺畅。6. 常见问题与排查技巧实录一类类踩坑一条条补上6.1 语法没报错但 Mermaid 渲染出来布局拥挤混乱这个问题的根源多半是“节点和连线太多而且没有用子图分组”。Mermaid 的自动布局在节点超过 20 个且没有分组时基本一定会乱。解决办法是优先引入subgraph把同一职能域的节点分到同一个组里然后再把组内部的关系画好。另外减少跨子图的连线如果跨子图的连接很多说明你的子图边界划分得可能有问题。我自己的经验是如果一个子图内部超过 8 个节点就要考虑是不是该拆成更细的子图了。别高估阅读者的图形处理能力也千万别高估自动布局算法的“智能”。6.2 图内容太多放在文档里宽度超过阅读区域遇到这种情况第一反应不应该是“缩小字体”而是重新审视“是不是信息量过载了”。如果这张图已经突破 30 个节点大概率不是布局问题而是设计问题。我常用的审图方法是“缩放测试法”把图缩到 60% 的尺寸如果主链路还能被轻松识别说明结构基本合格如果缩到 60% 后就看不出来主链路了那这张图就该拆分了。6.3 团队协作时有人对 Mermaid 语法不熟导致维护断层这是文本化工具绕不开的问题。我的解决方案不是换回拖拽工具而是给团队做一份“最小必要语法清单”只列最常用的几种写法如何定义节点、如何连边、如何写判断、如何分组。把这份清单放进项目仓库里谁卡住了就查一下。另一个行之有效的做法是建立“成品示例库”把团队里画得好的图沉淀成典型示例新人直接参考示例来改而不是从空白文档开始硬写。这个做法成本极低但对团队一致性帮助特别大。6.4 常见问题速查表现象可能原因解决建议渲染出来节点重叠或拥挤节点过多且未分组用 subgraph 分组单组不超过 8 个节点布局方向不对读起来别扭未设置流向或混用多方向统一用 TD从上到下或 LR从左到右不要混用跨组连线太多图显得乱子图边界划分不合理重新审视分组逻辑按“职能域”而不是“部署位置”划分虚线实线语义不清团队缺乏统一规范在项目文档里约定虚线异步/可选实线确定调用图更新跟不上代码图和文档没走版本管理把图片、Markdown、Mermaid 源码一起纳入 Git 评审流程7. 分享一个我自己每天都用的最小工作流最后说点实在的。我现在凡是画图都遵循一个最小工作流先列清单再定流向然后用 Mermaid 写第一版骨架本地预览做结构走查最后放进文档提交版本库。整套流程最多消耗 20 到 30 分钟但产出的图基本一次就能被评审同事看懂。这个工作流里没有一步是“美化排版”因为在我看来Diagram 设计的美学标准只有一条信息传达是否足够准确和高效。如果一张图要为系统设计决策服务那它就应该是“结构化表达”的产物而不是“视觉炫技”的结果。diagram-design 这个项目让我在无数次“画了又改、改了又画、画完没人看”的循环里找到了一条稳定路径。如果你也在画图上反复吃过亏我建议你先别继续找新工具按这篇的思路把画图前的“结构化思考”作为第一步试试。相信一两张图之后你也会怀念这种“一次画清楚”的感觉。