ARTICLE DETAIL

资讯详情

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

图表设计实战:用代码化工作流打造可维护的架构图

图表设计实战:用代码化工作流打造可维护的架构图 1. 图表设计到底在解决什么问题1.1 从“画图”到“设计”的本质差异我第一次接触 diagram-design 这个项目标题时第一反应是这不就是画图吗但真正动手做起来才发现图和图之间的差距比人和狗之间的差距还大。随便拉几个框、连几条线那叫涂鸦能够表达系统结构、交代清楚调用关系、让新同学三分钟看明白核心流程那才叫图表设计。diagram-design 解决的核心问题其实是一个信息传递效率问题。你的系统可能有几十个微服务、上百张表、千奇百怪的调用链如果靠口述或者看代码去理解这些关系成本极高。而一张结构清晰的图表可以把这些关系压缩成一个视觉整体让人一眼看到全局。但这张图的前提是它必须被“设计”过而不是被“画”出来。什么叫被设计过就是你在画图之前已经想清楚了这张图要表达什么主题、给谁看、拆到哪个层级、哪些细节必须保留、哪些信息可以舍弃。很多人画图失败不是画图技术不行而是没想清楚这些问题结果画出来的图不是给自己看的就是给代码生成器看的唯独不是给人看的。1.2 好的图表设计必须满足的四个维度我在实际操作中总结了一张好图需要同时满足的四个维度几乎可以当成自检清单来用。第一个维度是正确性。图里的每一个方块、每一条连线、每一个标注都必须真实反映系统的当前状态。很多人画架构图喜欢凭印象画结果图上的模块和实际代码结构对不上这种图比没有图更坑人。正确性是底线不能妥协。第二个维度是可读性。正确但读不懂的图依然没有价值。可读性要求在布局上有明确的阅读顺序主流程清晰分支不喧宾夺主节点的文字大小适中、不拥挤、不重叠。我见过太多架构图密密麻麻几百个节点堆在一起放大三倍才能看清这种图除了让人产生敬畏感没有任何信息传达的作用。第三个维度是可维护性。图不是画一次就完事的系统在演进图就需要跟着更新。如果一张图需要手动画两个小时才能调整一个小变化那它很快就会被团队遗忘。这也是我后来会重点推荐“代码驱动的图表设计”的核心原因只有把图变成实体文件才能纳入版本控制才能支持持续维护。第四个维度是一致性。同一个团队、同一个项目里所有图的画风、色彩逻辑、命名规范、层级深度应该保持一致。这样当你看完一张图再看下一张图时不需要重新学习作者的“表达习惯”认知成本会大幅降低。这四个维度听起来简单但真正全部做到的团队少之又少。diagram-design 这个项目本质上就是在用工程化的思路把这四个维度固化成一套可执行的工作流。2. 图表设计的工具选型与技术路线2.1 三条主流路线全手动、半自动、代码化目标读者不同的图表适用的工具完全不同。我把市面上常见的做法分成三条路线大家可以基于自己的场景对号入座。第一条路线是全手动绘图典型代表是 Draw.iodiagrams.net、Visio、Excalidraw、Figma。这类工具直接在画布上拖拽图形、连线、微调位置自由度最高上手最快。适合画产品原型图、架构愿景图、临时讨论用的草图。但缺点是很难版本化不好做自动化检查多人协作时容易产生风格分歧而且随着图片信息量增大维护成本会指数上升。第二条路线是半自动典型代表是 ProcessOn、Lucidchart 这类在线协作工具或者说用 Notion/Confluence 的图表组件。它们在手动绘图的基础上增加了一些模板、图层管理和协作能力比纯手绘强一点但本质还是“人在画布上操作”底层逻辑没有改变。第三条路线是代码化Diagram as Code代表工具是 Mermaid、PlantUML、Graphviz、D2 等。用文本来描述图形的结构和关系再由工具渲染成图。这条路线的核心优势在于图是以文本形式存在的可以直接进 Git 仓库做版本管理可以做代码审查可以批量生成和修改。它的逻辑是“先有模型后有视图”非常适合系统架构图和流程图的长期维护。这三条路线不冲突我自己的习惯是临时讨论用 Excalidraw正式落地用代码化工具。diagram-design 这类项目真正值得挖掘的就是代码化路线的实战打法。2.2 代码化图表工具的横向对比既然推荐代码化那就得说清楚工具怎么选。我拿四个最常见的工具做了一张对比表大家可以直接参考。工具擅长场景语法门槛布局能力渲染效果适用人群Graphviz依赖关系图、结构图、自动布局中强dot算法偏工整、略生硬后端工程师Mermaid流程图、时序图、甘特图低中自动布局有待加强简洁美观开发、产品、文档写作PlantUMLUML全家族、架构图中中偏UML风格软件设计人员D2通用图表、现代风格低中偏强现代感强、灵活对审美有要求的团队Graphviz 是我最早接触的图表代码工具它的核心引擎是 dot专门解决自动布局问题。你只需要声明节点和边它来负责布线非常适合画依赖关系复杂的大图。缺点是你一旦不满意默认布局想手动调整的时候就会比较难受因为它的设计哲学是“相信算法不要人肉干预”。Mermaid 是目前社区热度最高的一个因为它语法足够简单十分钟能上手。我在文档里写架构流程图基本都用它。但 Mermaid 也有明显的短板复杂场景下的布局控制能力偏弱节点一多就容易挤成一团这时往往需要拆分图像而不是硬画一张大图。PlantUML 是老牌工具胜在UML 支持完整类图、时序图、用例图都很成熟。如果你要表达对象之间的继承、组合、依赖关系PlantUML 比 Mermaid 表达能力强很多。缺点是生成出来的样式有点“年代感”不过近期版本也在改善。D2 是后起之秀设计理念很现代语法也更友好输出效果相比 Graphviz 更加顺眼。它在2022年左右开始被越来越多人认识目前还在快速迭代中。如果你是新项目对审美要求比较高D2 值得一试。2.3 选型背后的决策逻辑工具不是越强大越好而是越匹配越好。我在实际选型时一般会问自己三个问题。第一个问题是这张图的读者是谁如果读者是技术团队、要看依赖关系Graphviz 和 D2 更合适如果读者是产品运营、要看业务流程图Mermaid 的渲染风格更接近现代文档审美。第二个问题是这张图的生命周期有多长临时讨论图怎么方便怎么来长期维护的架构图必须考虑版本管理和自动化那就直接走代码化。第三个问题是绘制这张图的频率高不高如果只是偶尔画一次用代码化工具的性价比反而低因为要额外学习语法如果是高频场景比如每次迭代都要更新架构图那代码化几乎是最优解。还有一点容易被忽略工具的生态和团队已有技术栈是否匹配。Mermaid 在 GitHub 生态里支持最广README 里直接嵌入就能渲染GitLab 也原生支持。PlantUML 在 Jenkins、Confluence 等老牌工具链里集成很成熟。Graphviz 则是命令行工具任何支持 Shell 的环境都能跑。选工具不只是选语法更是选它周边的生态。3. 实操搭建一套可落地的图表设计工作流3.1 第一步对图表做类型拆解和层级规划拿到一个系统要画架构图先别急着打开编辑器。你要做的是拆解这个系统需要几张图而不是一张图包打天下。一个复杂的业务系统至少应该分成四层来画。第一层是业务愿景图面向领导和跨团队沟通只需要画出核心业务模块和外部依赖一般不超过六个框。第二层是系统上下文图描述系统与用户、外部系统之间的关系用于交代边界。第三层是容器图把系统拆成应用、服务、数据库、消息队列等运行单元标出它们之间的通信方式。第四层是组件图深入到单个容器内部画出它由哪些组件构成、组件之间怎么协作。这个思路其实就是常说的 C4 ModelContext、Container、Component、Code我建议每个画架构图的人都去了解一下。它最核心的思想是没有一张图能穿透所有细节你必须为每个目标读者选择正确的抽象层级。如果你画的图连你自己都觉得“信息太多了”那大概率是把多个层级的细节强行塞到了一张画布里。所以在 diagram-design 的实践里我先规划图表清单再逐张绘制。某张图承载不了的信息宁可拆成两张、三张也不要硬塞。好的图表体系是一个图的集合而不是一个巨大的图。3.2 第二步确定命名规范、图层结构和风格体系当我们确定要画哪些图之后就要统一风格。这是保证一致性最有效的手段。命名规范是第一个要约定的事。我一般要求图里的模块命名用统一的格式名词 用途。比如“订单服务”“库存服务”“支付网关”而不是“svc1”“mod2”。图名、文件名也要规范推荐结构是序号-层级-主题比如01-context-order-system.d2这样在仓库里排序清晰团队成员看一眼文件名就知道这张图画的是什么层级、什么主题。颜色和形状也要提前约定。我通常会定义一个简单的语义规则外部系统用灰色核心服务用蓝色数据存储用绿色消息中间件用橙色。形状上圆角矩形表示服务圆柱表示数据库箭头在线表示同步调用虚线箭头表示异步消息。这套约定不是设计书上的漂亮理论而是实际工程里的必备品。不然一张图里每个人用一种颜色看着像没收官的幼儿园拼接画信息密度再高也白搭。图层结构是我强烈建议团队纳入规范的一项。无论是 Draw.io 的图层还是代码化工具里的分组与嵌套都应该把图分成“底层画布 业务图层 标注图层”。这样你调整布局时不会误碰标注添加注解时不会打乱主体结构。3.3 第三步从节点开始逐步构建完整图在具体画法上我分享一个我屡试不爽的顺序先画节点再连边最后调布局和加标注。以 Mermaid 画一个订单流程为例第一步是写清楚有哪些参与方和节点。我们可以先搭一个最简骨架graph LR A[用户] -- B[订单服务] B -- C[库存服务] B -- D[支付服务]Mermaid 的图可以直接放在支持它的仓库里渲染。上面这个例子就展示了最基本的节点和关系。但注意这只是骨架不是成品。第二步是在骨架之上补充分支和异常路径。流程图最难处理的就是异常分支我建议异常路径单独使用一种颜色或线型。比如支付失败的场景就需要用虚线或者红色连接到“补偿流程”节点。这样读者第一眼就能抓住主流程一旦出现异常分支也不会混淆。第三步是给每条关键边上补充标注。比如“调用”“回调”“订阅”“写库”这一类的动词标注要短、精确不要写一长串完整的句子。一个边上的文字超过十五个字基本就没人看了。我个人还有个偏方在一张图完成后把它缩小到原尺寸的 50%放到屏幕上离自己一米远。如果你仍然能理解这张图的大致关系和主路径说明它的结构是合格的。如果你缩小后什么都看不清那说明这张图承载的信息超出了正常可读范围必须拆分或者精简。3.4 第四步把图表纳入版本控制和自动化流程手动画图和代码化图表最大的分水岭就是有没有纳入版本控制。我强烈建议团队内的正式架构图、流程图都放在 Git 仓库里和代码放在一起像管理源码一样管理图源文件。这样做的好处是你可以查看图表的演进历史知道它是什么时候、因为什么原因被修改的甚至可以在 Code Review 里直接对图源文件提意见。在 Git 之外还要做自动化渲染。我在一个项目里的标准配置是在 CI 流水线里加一个步骤把.d2或.mmd文件编译成 SVG/PNG然后发布到内部文档站点。源码一旦有变更自动重新生成图片。这样会解决我前面说的维护失效问题——图永远跟随代码仓库的当前状态不会出现文档里挂着一张三个月前的旧图的情况。具体实现可以参考一个简单的 GitHub Actions 示例对于 D2 来说name: render-diagrams on: push: paths: - diagrams/** jobs: render: runs-on: ubuntu-latest steps: - uses: actions/checkoutv3 - run: curl -fsSL https://d2lang.com/install.sh | sh -s -- - run: for f in diagrams/*.d2; do d2 $f ${f%.d2}.svg; done - uses: actions/upload-artifactv3 with: name: diagrams path: diagrams/*.svg这段配置的核心是每当diagrams目录下的图源文件有变更自动用 D2 编译器重新渲染所有 SVG并把产物作为 Artifact 上传。这个工作流的本质就是“图源单一、产物自动更新”不依赖任何人手动导出图片。哪怕你的团队暂时用不上 CI本地至少也应该配置一个 Makefile 或者 npm script一条命令把目录下所有图源文件全部渲染出来。手动打开一个一个导出是在无限期延续你的加班。3.5 第五步图表纳入评审流程图是要评审的这不是形式主义。我可以直接说图比代码更容易失真因为画图的人往往对自己脑中的假设太熟悉画出来的图他自己看得懂但团队其他人看到的只是表面形状看不见背后的潜台词。所以我把“图表评审”加入了迭代流程与代码评审配套。评审时重点看三点图是否反映当前系统状态图是否覆盖了关键异常路径命名和风格是否遵守约定。评审的方式就是对图源文件发起 Merge Request在 PR 评论里交流。因为图源是文本评审者可以直接指出某一行写的某个节点关系有误修改成本极低。有同学可能会问手绘图不也能评审吗能但过程非常痛苦。手绘图的修改是重新拉动一整条线、重新排布几十个节点改一次费一个小时评审反馈根本推不动。代码化图则完全不同改一个字母、增删一行渲染后就是新图评审成本降了两个数量级。这也是为什么我坚持说“可维护性”是图表设计的核心维度而版本控制是把可维护性落到实处的唯一途径。4. 常见问题与排查技巧实录4.1 布局崩坏节点全挤成一团代码化绘图最常见的问题就是布局崩坏尤其是节点多、连线多的时候渲染出来的图会变成一团乱麻。Graphviz 通常还过得去Mermaid 在复杂场景下最容易出现这种问题。遇到这种问题我建议的顺序是这样的先检查是否“一张图塞了太多东西”如果节点数超过二十个、连接数超过三十条布局再好的引擎也很难保证清晰的体验。这时候你要做的不是调引擎而是拆图。把一张大图按边界拆成三张子图用一张“总览图”把三张子图的入口串起来结构立刻清晰。如果确定不需要拆图但依然布局不佳那就考虑手动约束。Graphviz 里可以用rank约束同一层级的节点可以在边上加len控制连线长度Mermaid 里可以用direction改变布局方向用子图subgraph把相关节点分组。这些布局参数是工具给你留的“微调开关”该用就用。还有一种很多人忽视的情况布局乱是因为节点之间“强关系”没有约束。一个节点应该和多个节点靠在一起但因为没有声明分组渲染引擎把它们打散了。解决方案就是聚合语义关系——把高内聚的节点放进同一个子图引擎会优先把子图内部的节点聚拢成一块布局瞬间清爽很多。4.2 信息过载图看不懂本质是取舍问题排查完布局第二个高频问题是信息过载。很多同学画图默认遵循“Everything in one diagram”的思路恨不得把所有的服务、表、配置、接口都画在一张图里画完之后自己也不记得从哪看起。这里有一个非常实用的原则一张图只表达一个核心主题。如果你想表达系统的部署结构就不要把业务时序细节也画在里面如果你想表达核心链路就不要把所有边缘调用关系全部塞上去。每多一条无关的线读者对核心路径的理解成本就增加一分。我还习惯在画完主体内容后问自己两个问题。第一个这张图能不能在一分钟内向一个完全不了解这个系统的新人讲清楚如果不能继续删。第二个这张图上有没有任何元素是“为了完整性”而放的而不是“为了帮助理解”而放的如果有删掉。图表不是论文的附图没必要追求完整覆盖理解效率是最高优先级。4.3 图表过时图和代码脱节的应对策略图过时是工程团队里最普遍、也最令人头疼的问题。我在很多团队里看到过这样的场景架构图上密密麻麻标着七八个模块但项目代码里早就改到认不出这个结构了。图成了“图个心理安慰”的摆设。要避免这个问题核心手段已经在前文说过代码化 版本控制 CI 渲染。只要图形文件在仓库里任何代码变更都可能影响图形评审者会在 PR 里看到图源变化就知道图需要更新。这样至少把图过时的“感知时延”从几个月压缩到了几天。但光有流程还不够还要在日常操作中做两件事。第一把“更新相关图”作为代码提交流程的一部分你在改代码时如果发现某个服务和图上的描述不一致顺手把图源改了别等“以后有空再改”。第二在 Code Review 模板里加一个勾选项“本次改动是否影响了现有图表如果是对应图源已更新。”一个模板勾选项比一百次口头强调都管用。4.4 工具锁死与迁移焦虑最后一个常见问题是工具选错之后的“迁移焦虑”。比如团队先用 Mermaid 画了大量文档图后来发现复杂架构图布局不够用想迁到 D2 或者 Graphviz。这确实是一笔成本但没有大家想的那么可怕。迁移成本对等关系与其自己写脚本解析 Mermaid 语法生成 D2 语法不如直接手动重画前提是你的图本身不多。如果图很多就需要一个结构化的中间表达把自己的模型抽象成 JSON 结构节点、边、分组、样式然后基于这个 JSON 分别写目标工具的导出器。这样既可以在未来继续迁移到新的工具还能拥有一份不依赖任何具体工具的独立图数据模型。我个人经验是一开始就定义自己的图表数据模型比把图和某一种工具深度绑定要稳得多。diagram-design 这个名字本身也给了我一个提醒——重点在“design”而不是某一个具体工具的语法。工具会演化、会流行也会过气但你对图的结构设计和信息表达能力的提升是长期复利。5. 图表设计是一项沉淀能力最后聊一点我在实践中的感受。画图这件事看起来门槛极低但真要画出让别人一看就懂、能长期维护、经得起评审的图是非常考验抽象能力和信息取舍能力的。diagram-design 这个项目让我养成了一个习惯拿到一个复杂系统先不动手写代码先画图把结构和关系理顺了代码设计质量也会跟着提升一个档次。如果你刚开始做图表设计不用迷信工具也不要追求一步到位。先从一张流程图开始用最顺手的工具画画完拿给同事看问他能不能三分钟讲清楚这张图的主流程。再根据反馈迭代你的命名规范、图层结构、颜色语义。当你的图稳定到“同事看完不需要再问你添加解释”这一水平这套工作流就真正成熟了。我也不会说“上面这套方案适用于所有团队”。如果你的团队规模很小、系统迭代不频繁用 Excalidraw 手绘就够了没必要上代码化那一套工程体系。但只要你所在的系统开始变得复杂、协作人数变多、图开始频繁变更我建议你尽早切换成代码化 版本控制 自动化渲染的路线。早切换早省钱图债也是技术债欠多了是必须还的。
返回列表