diagram-design:代码优先的技术图表设计与实践

发布时间:2026/9/15 6:49:55
diagram-design:代码优先的技术图表设计与实践 最近在整理技术文档的时候我发现团队里最耗时间的其实不是写代码而是画图。架构图、流程图、时序图每张图的画风都不一样有人用ProcessOn有人开Draw.io还有人直接在Figma里连线结果就是文档里塞了一堆风格割裂、更新不及时的示意图。后来我把整套画图流程重新梳理了一遍沉淀出一套自己的做法并把它命名为“diagram-design”。diagram-design不是某款具体软件也不是一个标准规范而是一套把“图示”当成正式设计交付物来对待的工作流。它覆盖了从需求拆解、工具选型、布局排版到最终产物嵌入文档的完整链路。这篇文章把我的实操经验、踩过的坑、以及每一步为什么这么选一次性讲清楚。不管是做技术方案、产品原型还是写课程讲义、项目汇报这套思路都能直接套用。1. 项目初衷与整体设计思路1.1 为什么需要一套独立的diagram-design流程很多人觉得画图就是“打开工具拖几个框连几条线”但真正做过的人都知道一张图从草稿到能放进正式文档至少要经历三到五轮调整。最常见的问题有三个第一需求本身不清楚。业务方说“画一下新的下单流程”但下单流程涉及用户端、订单中心、库存系统、支付回调到底画到哪个粒度是给技术评审看还是给业务验收看如果不提前确认画出来的图大概率会被打回。第二风格不统一。一张图里出现了圆角矩形、直角矩形、菱形、圆柱体还混用了五六种颜色看的人很容易抓不住重点。实际项目中图的首要目标是传递结构而不是展示美术能力。第三更新维护困难。拖拽式画图改起来非常痛苦尤其是图变大之后挪一个节点要连带调整一整片连线。版本管理更是不用想没人知道这张图是什么时候改的、为什么改的。diagram-design要解决的就是这样三个问题需求对齐、风格统一、可维护性。它的核心理念是把画图从一个“临时动作”变成一个“设计过程”用一套固定套路来降低每张图的试错成本。1.2 这个项目的目标形态从三种图切入做diagram-design的过程里我给自己定的范围是先把技术文档里最高频的三种图做好架构图、流程图、时序图。这三种图覆盖了大约80%的日常需求而且它们的构图逻辑差异足够大搞懂了这三种其他像状态图、ER图、甘特图基本都能触类旁通。架构图重在展示系统的分层和模块边界。流程图重在展示业务分支和决策路径。时序图重在展示对象之间消息的先后顺序。三种图对布局的敏感点完全不同架构图怕层次乱流程图怕分支多时序图怕消息线交叉。后面我会详细讲针对每种图的具体处理方式。1.3 方案选型为什么我最终选择了“代码优先、可视化辅助”选工具之前先明确了一个原则只要条件允许优先用基于文本的工具生成图而不是用鼠标对着画布拖。原因很简单。文本工具有三个天然优势。一是可版本管理改一行文字就等于改一次图提交到Git里能看到完整的变更历史。二是可复用常用的组件定义、样式变量可以抽出来反复使用。三是可自动化画图逻辑可以和代码逻辑放在一起维护图从代码里生成永远和代码保持一致。当然纯拖拽式工具也不是没有价值。快速画个草稿、和同事白板讨论方案的时候拖拽式工具效率更高。我的实际选择是“双轨制”正式文档中的图用代码生成临时讨论的示意图用拖拽工具随手画。2. 工具选型解析与比对2.1 主流图表工具的横向对比市面上的画图工具我基本都用过简单排一下梯队。第一梯队是Mermaid语法简单和Markdown文档集成度高GitHub、GitLab、Notion都原生支持。第二梯队是PlantUML语法成熟功能覆盖面广尤其适合UML类图。第三梯队是Draw.io可视化拖拽能力强离线可用适合做复杂的大型架构图。第四梯队是Graphviz老牌工具布局算法强大但语法门槛较高。另外还有Excalidraw和Figma这类更偏手绘风格的工具适合表达轻松、临时的想法不适合正式技术文档。选型的时候要结合自己团队的基础设施。如果团队用GitLab做代码托管、用Markdown写文档Mermaid几乎是零成本上手如果团队重度使用Confluence、需要交互式编辑Draw.io更合适如果经常画领域模型和类图PlantUML会让你很舒服。2.2 我最常用的组合方案我目前的固定搭配是Mermaid画流程图、状态图、时序图Graphviz画架构图Draw.io处理Mermaid表达起来比较吃力的复杂架构图。这三个工具覆盖了我百分之九十以上的场景。举一个实际例子我之前整理一套微服务调用链路文档涉及八个服务、四层调用关系用Mermaid的flowchart画代码写起来很顺手节点和边都清晰。但后来要把这张图转成PPT汇报材料Mermaid导出的SVG在排版上不够灵活我把同样的结构复制到Draw.io里重新排布了半小时效果立刻不一样。工具之间不是替代关系而是场景互补关系。2.3 为什么命令式语法比拖拽式更利于团队协作拖拽式画图的痛点在多人协作时暴露得特别明显两个人同时编辑同一张图几乎必然产生冲突。云协作工具虽然支持多人实时编辑但画布上的元素在合并时很难处理。相比之下文本格式的记录天然适合合并。每个人都提交文本变更就算有冲突Git的diff也能清楚指示出哪里改了。另外文本工具允许你“写图”这意味着可以批量生成图。比如我写过一个小脚本读一遍AWS资源清单自动生成一张Mermaid架构图整个过程不需要任何手动拖拽。这个能力是拖拽工具很难做到的。3. 核心细节解析与实操要点3.1 动手画图之前先搞清楚三件事很多图画的烂不是因为技巧不行而是在画之前没有想清楚三个问题这张图是给谁看的他想从中获得什么他需要看到哪一层细节给CTO看系统架构应该突出技术选型、服务边界、数据流向不要让他在图里找某个具体的字段名。给开发同学看模块划分就要把接口、依赖关系、部署单元标注清楚。给业务方看流程图不要出现技术名词用他们都懂的业务语言。“细节到哪一层”是最容易犯错的地方。我的经验是宁可少画一层也不要多画一层。图一旦超过二十个节点阅读负担会急剧增加。正确的做法是分层画把系统分成多张图一张图讲一个重点而不是试图在一张图里塞进所有信息。3.2 布局与版式设计的三项原则原则一分区与分层。自上而下的架构图每一层放一类组件。业务表现层在最上面应用服务层在中间基础设施层在最下面。区域之间用显式的边界区分不要让节点跨层连接。原则二流向清晰。流程图的主路径应该贯穿画布最好是从左上到右下分支路径要明显窄于主路径。这个逻辑和阅读习惯一致。为了让用户的视线停留在线路而不是回溯上不要画回头线如果业务上确实需要循环用标记注明循环条件。原则三留白与对齐。节点之间的间距保持均匀不要让某些节点挤在一起、某些节点空旷到找不到连接线。在代码式工具里间距可以通过固定层级顺序控制比如在Mermaid中用flowchart LR时尽量让同一层的节点数量相近这样生成的图会自动排列得比较整齐。3.3 配色、形状与字体风格统一的底层规则技术图的配色核心是“少即是多”。我的做法是三色原则一种主色表示当前重点模块一种灰色表示次要或依赖模块一种亮色用于高亮异常或重点路径。整张图尽量不要出现超过五种颜色。形状也要保持语义一致矩形是常规节点菱形是判断分支圆角矩形表示外部系统或终端圆柱体表示数据库。观众在解码图形时靠的是惯例你的图必须尊重这些惯例不要为了好看随便换形状。中文字体的显示问题是很多工具的痛点Mermaid在部分渲染引擎下默认字体对中文支持不好容易变成方块乱码。我的处理办法是在样式里显式指定字体比如设置fontFamily: Microsoft YaHei, PingFang SC并优先导出SVG格式这样在大多数环境里都能保证清晰度和中文正常显示。3.4 文字颗粒度图上写什么、不写什么图上的文字和信息密度直接相关节点里的文字越短越好。我的控制标准是节点标题不超过六个字连线标注不超过四个字详细的字段列表和解释放在图下方的说明文字里。不要试图用图替代文档。图的作用是提供结构视角文档的作用是提供细节解释。一张好图观众三秒之内能看出主体结构一张坏图观众看三分钟还不知道重点在哪。如果一张图需要花很长时间去“读”那它已经没有存在的价值了。4. 实操过程用代码式工具完成三类核心图4.1 架构图实操从模块清单到分层Layout先看一个典型的Mermaid架构图产出过程。我接手过一个电商后台的重构方案需要把新的模块边界画出来。第一步先列模块清单网关、用户服务、商品服务、订单服务、支付服务、消息队列、数据库。第二步划层级网关在最上层业务服务在中层中间件与存储在下层。flowchart TB subgraph ClientLayer[客户端层] Web[Web管理端] H5[H5移动端] end subgraph GatewayLayer[接入网关] GW[API Gateway] end subgraph BizLayer[业务服务层] User[用户服务] Product[商品服务] Order[订单服务] Pay[支付服务] end subgraph InfraLayer[基础设施层] MQ[(消息队列)] DB[(MySQL集群)] Cache[(Redis集群)] end Web -- GW H5 -- GW GW -- User GW -- Product GW -- Order Order -- Pay User -- DB Product -- DB Order -- DB Order -- MQ Order -- Cache Pay -- MQ画完之后检查三件事第一同一层级是否都在同一个subgraph里第二跨层连接数量是否合理如果某两个非相邻层直接拉了很多条线说明中间少了一层防腐第三标题是否简短。上面这个图标题都在六个字以内结构一目了然。用Graphviz画更复杂的调度链路时我会把每个子系统定义为node把依赖关系用edge表达。Graphviz的优势是自动布局能力强节点再多也不容易交叉乱飞缺点是需要额外学一套语法。建议非必要不优先用GraphvizMermaid在大多数情况下就够了。4.2 流程图实操分支多、回环多的处理策略流程图是最容易画“乱”的图。业务流程图如果超过十个节点再加上几个判断分支画布就会变得像蜘蛛网。我的经验是先把流程画成线性主干再处理分支。主干上只保留“发起→经过核心动作→结束”的路径分支用子程序或独立图表达。举例一个退款流程看起来简单但包含用户申请、商家审核、系统校验、原路退回、超时自动处理等多种情况。用Mermaid表达时我会把超时自动处理放到subgraph里不让它干扰主线。flowchart TB Start([用户发起退款]) -- Apply[填写退款申请] Apply -- Check{系统校验} Check -- 通过 -- MerchantReview[商家审核] Check -- 不通过 -- End1([流程结束]) MerchantReview -- ReviewRes{审核结果} ReviewRes -- 同意 -- Refund[原路退回] ReviewRes -- 拒绝 -- End2([流程结束]) Refund -- Notify[通知用户] Notify -- End3([退款完成]) subgraph TimeoutTask[超时任务] Timeout[48小时未处理] -- AutoApprove[自动同意] end分支的颜色可以不统一但建议给分支条件加上统一的样式比如条件为“通过/成功”的统一用绿色语义失败/拒绝的用红色。这样受众扫一眼颜色就能判断正常路径和异常路径。4.3 时序图实操参与者顺序和消息层级的安排时序图在表达接口调用、异步消息流转、分布式事务场景时非常有用。画时序图最容易犯的错误是参与者顺序瞎排。我的规则是把最核心的两个角色放到最左边次要角色从中间依次往右排消息线长交叉就会减少。以用户下单为例涉及客户端、订单服务、支付服务、积分服务。先排参与者客户端在最左中间是订单服务右边是支付服务和积分服务。因为主链路是客户端→订单服务→支付服务→订单服务→积分服务这个顺序最顺。sequenceDiagram participant C as Client participant O as OrderService participant P as PayService participant I as IntegralService C-O: 1. 创建订单请求 O-O: 2. 校验库存 O-P: 3. 发起支付 P--C: 4. 支付链接 C-P: 5. 完成支付回调 P-O: 6. 支付成功通知 O-I: 7. 增加积分 I--O: 8. 积分结果 O--C: 9. 下单完成消息文案要清晰标号序号。时序图的读者是按顺序阅读参与的编号能帮助人快速定位。需要注意的是异步消息用虚线同步调用用实线这个约定必须遵守否则会误导读者对调用模型的理解。4.4 从代码到最终产物导出、嵌入与版本管理代码式工具画完图最终产出有两种形态一种嵌入到Markdown文档中动态渲染一种导出成图片放到PPT或Word。被嵌入到文档时建议直接使用Mermaid原生格式。如果是导出图片我倾向于导出SVG因为放大不模糊。要注意Mermaid导出SVG之后某些中文字体可能被路径化无法再用文本工具搜索如果需要后续改字最好保留源文件。版本管理方面我会把所有图的源文件集中到docs/diagrams目录文件名和业务模块对应。提交信息写清楚“更新了什么连接”。这样三个月后回来看还能知道这张图经历了什么。5. 常见问题与排查技巧实录5.1 中文乱码与字体渲染问题Mermaid渲染中文乱码在自部署环境中比较常见。排查思路很简单看渲染引擎使用的默认字体是否支持中文。浏览器端的mermaid.js渲染通常会继承当前页面的字体样式在页面样式中显式设置一个中文字体栈基本能解决。如果是通过命令行工具导出需要检查系统字体列表里有没有中文字体没有就安装fonts-noto-cjk之类的字体包。Draw.io的中文问题相对少主要出现在导出PDF时。解决办法是在导出设置里勾选“包含嵌入字体”或者把字体统一改成“Arial Unicode MS”。5.2 节点太多导致布局爆炸怎么拆解Mermaid自动布局在节点超过三十个时会开始出现连线交叉、节点重叠的问题。这不是bug而是自动布局算法在大规模图上的天然短板。解决方式不是硬调而是拆图。拆图有两种方向一是按层次拆把一张大图拆成几张局部图局部图之间用链接关联二是按场景拆把主流程一张图、异常分支一张图、依赖关系一张图。拆完之后再加一张全局概览图把分图之间的关系表示清楚。这样总体信息量不变但每一张图都是清晰的。5.3 布局方向难以控制怎么强制对齐Mermaid节点多了之后方向控制是个头疼问题。例如你想让两个节点强制左右对齐但它们被打散了。这时可以用一些隐藏节点和透明连线来“占位”这是老玩家的常用技巧。比如A --- B旁边增加A2[ ] --- B2[ ]利用不可见占位节点来撑出空间。Graphviz的方向控制则靠rank约束。{ranksame; A; B;}可以把两个节点强制放在同一水平线上。如果你在用PlantUML也可以通过隐藏关系例如A -[hidden]- B实现类似效果。5.4 多人协作时的格式冲突与统一团队使用代码式工具的最大阻力是每个人写Mermaid的风格不同。有人喜欢用flowchart TD有人习惯graph LR有人节点名写中文有人写英文。最后合并出来的图五花八门。解决方案是团队内定一个约定至少包含这三点方向统一流程图统一用flowchart TB节点命名统一用有意义的英文ID显示的标签用中文连接线统一同一层级的节点连线下沉式写法保持一致。同时把约定写进项目CONTRIBUTING文档并且用CI脚本里的npx mermaid-js/mermaid-cli做的简单格式校验和渲染检查语法不对就直接拦截。5.5 常见坑位速查表问题原因快速解决中文乱码渲染环境缺少中文字体显式设置中文字体栈箭头线交叉多节点顺序不合理按调用顺序排列参与者导出图片模糊使用了位图格式改导SVG放大不模糊分支太多显得乱试图在一张图里塞过多场景按主流程/分支拆图subgraph边界重叠子图命名冲突或节点跨子图检查subgraph内节点是否唯一自动布局不稳定节点数量超过自动布局舒适区缩小单图规模或换Graphviz6. 场景适配与扩展方向6.1 产品汇报场景把技术图改成人人能懂的图同样的系统架构给开发同学看的版本和给业务老板看的版本完全不同。给老板汇报时少画服务、多画能力。例如不需要把“用户服务”“商品服务”单独画成不同框可以合并成“业务中台”再把“扩展性”“高可用”“快速交付”这几个关注点用色块标注在旁边。重点不是展示复杂度而是展示价值。我习惯在汇报版本里隐去数据库、缓存、消息队列这些基础设施不隐藏它们是为了演示上云方案否则一般在汇报图里留一层“基础设施”即可不要细究到MySQL、Redis的型号。除非对方明确问。6.2 代码文档场景让图跟着代码一起走最省心的维护方式是让图直接放在代码仓库里并跟随代码一起评审。Mermaid源文件可以直接用markdown代码块嵌在.md文档里开发者提交代码时一并改动评审者在MR中就能看到图的变更。这样图不再是文档团队单独维护的资产而是开发流程的一部分。另一种扩展方向是把图当作测试断言的一部分。比如端到端测试的调用链可以直接让测试结果渲染成时序图失败链路自动标红。我写过类似的插件它读取测试trace渲染成Mermaid时序图断言的失败节点用红色显示。这个能力对排查线上分布式调用问题很有价值。6.3 从diagram-design到数据可视化设计diagram-design的思想还可以延伸到更广的数据可视化场景。图表的本质是信息编码不管是架构图还是折线图核心都是把数据映射成视觉元素。画架构图时养成的“少即是多”“明确层级”“控制颜色数量”这些习惯在做Dashboard、报表设计时同样有效。如果你后续想深入推荐研究一下多元数据编码、视觉通道匹配这些基础理论。你会发现diagram-design的坑数据可视化一个都不会少。7. 执行清单与迭代计划7.1 新项目接入diagram-design的四个步骤如果你打算把这个流程引入到自己的项目里我建议按以下顺序推进。第一步统一工具链让组内全部使用支持文本格式的工具第二步建立模板库把常用的流程图、时序图、架构图模板沉淀下来第三步写清楚约定包括配色、形状、命名规则第四步接入CI检查把渲染问题挡在合并之前。我自己的经验是最花时间的不是画图本身而是统一团队习惯。人们总是习惯性打开ProcessOn框选拖拽。这时候不要强行禁止可以让他们先用拖拽工具画画完再转成代码式图。经过两三次转化他们自己就会感受到代码式维护的便利。7.2 下一步给diagram-design加一套校验与自动化当前我的diagram-design流程还有一个不完善的地方缺少自动化校验。比如检查是否包含孤立节点检查连线是否跨越过多层检查节点文字是否超长这些都是规范里应该自动校验的点。我已经开始在写这套校验器。基本思路是解析文本生成AST再基于AST做规则检查。规划里它可以输出lint提示在CI中阻断合并。等项目跑通后再把这套校验规则开放出来。这就是另一个主题了之后有机会再展开细说。画图这件事表面上看是工具问题实质上是信息设计问题。只要把受众、目标、层级、风格这些底层逻辑想清楚用什么工具都能画出好图。反过来如果这些东西没想清楚换了再贵的工具也救不了。diagram-design是我在实践中走通的一套流程希望能给你一些参考。