在团队里待得久了,你会发现一个很有意思的现象:代码写得漂亮的人不少,但能把一张图设计得清晰、准确、让所有人一眼就看懂的人,非常少。我前几年主导过一个中台项目的技术评审,就栽在一张架构图上。那张图把所有模块、所有依赖、所有中间件全部画在了一起,节点超过四十个,连线密密麻麻,评审会开成了辩论会——三个人指着三条不同的连线理解出了三个完全不同的意思,最后架构没聊清楚,时间全花在"图到底想表达什么"上了。
那次之后我意识到,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 的终局不是画出漂亮的图,而是画出一张准确、新鲜、经得起追问的图,让每个看到它的人都能快速建立和原作者一致的心理模型。这比任何技巧都值钱。