
在团队里待得久了你会发现一个很有意思的现象代码写得漂亮的人不少但能把一张图设计得清晰、准确、让所有人一眼就看懂的人非常少。我前几年主导过一个中台项目的技术评审就栽在一张架构图上。那张图把所有模块、所有依赖、所有中间件全部画在了一起节点超过四十个连线密密麻麻评审会开成了辩论会——三个人指着三条不同的连线理解出了三个完全不同的意思最后架构没聊清楚时间全花在图到底想表达什么上了。那次之后我意识到diagram-design 这件事和写代码一样是需要刻意练习、有方法论支撑的专业技能而不是会画框和箭头就行。一张好的设计图本质上是把复杂系统压缩进人的短时记忆里它有一套从信息筛选、布局编排到视觉表达的完整工作流。这篇文章我想把我这几年的实战经验完整梳理一遍包括画图前怎么给信息分层、布局和连线有哪些工程化规范、主流工具链怎么选以及一个订单系统架构图从零到落地的完整过程。无论你是做架构设计、系统设计还是数据可视化这些方法都能直接套用。1. 为什么我把图表设计当成一项需要刻意练习的技能很多开发者对画图的认知停留在辅助沟通的草稿这个层面有个想法了拖几个框画几条线能看懂就完事了。但实际上当系统复杂到一定程度图就不再是辅助品而是团队成员之间达成共识的唯一媒介。这时候图的质量直接决定共识的质量。1.1 图表设计的三个层次看得清、看得懂、看得对我习惯把一张图的质量分成三个递进的层次这也是我自己评审图时的默认框架。第一层是看得清属于视觉层面。字体大小是否一致、线条是否对齐、配色是否有足够的对比度、有没有明显拥挤或者空旷的区域。这一层是基本功多数人停留在这一层觉得图画得挺好看就到位了——其实这只是及格线。第二层是看得懂属于逻辑层面。看图的读者在十秒之内能不能判断出这张图主要在讲什么它的主流程是自左向右还是自顶向下哪些节点是核心、哪些是辅助如果读者需要追着讲图的人问这条线是什么意思那这张图在逻辑上就是不成立的。第三层是看得对属于语义层面。图里的每个符号、每个连线是否和真实系统严格对应有没有为了视觉简洁而省略了不该省的依赖有没有把调用关系和数据流向混在一条线上表达这一层是最难的因为需要画图的人对系统边界有足够清晰的理解。很多图看起来漂亮但经不起追问一追问就发现画的人自己也没想清楚。1.2 一张烂图的成本一次评审会亲历的教训回到文章开头那次评审会。当时那张超过四十个节点的架构图问题不在于乱而在于它试图在一张图里回答所有问题既要展示服务拓扑又想标出数据流向还想体现部署环境甚至把未来的规划也用虚线画了上去。结果就是不同背景的读者各自挑了自己关心的那部分看然后基于完全不同的局部理解开始讨论。那次会议的实际成本五个核心成员两个小时产出为零。事后我把那张图拆成了五张分别讲拓扑、依赖、数据流、部署和演进规划再重新评审四十五分钟结束结论清晰。从那以后我给自己定了一个原则一张图只回答一个问题。这是 diagram-design 里性价比最高的一条规则。1.3 好图的标准不解释也能看懂如果你画完一张图还需要在旁边对着图讲上十分钟别人才能理解那基本上可以断定这张图是失败的。好的设计图应该具备一个特征——自解释性。怎么检验画完之后把它发给一个不熟悉该项目、但懂技术的人只给图不给任何口头说明看他能不能复述出八成以上的关键信息。如果做不到问题通常出在三个地方信息粒度不对、布局顺序混乱、或者连线表达含糊。后面几章我会逐个拆解这些问题的根因和修正方法。2. 动手画图前的信息分层先决定这张图不讲什么我见过太多人打开绘图工具就直接开始拖框这是最大的坏习惯。画图的第一步应该发生在绘图工具之外——你需要在纸面上或者文档里完成信息分层想清楚哪些信息进入这张图、哪些信息坚决不进入。2.1 单图单主题一张图只说清楚一件事单图单主题这句话听起来像废话但真正执行起来极其反人性。因为一个真实的系统本来就是复杂的当你脑子里装着一整套完整架构的时候让你砍掉任何一部分都会觉得这也很重要啊。我的做法是先写下这一张图的主题句一句话。比如本图展示订单创建请求从客户端到数据库的完整调用链或者本图展示订单服务的内部模块依赖与边界。主题句里必须有明确的动词和边界词比如调用链、依赖与边界。如果主题句超过三十个字说明这张图的范围太宽继续拆分。主题句写完之后把它贴在画布最上方当作标题。之后每往图里加一个元素就问自己它服务于这个主题句吗如果服务于放进来如果只是顺便相关拿出去放到另一张图里。2.2 四类信息元素节点、连线、标注、容器把复杂的真实系统映射到图上无非四种元素节点、连线、标注、容器。不要发明第五种不要创造复杂的花哨符号。节点表示系统里的实体比如服务、数据库、客户端。节点是图的名词。连线表示实体之间的关系比如调用、依赖、消息订阅。连线是图的动词。标注对节点或者连线的补充说明比如超时时间、协议类型、数据条数。标注是形容词。容器表示环境或者范围边界比如生产环境、网关层、领域层。容器是段落它把节点组织成可读的组块。我见过很多混乱的图本质问题就是角色扮演混乱有人用颜色深浅表达依赖关系有人用节点大小表达流量高低还有人用虚线表达时序先后。这等于在用第四种、第五种语义通道表达信息而读者的视觉系统根本来不及解码那么多规则。严格把语义绑定到这四种元素上图的解读成本就会直线下降。2.3 从需求到草图一页纸的信息架构清单实际操作里我会用一个固定清单来整理一张图的信息素材。清单分四栏主题句、必须出现的实体、必须出现的关系、坚决不出现的内容。举个例子假设我要画一张订单服务的内部模块依赖图。清单可能长这样主题句展示订单服务内部模块划分以及模块间的直接依赖。必须出现的实体接口层、应用层、领域层、基础层下的主要模块比如订单聚合、支付网关适配、库存接口。必须出现的关系模块间的方法调用依赖基础层被哪些模块依赖。坚决不出现的内容数据库表结构、外部系统的内部细节、Kafka 消息的具体 topic 划分、每个接口的超时配置。这一步做完之后画布上放什么已经确定了八成。剩下的工作是在画布上把素材排成一个人类视觉系统容易消化的结构也就是下一章要讲的布局与视觉语言。3. 布局、连线与视觉语言的工程化规范信息素材备好之后真正考验手上功夫的是布局和视觉表达。这一部分我积累了一套可以量化的规范包括布局方向、连线约束、色彩与字体规则等下面逐条说明。3.1 布局方向与阅读顺序的强约定人的阅读习惯是从左上角开始沿着某个方向扫视。图表设计必须顺应这个习惯建立一个清晰的主阅读路径。常见的两种路径是自顶向下适合展示分层架构比如网关层、应用层、数据层和自左向右适合展示流水线或者调用链比如客户端请求一路流向数据库。相比之下自中心向外扩散的布局只适合展示关系图谱比如微服务治理图但这类图天然不适合传达顺序和依赖层级所以在系统设计图里我很少用。布局上有一个非常实用的原则主路径走直线辅助关系走曲线。也就是说核心的调用链或者依赖路径尽量让它在水平和垂直方向上对齐读者沿着这条路径一眼扫过去就能读完主流程而次要的、辅助的关系比如某个模块配置了缓存、某个服务连接了配置中心这些连线即使走向复杂一点也可以接受——因为它们本来就不是读者第一时间要关注的内容。3.2 连线交叉最少化与一步依赖原则连线的质量直接影响一张图的可读性。我给自己定了几条硬规则。第一两两连线之间尽量不交叉。如果交叉不可避免宁可在图上留出让连线绕行的空白也不要让三四条线挤在一个点上。现实中我见过太多图节点排得整整齐齐结果连线连成了蜘蛛网重点全毁了。第二连线上尽量只表达一种关系。一张图里如果既有调用关系又有数据流向千万不要混在同一根线上。要么分成两根线并分别标注要么干脆只保留主要的那一种。最忌讳的是画一根带箭头的线既标HTTP调用又标数据返回读者根本搞不清方向的主次。第三减少中间跳转。如果 A 调用 B、B 调用 C而 A 也要调用 C那么图上应该直接画 A→C还是让读者自己沿着 A→B→C 绕一圈推出来我的建议是只有在你确定这种隐式依赖是读者不需要都知道的情况下才省略否则不要省。省略隐式依赖是看得对这一关最常见的翻车点——架构师看了图以为 A 和 C 没有直接耦合实际上调用链里有隐藏的 direct call后期排查问题的时候会被图误导。3.3 色彩、线宽与字体的克制使用很多设计图丑不是因为缺元素而是因为元素太多各自为政。色彩上我推荐 3-5 个颜色上限并且每个颜色绑定一个语义。红色表示异常或者重点关注路径绿色表示正常或标准路径灰色表示不重要的辅助组件蓝色表示核心业务组件。一定不要因为好看给每个模块配一个不同颜色那是灾难。线宽用来表达关系强度或者流量重要性。主路径连线用 2px 或更粗次要连线用 1px标注性的虚线一律 1px 以下。字体遵循全图不超过两种字号的原则标题和节点名称一个字号标注和注释一个字号且都用无衬线字体。这里分享一个很实用的小技巧给容器比如分层边界框加一个非常浅的底色能显著提升读者对分组区域的感知尤其是节点密集的时候。我常用的做法是底色用对应语义色的 5% 透明度既不影响内部节点文字的可读性又能清晰划分区域。3.4 标注重载写进图内还是放进说明标注是最容易失控的元素。一个常见的场景模块下面写了一长串文字从接口协议到超时时间到负责人都补了上去导致节点被撑得巨大无比图面失去平衡。我的原则是图上只标注那些不标就误解、不标就漏信息的内容。比如连线协议是 HTTP 还是消息队列这个要标某个流程分支的条件表达式这个也要标。但像超时重试三次这种细节放到图下方的说明区用编号一一对应不要塞进图里。具体实现上我习惯给每个节点和连线编号在图下方或者图右侧放一个图例 说明区域用文字补充编号对应的细节。这样图本身保持清爽信息却不丢。很多人觉得这样多此一举实际在团队评审时测试过带编号说明的图比全图塞满文字的图理解速度快近一倍。4. 工具链选型代码派、拖拽派和手绘派的取舍我最早画图用的是 Visio中间试过无数工具现在的工作流是代码生成 拖拽白板 手绘速写三个流派并行。工具没有绝对的好坏关键是匹配场景。下面说说我对主流方案的实测感受和选型逻辑。4.1 代码生成方案Mermaid 与 PlantUML 的实测感受代码生成类工具的最大优势是图即文本天然适合版本管理。同一张图的每一次修改都能在 Git 提交记录里清晰回放这个特性对长期维护的项目来说价值巨大。Mermaid 的语法很轻学习成本极低十分钟能上手。它的流程图和时序图用来表达调用链效果很好——自动排版虽然时不时有点呆但胜在稳定。我在快速记录设计思路、给代码仓库写 ARCHITECTURE.md 时会优先用 Mermaid。PlantUML 则更像一门完整的画图语言表达能力比 Mermaid 强不少特别是在时序图和部署图里可以定义很细的参与者、激活条、嵌套消息等。代价是语法更重团队里总有成员对它的语法望而生畏。我的建议是如果团队里所有人都有意愿学习和维护PlantUML 更合适如果只是少数人画、多数人看Mermaid 就够了。这两个方案都有一个共同短板布局自动化程度不够高复杂图容易排版很丑而且手工调整空间几乎为零。只适合表达结构化较强、节点数少于二十个的图。4.2 拖拽白板方案draw.io 与 Excalidraw 的实测感受当节点超过二十个或者需要精细控制布局的时候我会切换到拖拽类工具。draw.io 算是这类工具的常青树免费、全平台、本地文件优先、和 GitHub 集成天然——我团队里很多人用 VS Code 插件直接编辑 .drawio 文件某种程度上也算半文本化。draw.io 的图层、容器、精确对齐、吸附这些功能非常扎实适合生产严肃的架构图。但它的默认样式比较工具感需要花一点时间调样式才能好看。Excalidraw 是我近两年最惊喜的发现。它的手绘风格一开始让我觉得不够专业但实际用过之后发现这种手绘质感在早期设计沟通过程中反而有巨大优势——它天然传递一种这是草稿请随意质疑的心理暗示会让评审者更愿意提意见。相比之下一张精致得像艺术作品的图反而会让人不敢挑错。所以我的分工是早期头脑风暴和接口方案探讨用 Excalidraw正式输出的架构图用 draw.io 精修。4.3 我的推荐组合与场景矩阵下面这个表是我现在在团队里推的工具选型标准直接抄作业就能用。使用场景推荐工具核心理由快速记录想法、速写草图Excalidraw门槛极低手绘风格降低沟通防御性正式架构图、部署图、精修交付draw.io布局精确支持图层和容器易配合版本管理仓库文档内嵌图、变更追踪Mermaid文本化能随代码 diff 一起 review复杂时序图、协议交互图PlantUML语法表现力强足以描述复杂交互细节白板实时协作、远程会议思维导图FigJam / 白板工具多人实时协作体验强适合研讨会选型时还有一个容易忽略的点导出格式。尽量选能导出 SVG 的。SVG 是矢量图放大不糊而且能被工具再次编辑。导出了 PNG 发给别人对方想改只能全部重画而给 SVG 文件对方能直接在线编辑协作效率天差地别。5. 实战案例从零设计一张订单系统的核心架构图理论说了不少下面用一个真实的例子完整走一遍流程。假设我需要设计一张订单服务内部模块依赖图面向的读者是刚加入团队的新人目标是让他们十分钟之内理解订单服务的模块划分和互相依赖。5.1 原始需求与信息分层过程按照第二章的流程第一步不是画图而是先用文字完成信息分层。我写下的主题句是展示订单服务内部按层划分的模块以及模块之间的直接依赖。然后整理信息素材。必须出现的实体包括接口层Consumer/Controller、应用层OrderAppService、PaymentAppService、领域层OrderAggregate、PaymentDomainService、InventoryClient、基础层OrderRepository、PaymentRepository、OutboxPublisher。必须出现的关系包括接口层调用应用层应用层调用领域层领域层通过基础层访问数据库、发布消息。坚决不出现的包括数据库表结构、外部系统的内部实现、各种中间件的部署细节。这个步骤花了大约十五分钟但省下的是后面至少一个小时的返工。5.2 布局编排与层次落地确定布局方向。这是一张分层依赖图我选择自顶向下的布局接口层在最上方应用层在其下领域层再下基础层垫底。读者从顶部开始按自然阅读方向一路读下去四层关系一目了然。接下来用容器画出三个虚线框分别标注接口层、应用层、领域层基础层因为是公共支撑我用一个浅蓝底色的横条放在最下方表示它对上层提供通用能力。节点排放上我遵循同层节点水平对齐、垂直方向留白均匀的原则。理想情况下核心路径上的节点放在同一条垂直中心线上比如 OrderController → OrderAppService → OrderAggregate → OrderRepository这四个节点我用一条主路径直线连下来读者一眼就能看到订单创建请求的主干。链接线上主路径用 2px 黑色箭头线辅助路径比如应用层调用 PaymentAppService 以及它对 PaymentDomainService 的调用用 1px 灰色线不与主路径交叉。为了避免交叉我把 Payment 相关模块放在 Order 主路径的右侧把 Outbox 消息发布放在左侧两翼互不干扰。每一根线上都标注了关系类型。主路径标注创建订单或者聚合操作辅助线上标注支付校验、发布 Outbox 事件等。这个过程里我特意检查了一件事隐式依赖有没有缺失。比如 InventoryClient 虽然在领域层内部被 OrderAggregate 调用但库存扣减的失败会反向影响订单状态——这条反向影响线我加在图上用虚线标注失败触发状态回滚避免新人误以为它们是单向调用的纯粹关系。5.3 成图后的自检清单画完不代表完工我有一套自检清单每张图发布前都会过一遍主题句是否在图上最显眼的位置读者第一眼看到的文字必须是这张图在讲什么的标题。有没有任何孤立节点一个节点如果没有任何连线说明它是放错图的元素或者信息没有整理干净。连线交叉点是不是控制在最小数量我要求主路径连线零交叉辅助连线交叉不超过两处。图例和语义是否完整颜色、线型、线宽、容器每一类视觉通道都要在图例里说明。有没有省略这个读者必须知道的依赖这一步我会把图拿给一个没参与设计的人看让他指出任何疑惑点再针对性修改。这套例子里的图初稿用了四十分钟自检又花了二十分钟但之后几乎没有收到过这图看不懂的反馈。这个时间投入远比评审会上扯皮两小时值。6. 让图活得久一点版本管理、更新节奏与团队协作孤立的、一次性画完就丢的图没有长期价值。真正有生产力的图是活文档它和代码一起演进。最后一章聊聊怎么让图在团队里活起来。6.1 图也是代码基于文本格式的版本控制这一点我强烈建议团队尽早落地。尽量使用文本化格式的绘图文件——Mermaid 的 .mmd、PlantUML 的 .puml、draw.io 的 .drawio 底层也是 XML这些都是可以直接进 Git 的。把图放在和代码同一个仓库和代码一起提交review 代码的时候顺带 review 对应改动的图。如果团队用的是纯拖拽工具且没有文本化格式至少要做到按版本号或者日期归档不要直接在原图上改完覆盖。我在很多团队见过同一个文件十几个备份的情况架构图_v1、架构图_v1_final、架构图_v2_真最终……这种命名方式本身就是在制造混乱。6.2 更新触发点什么时候必须改图很多图最后失效不是因为画得不好而是因为没人维护。我建议把图的更新纳入开发流程的定义完成标准里。具体的触发点是模块的接口发生变化新增、删除或者改名模块间的依赖关系发生变化新增依赖、移除依赖、改变调用方式部署架构发生变化环境拆分、中间件替换数据流方向发生变化异步改同步、消息队列改 RPC。在这些变更发生时把同步更新架构图当成和补测试一样严肃的任务。如果嫌维护成本高可以给每张图加上次验证时间和负责人两个元字段至少让读者知道这张图有多新鲜。6.3 团队评审中如何读图与听图最后分享一个团队协作里的实操技巧评审会读图时不要从第一行开始逐字读而是按先主干后枝叶的顺序读。先找主路径——通常是图上最粗的那条线复述它表达的主流程再找容器——看哪些模块是被同一个灰色/边框圈在一起的这部分代表分层边界最后再看辅助连线和标注这些往往是评审最有价值、最容易引起问题的细节。评审提问也有技巧。作为画图人我会主动问三个问题这张图缺什么哪些关系是画错了的哪些连线让停下思考超过三秒第一个问题暴露信息完整性第二个问题暴露语义准确性第三个问题暴露布局和视觉表达的问题。每个问题都能在对应层次上推进图的质量。说白了diagram-design 的终局不是画出漂亮的图而是画出一张准确、新鲜、经得起追问的图让每个看到它的人都能快速建立和原作者一致的心理模型。这比任何技巧都值钱。