图表的本质是沟通不是装饰。diagram-design这四年里我对这句话的理解越来越深。大多数开发者画图习惯打开画布拖拽几个方框、拉几条线觉得“画完就行”。但在实际的架构评审、技术方案评审、甚至给新人讲业务逻辑的场景里一张结构混乱、连线交叉、重点不清的图带来的沟通成本远远大于它的表达价值。我参与维护的一个内部项目名字就叫diagram-design。它不是一个具体的绘图软件而是一套围绕“如何用声明式文本快速产出高质量系统图表”的方法论与实践工具栈。你可以把它理解为用写代码的方式画图用工程化的思维管图。这篇文章我会把整套思路、常用工具选型、实操细节和踩过的坑完整梳理一遍希望能给正在做技术文档、系统设计、或者日常需要画架构图的朋友一些可复用的参考。1. 内容整体设计与思路拆解1.1 为什么我放弃了拖拽式绘图早年我也用那些所见即所得的绘图工具画系统架构图确实方便但维护起来是灾难。改一个节点的名称可能要手工调整三条连线的位置删掉一个模块整张图的布局可能都要重排。最痛苦的是多人协作场景每个人拖出来的图风格完全不同合到一起简直没法看。后来我把绘图场景做了一个分类发现大约只有两类需求真正需要使用拖拽式工具一类是极早期的灵感草图不需要规范就求一个快另一类是给外部交付的精美配图需要很强的视觉设计感。但这两类场景占我日常图表工作的比例其实不到两成。剩下八成多的需求是系统架构说明、数据流描述、模块关系梳理、接口调用链展示。这些图的共同特点是结构性强逻辑关系明确而且往往要随着代码迭代持续更新。我需要的不是一块无限画布而是一个能描述“节点是什么、节点之间什么关系”的声明式系统。diagram-design的核心思路就是把图表当作代码来管理。用文本定义节点和连线用统一的布局引擎自动计算位置用主题系统统一样式。这样一张图可以被review、被diff、被版本化管理就像管理一段代码一样。1.2 文本化图表的核心权衡文本化方案最大的好处是可追踪、可复用、可自动化。但代价也很明显布局控制力相对受限复杂图元的视觉表现力不如手绘。所以在选型时我给自己定了一条原则如果一张图需要我精确控制每个元素在画布上的像素位置那说明它本质上是一张视觉设计稿而不是一张架构图。架构图的价值在于传递关系不在于美感。基于这个原则diagram-design的技术栈选型很明确选择那些具备自动布局能力、语法简单、且支持程序化导出的文本图表工具。我在实际项目中主要使用D2作为主力语言辅助PlantUML处理部分UML时序场景。选D2而不是更流行的Mermaid有一部分原因是D2对复杂架构图的描述能力更强布局引擎处理嵌套和连接关系的效果更干净这个后面会详细拆解。1.3 一张好图的标准在展开细节之前我觉得有必要先定义清楚“好图”的标准。diagram-design项目的内部规范里我们对一张图只有四个要求结构清晰、信息完整、层级合理、风格统一。结构清晰指阅读顺序明确重要的依赖关系一眼能看出来信息完整指必要的角色、协议、数据流标签都在不缺失关键信息层级合理指通过容器、分组正确表达了系统的边界不能把不同抽象层级的东西混在一起风格统一指颜色、线型、节点形状的使用有语义规范而不是随心所欲。这些标准听起来不难但实际做起来非常考验使用者的抽象能力。这也是为什么我认为图表设计首先是设计问题其次才是工具问题。2. 核心细节解析与工具选型2.1 主流文本图表语言横向对比我画图这几年接触过的文本化图表工具不下五种。这里我把d核心的三种做一个系统性对比方便你根据自己场景做判断。D2的优势在于设计理念。它的语法被刻意设计成“所见即所得”的逻辑而不是“图灵完备”的编程语言。所有的连接、容器、样式描述都尽量贴近自然语言学习成本很低。渲染底层采用了比Mermaid更现代的实现默认主题的辨识度很高。Mermaid最大的优点是有GitHub原生渲染支持在Markdown生态里的集成度最高。如果你只是想在项目文档里画一个简单的流程图Mermaid的性价比极高。但它处理复杂嵌套结构的时候布局容易乱且生僻场景的定制能力弱于D2。PlantUML则是UML场景的老牌选手。它的时序图、用例图、活动图语法经过多年打磨非常成熟在Java技术栈的项目里应用广泛。缺点是图形风格相对“朴素”插到现代风格的技术文档里会显得有些突兀。我的个人使用建议是系统架构图优先D2嵌入式文档中的简单流程优先MermaidUML时序图优先PlantUML。当然这个结论比较主观适合自己团队的工具才是最好的。特性D2MermaidPlantUML语法简洁度极简简单中等自动布局质量高中中嵌套容器支持强一般强GitHub原生渲染部分支持支持不支持主题定制能力可编程定制有限有限动画/交互演示支持有限弱适用范围架构图、流程图文档内嵌图UML图为主2.2 为什么D2适合作为主力方案D2有一个至今让我印象深刻的特性就是你写注释的时候它会把注释变成节点文字的一部分自然排进布局里。这个设计大大减少了“文字旁注”的需求因为很多时候我们画图时被信息塞满就是因为没有地方写补充说明。D2的语法让描述性文字天然成为图表内容而不是事后添加的浮层。另外一个让我从Mermaid转向D2的关键点是它对复杂架构图的布局处理。早期Mermaid对复杂布局的抽搐问题很严重节点一多就乱成一团。D2的默认布局引擎要稳定得多尤其在处理双向连接、多层容器嵌套的时候几乎不需要人工干预。配合ELK布局引擎即使在非常复杂的网络拓扑场景下也能保持清晰的可读性。我还特别看重D2的原生命令行动画。日常评审的时候用一行命令把静态图变成逐步演进的动画示意图讲数据流的动态过程特别直观。我的经验是评审会上放一张静态图和放一段强调先后顺序的动画图听讲者的理解效率完全是两个档次。2.3 安装与环境配置D2的安装非常简单支持常见的包管理工具也可以直接下载编译好的二进制文件。我日常的开发环境覆盖macOS和Linux两类系统全流程如下在macOS下如果安装了Homebrew只需要一条命令brew install d2在Linux服务器上我习惯用官方提供的一键脚本安装curl -fsSL https://d2lang.com/install.sh | sh -s --Windows环境不建议使用WSL之外的方案因为D2的字体渲染依赖较底层的库原生Windows支持虽然存在但体验不如在WSL里使用顺畅。安装完成后记得补一个可选的辅助工具用于导出PDF和PPT格式brew install talaTALA是D2官方推荐的布局引擎之一跟默认引擎相比它在处理有向图布局时更擅长利用垂直空间。我的直观感受是涉及层次化架构图比如分层系统设计的时候TALA的布局结果比默认引擎更接近我们手绘架构图的习惯。2.4 语言基础从语法规范到设计约束D2的核心语法核心简单到令人难以置信。节点就是普通的文字连接用两个箭头表示容器用花括号包裹。下面这段代码是一段入门示例用户 - 认证服务: 发起登录请求 认证服务 - 用户数据库: 校验凭证 认证服务 - 用户: 返回令牌三行代码一张完整的调用时序图就出来了。这个语法设计有一个隐含的优势任何人都能看代码预判输出图的样子不需要在工具和画布之间来回切换预览。D2支持多种箭头类型和修饰符。实线表示同步调用虚线表示异步消息加粗箭头表示高优先级请求指针修饰符表示数据流方向。这些细节能力让它在描述系统交互场景时完全够用。而且D2原生支持自定义关键词修饰比如你可以给连接线打上一个标签描述协议类型是HTTP还是GRPC这样读图的人不需要额外去查文档。3. 实操过程与核心环节实现3.1 从空白文件到第一张架构图我现在用一个实际的微服务架构图解示例完整走一遍diagram-design的工作流。这个场景是我在给一个内部系统设计权限模块时画的图参考价值比较高。首先创建目录和文件mkdir diagram-design-tutorial cd diagram-design-tutorial touch auth-architecture.d2用文本编辑器打开这个文件先定义顶层容器。权限系统按逻辑边界拆成三个部分客户端层、网关层、服务层。D2里用花括号区分容器客户端层 { 管理后台 用户App } 网关层 { 接入网关 } 服务层 { 认证服务 权限服务 用户服务 }D2的渲染引擎会自动把同级的容器并列排布容器内的节点自动居中对齐。布局这一步完全不需要人工干预这也是我坚持用文本画图的主要原因。3.2 连接关系与数据流标注容器定义好之后开始加连接关系。这里有几个操作细节非常关键。容器之间的连接D2默认是从容器的边界出发指向目标容器的边界。如果你需要明确到具体的内部节点要去掉容器名直接用内部节点名。例如管理后台 - 接入网关: HTTPS {style.stroke-dash: 3} 用户App - 接入网关: HTTPS {style.stroke-dash: 3} 接入网关 - 认证服务: JWT校验 认证服务 - 用户服务: 读取用户信息 {style.stroke: green} 认证服务 - 权限服务: 校验权限 {style.stroke: blue}注意我在这里给连接线加了颜色属性。颜色在架构图里不是美化而是语义编码。绿色表示读操作蓝色表示校验操作。团队成员不需要看图例就能快速理解数据流的性质这就是用规范替代交流成本。3.3 布局调整与方向控制D2默认的布局方向是水平从左到右自顶向下。对于某些场景比如用户访问链路的描述垂直布局更合适从上到下描述请求的流转路径。你只需要在文件顶部加一行direction: down整张图就会切换成从上到下的布局。这个参数在D2的实现里是全局的它会影响所有容器内节点的排列方向但不影响节点之间的逻辑连接关系。如果你用ELK引擎还需要注意一点ELK天然偏向有向图布局在复杂图上的表现优于默认引擎但它不保证每个逻辑层级严格对齐。强制对齐这类需求用TALA引擎效果更好。3.4 样式定制与主题体系D2支持完整的CSS风格变量定制。但在项目实践里我不建议直接修改每个节点的颜色效率太低而且容易造成风格不一致。正确做法是定义一套统一的主题然后让所有图表自动继承。D2可以在文件级别的meta信息里配置主题vars: { d2-config: { theme-id: 200 } }200号主题是D2内置的“文档酷炫”风格字体和配色更适合展示场景。除了内置主题你还可以定义全局的CSS变量让所有节点的边框、阴影、圆角保持一致vars: { d2-config: { theme-id: 200 dark-theme-id: 201 } }对字体和配色要求比较高的团队建议维护一个统一的主题基础文件然后在每个图里通过import语句引入。这样整个知识库的图视觉风格天然统一。3.5 导出与集成D2的编译输出选项支持SVG、PNG、PDF等格式。日常我在本地预览时使用中间输出格式方便快速刷新d2 --watch auth-architecture.d2 /tmp/preview.svg--watch参数让D2监听文件变化每次保存自动重新渲染。这个模式在开发体验上非常好你调整完代码切到浏览器刷新一下就能看到最新的图。交付场景下我通常直接输出SVG文件嵌入文档。关键原因是SVG是矢量格式放大不模糊且在网页上可以天然交互比如点击节点跳转链接。AI生成的图表或者图片格式全部规避掉统一用SVG提交到代码仓库。4. 常见问题与排查技巧实录4.1 布局乱飞问题与ELK引擎适配用得久了难免遇到D2的默认布局引擎在复杂图上表现不佳的情况节点互相重叠、连接线缠绕。遇到过这种问题先不用急着改代码优先尝试切换布局引擎。D2支持在命令行指定d2 --layoutelk file.d2 out.svgELK引擎在层级关系复杂的架构图上表现明显更好。注意ELK引擎对箭头方向有一点敏感性如果输出方向不符合预期试着调一下direction参数有时能解决问题。还有一个排查思路是检查容器层级是否清晰如果所有的节点都在同一个层级没有合适的父子关系布局引擎很难自动判断结构主次节点排列自然就混乱了。4.2 样式继承无效背后的“就近原则”我在早期使用D2定制主题时踩过一个坑就是试图在容器上定义样式希望子节点继承结果子节点的样式没有变化。这个设计跟CSS的继承逻辑不同D2的样式生效采用就近原则子节点如果没有显式定义样式完全不会被父容器的样式影响。解决方案有两个一是利用D2内置的Vars与场景定义全局性的节点样式二是在子节点上逐一指定样式适合局部微调。理解了这个机制样式定制就不再困惑。4.3 中文字体渲染问题中文字体渲染问题是一个很容易被忽略的细节。D2的默认字体在某些Linux发行版上不包含中文字形渲染出来的图里中文全部变成方框乱码非常影响阅读。解决方法是显式指定一个包含中文字形的字体。可以在文件里设置vars: { d2-config: { font-regular: NotoSansSC } }也可以修改系统的fontconfig配置让D2优先使用Noto Sans CJK系列字体。如果你在macOS上开发本机的苹方字体一般能正常识别不需要额外设置。我个人的实践是高频率生成中文图表时把字体配置固化到主题里而不是每次单独指定。4.4 常见问题速查表这里我把日常使用过程中出现过的问题归类成一个速查表方便团队新人在遇到对应情况时快速定位。问题现象可能原因解决建议中文字符全部显示为框缺少中文字体配置在主题中指定全字体连接线相互交叉严重布局引擎不适应图结构切换ELK或TALA引擎样式定义失效子节点未显式继承样式使用就近原则显式定义导出PNG文字模糊部分预览器对PNG缩放不佳改用SVG格式节点文字被截断节点宽度未自适应调整节点尺寸或缩短文字原图渲染慢使用了过多嵌套容器拆分成多张子图4.5 命令行动画与评审提效最后分享一个让评审效率倍增的小技巧。D2支持把图表导出为动画序列配合命令行工具可以控制动画的播放节奏。这个功能从我第一次使用起就固定在了我的评审流程里。当前实现方式是D2原生支持在SVG中生成带有动画步长信息的规范输出再配合适当的工具链转换为视频或交互式SVG。实际操作中我会把一张包含数据流的架构图拆成多个动画步骤第一步只显示用户发起请求第二步显示网关转发第三步显示认证成功这样依次呈现。评审的时候大家跟着动画顺序走一遍流程理解速度远超对着静态图讲。这个技巧在给非技术同事讲系统逻辑时特别好用。5. 团队协作与知识库沉淀经验多人协作画图最大的挑战是图的可维护性。文本化是第一步解决方案D2的代码是普通的文本文件天然适配代码评审流程。我们在项目里做了两个额外约定保证了图库的长期可用。第一个约定是图表文件和源数据必须放同一个仓库图随代码变。每次涉及接口变更、模块重构必须同步更新对应的D2文件把这个作为代码评审的checklist项。否则过几个月再看图就变成过期的历史文件了。第二个约定是全部使用SVG格式输出嵌入文档。如果用图片格式提交diff阶段很难看清楚文件和文件之间改了什么。SVG配合代码仓库每次变更可以被精确审查。这两个约定执行之后图表的时效性和质量都有了质的提升。6. 写在最后的一点体会回到文章开头那个观点图表的本质是沟通不是装饰。diagram-design整个项目实践下来我最大的收获不是掌握了一个强大的工具而是建立了一套用文本精确描述复杂关系的思维方式。画图的过程变成了一种帮助我理清思路的手段而不是一个表达负担。如果你现在正在纠结选什么图表工具我的建议是从D2入手试一下。它的语法足够简单你不会花太多时间在学习成本上。而一旦你体验到“改图就像改代码”的流畅感大概率就不想回到拖拽式画图的方式了。最后补充一个建议不管使用哪种工具一定要为你的团队制定一份图表设计规约明确颜色语义、层级规范和样式主线。没有规约的图库最终都会变成无人愿意维护的垃圾场。
阅读完成 · 觉得有帮助?