技术方案的评审效率,往往不取决于你写了多少字,而取决于对方看到了什么。很多开发同学都有过类似经历:花了两天写完一份设计稿,逻辑、流程、接口定义都写得清清楚楚,结果评审会上大家还是对着同一段文字反复确认“这里是谁调用谁”“这条链路失败以后去哪里”。问题不在文字质量,而在信息呈现方式——文字是线性阅读,图是结构阅读,人在看方案时,图的处理速度远快于文字。
所以每次写稿件、写方案、写技术博客,我都有一个习惯:先确定三张最核心的大图,再围绕它们补充文字。这就是“3张大头”的意思——不是标题党,而是指一份技术交付物里最有价值的三个图形资产。
这篇稿子不讨论泛泛的“如何画图”,而是把问题收敛到具体的场景:一份技术方案、一篇技术博客、一次架构评审,最值得花精力打磨的三张图是哪三张,分别怎么画,用什么工具画,画完如何维护、如何嵌入文档、如何避免评审时被追问到说不清。读完之后,你可以直接拿自己手头一份旧方案练手,把它重构成“三张大图 + 精简文字”的结构,再对比一下评审体验。
1. 为什么方案评审总在“看不懂”上翻车
先还原一个非常常见的场景。
你打开一份设计文档,看到一大段文字:“用户请求先经过网关进行鉴权,鉴权通过后由订单服务处理,订单服务首先查询本地缓存,如果缓存未命中,则回源到数据库,同时将结果写回缓存,随后订单服务调用库存服务扣减库存,扣减成功后返回结果,如果库存不足则抛出异常……”这段话信息量很大,但绝大多数人读完一遍是记不住完整链路的,必须在脑中重新组织出一条分支图,才能判断逻辑是否正确。
问题出在认知负担上。文字是一种线性编码,阅读者必须逐行处理,再自己建立节点之间的连接关系。而图直接把节点和连接呈现出来,阅读者只需要做一件事:沿着箭头走。对于包含分支、依赖、多参与者协作的内容,图的信息密度和处理效率远超文字。
更隐蔽的问题是,评审时每个人的关注点不同。有的人关心边界划分,有的人关心异常分支,有的人关心调用依赖。一段纯文字很难同时满足所有视角。而一张架构图可以让人快速找到自己关心的模块,一张流程图可以让人快速验证主链路,一张时序图可以让人快速对齐交互顺序。不是文字没用,而是文字适合承载细节,图适合承载结构。
所以这里给一个明确判断:技术稿件的说服力峰值,出现在结构清晰的大图上,而不是出现在洋洋洒洒的章节里。与其花时间扩充文字,不如先把图打磨到能让一个不了解背景的人在三分钟内读懂。
| 对比维度 | 纯文字方案 | 三张大图 + 文字方案 |
|---|---|---|
| 阅读方式 | 线性,逐行理解 | 先整体后细节,可跳跃 |
| 空降评审理解成本 | 高,需要脑内重建结构 | 低,图就是共享心智模型 |
| 定位问题速度 | 慢,需要反复比对上下文 | 快,按图索骥 |
| 会后被追问概率 | 高,容易忽略分支和边界 | 明显降低 |
| 维护成本 | 低,改一次文字即可 | 略高,需要同时维护图源文件 |
2. “3张大头”到底是哪三张图:架构图、流程图、时序图
所谓三张大图,不是随便选三张好看的图,而是对应系统设计中最常被追问的三个问题:
- 系统由什么组成?边界在哪里?模块之间是什么关系?
- 一个业务目标是怎么被完成的?主链路是什么?有哪些分支和异常?
- 多个参与者之间如何协作?谁先发消息,谁等待谁,消息顺序是什么?
第一个问题用架构图回答,第二个问题用流程图回答,第三个问题用时序图回答。这三张图分别覆盖了“组成、流程、协作”三个视角,组合在一起,基本就能支撑一份技术方案的主体结构。
有些方案还会用到类图、ER图、部署图、状态图,但那是领域深入后的补充。在“先把方案讲清楚”的阶段,三张大图是最小必要集合。画好这三张,云评审时的“看不懂”问题就解决了一大半。
这里特别提醒一个误区:很多人会画“伪架构图”,就是网上常见的那种五颜六色、带渐变和卡通图标的示意图。这种图对PPT演示有用,但对技术评审价值很低。技术评审里被追问得最多的往往是边界、依赖方向、数据流向这三件事,如果图画得好看但说不清谁依赖谁,评审成员还是会把问题抛回给你。
| 图类型 | 回答的问题 | 核心要素 | 适合场景 |
|---|---|---|---|
| 架构图 | 系统由哪些模块组成,边界在哪 | 模块、依赖、层次、外部系统 | 方案概览、系统设计、团队对齐 |
| 流程图 | 一个任务按什么顺序执行 | 节点、分支、判断、结束 | 业务流程、请求链路、异常分支 |
| 时序图 | 多个对象之间如何交互 | 参与者、生命线、消息、返回 | 接口交互、异步消息、分布式事务 |
3. 工具选型:先想清楚图是否需要持续维护
画图工具很多,但如果要长期维护和进代码仓库,工具选型建议先回答一个问题:这幅图是一次性的,还是会在版本迭代中持续修改?
如果是一次性示意图,ProcessOn、draw.io、Excalidraw 这类图形化工具很合适,拖拽快,调整方便。但如果图会跟着代码一起变更,更推荐用文本化绘图工具,比如 PlantUML、Graphviz,或者 Mermaid。原因很简单:文本化图源可以进 Git 做 diff,可以参与 Code Review,可以写注释说明为什么这么连,不会被“谁改了图导致对不上”的问题困扰。
不过要注意一个现实问题:不是所有 Markdown 平台都原生渲染这些文本绘图语言。CSDN 编辑器在部分环境下支持 Mermaid,但为了在历史版本、各种浏览器和分享出去的文档里保持稳定,更稳妥的做法是先渲染成图片再嵌入正文。文本化图源负责维护,导出图片负责展示,两条路径分层处理。
具体版本号这里不写死,因为这类工具迭代很快,以各自官网最新版为准。文章后面所有示例用的都是 PlantUML 和 Graphviz 的通用语法,在任何已安装环境中都能运行。
工具选择建议如下:
| 场景 | 推荐工具 | 理由 |
|---|---|---|
| 快速梳理思路 | Excalidraw、draw.io | 拖拽快,适合草稿 |
| 正式方案图 | PlantUML、Graphviz | 文本化,可进Git,可注释 |
| 博客配图 | 文本绘图后导出SVG/PNG | 可维护,排版稳定 |
| 团队协作高频修改 | PlantUML + Git | 变更可追溯,可评审 |
4. 第一张大图:架构图怎么画才能经得起追问
架构图的本质是把系统的静态结构画清楚。它要回答的问题很朴素:系统里有哪几个部署单元,每个单元负责什么,谁依赖谁,数据流向哪里。
画架构图第一步不是打开工具,而是先确定边界。边界可以是逻辑边界,比如订单服务、用户服务、库存服务;也可以是物理边界,比如网关层、应用层、数据层。对于中小型项目,直接用逻辑边界分模块更直观;对于复杂分布式系统,建议从上往下分层:接入层、业务层、基础设施层、外部依赖层。
画的过程中最容易犯的错误是“什么都要放进来”。一张架构图只表达一个主题,如果业务模块、部署机器、中间件、外部对接全部堆在一张图里,很快会变成一团乱麻。更合理的做法是主架构图只画核心模块和依赖方向,细节用局部图展开。
下面用一个 Graphviz 示例说明如何表达模块依赖与层次关系。这里以 Spring Cloud 常见的“网关 → 服务 → 数据库”结构为例,重点演示图的语法结构,而不是绑定某个具体项目。
// 文件路径:docs/diagrams/architecture.dot digraph system { rankdir=TB; node [shape=box, style="rounded", fontname="Microsoft YaHei"]; subgraph cluster_client { label="客户端"; style=dashed; client [label="APP / 浏览器"]; } subgraph cluster_gateway { label="接入层"; gateway [label="API Gateway"]; } subgraph cluster_service { label="业务层"; order [label="Order Service"]; stock [label="Stock Service"]; user [label="User Service"]; } subgraph cluster_data { label="数据层"; db [label="MySQL"]; redis [label="Redis"]; mq [label="Message Queue"]; } client -> gateway [label="HTTPS"]; gateway -> order [label="路由"]; gateway -> user [label="路由"]; order -> stock [label="Dubbo/HTTP"]; order -> redis [label="缓存读写"]; order -> db [label="持久化"]; order -> mq [label="发送消息"]; stock -> db [label="库存扣减"]; }这段 dot 代码说明几个要点:subgraph cluster_xxx用于在图中画出分组边框,表达“层次”或者“域”的概念;rankdir=TB让图按从上到下的方向排列,符合用户阅读习惯;label写在边上,用于表达依赖类型。渲染时,架构图会按集群边界清晰分组,比把所有节点平铺在一行更有层次感。
Graphviz 渲染命令也很简单:
# 将 dot 源码导出为 SVG 文件 dot -Tsvg docs/diagrams/architecture.dot -o docs/diagrams/architecture.svg这里补充一个经验判断:架构图是否合格,可以拿三个问题来检验。第一,每个矩形是否都能用一句话说清“它负责什么”;第二,任意两个模块之间的箭头方向是否和代码里的依赖方向一致;第三,如果删掉某一个节点,图上的箭头是否还讲得通。三个问题都成立,这张架构图就经得起评审追问。
5. 第二张大图:业务流程图怎么画才不漏分支
流程图解决的是“任务怎么被完成”的问题。相比架构图的静态结构,流程图更关注事件的推进顺序:先做什么,再做什么,满足什么条件走哪条路,失败在哪里终止或重试。
画流程图的常见问题是不画异常分支。很多人的流程图只有主链路:用户下单、库存扣减、发送消息、返回成功。一旦评审问“库存扣减失败怎么办”“消息发送失败怎么办”“重复请求怎么处理”,图上一个节点都找不到,又要临时补一段文字来描述。这种流程图在评审会上没有太大意义。
更好的做法是画一张泳道图或活动图,明确区分不同参与方的职责,并把关键异常分支画出来。下面是 PlantUML 活动图的示例,模拟一个最简单的下单流程,重点在于展示if/else分支和repeat循环的表达方式。
@startuml start :用户发起下单请求; :网关鉴权; if (鉴权通过?) then (是) :创建订单; :调用库存服务扣减库存; if (库存充足?) then (是) :支付扣款; :发送消息通知; stop else (否) :标记库存不足; :返回失败原因; stop endif else (否) :返回未授权提示; stop endif @enduml这段代码对应的逻辑是:先判断鉴权,再判断库存,最后走支付与消息通知。PlantUML 的if (条件?) then (分支名)语法会把分支标签直接显示在判断节点上,阅读者可以快速找到每条分支的走向。
渲染命令同样很简单:
plantuml docs/diagrams/order-process.puml -tsvg画流程图的另一个建议是给每个判断节点加上“是/否”或具体条件标签,不要只画一个菱形却不说明判断依据。比如“库存充足?”比“库存状态”更容易被评审理解。分支条件是流程图的核心信息,省略掉就等于没有画分支。
此外,流程图要控制单图规模。一个完整业务流程可能有上百个节点,全部放在一张图里会丧失可读性。建议遵循“一张图只画一条主链路 + 关键分支”的原则,把复杂的子流程独立成另一张图,然后通过文字链接互相引用。这样做的好处是,每一张图都能在几分钟内被人看懂,而不是变成一张要缩放半天才能找到自己模块的蜘蛛网。
6. 第三张大图:时序图怎么画才能说清交互顺序
架构图画了模块和连线,流程图画了业务推进顺序,但分布式场景下还有一个更棘手的问题:多个模块之间的消息顺序到底是怎样的?谁先启动,谁等待谁,谁异步处理,失败后有没有补偿机制。回答这些问题需要时序图。
时序图的核心元素是参与者和生命线。每一位参与者在图中表现为一条垂直虚线,参与者之间的消息则用水平箭头表示。从上往下看,箭头的先后顺序就是时间顺序。这个模型非常适合表达接口调用链、异步消息、分布式事务里的协商过程。
下面用 PlantUML 时序图模拟一个分布式下单的交互过程。为了体现“接口调用 + 异步消息”两种交互模式,示例里加入了消息队列这一参与者。
@startuml actor 用户 participant "API Gateway" as gw participant "Order Service" as order participant "Stock Service" as stock participant "Message Queue" as mq participant "Notification Service" as notify 用户 -> gw: 提交订单 gw -> order: 转发下单请求 order -> order: 校验参数\n生成订单号 order -> stock: 预扣库存 alt 库存充足 stock --> order: 预扣成功 order -> mq: 发送下单完成消息 mq -> notify: 异步消费消息 notify --> 用户: 推送通知 else 库存不足 stock --> order: 预扣失败 order --> 用户: 返回库存不足 end @enduml这段代码展示了两个核心语法:->表示同步消息,-->表示返回消息,返回消息一般用虚线表达;alt/else/end用于表达交互中的条件分支。在实际方案里,存在多个分支时可以把所有分支画在一个alt块里,让评审成员一眼看出不同情况下的消息差异。
时序图的难点不是语法,而是对象粒度。太粗的时序图画成“用户 → 系统 → 数据库”只有三条线,漏掉了内部关键交互;太细的时序图把每个 getter、setter 都画出来,又失去表达力。一个合理的标准是:只画“会产生业务后果”的消息,比如状态变更、数据落库、消息发送、远程调用,不画编程细节。
画时序图前建议先做一件事:把一次请求从头到尾的完整事件顺序写在纸上,标出哪些事件是同步等待,哪些是异步触发,哪些失败后需要补偿。这个事件清单本身就是时序图的草稿。把事件序列理清楚后再画图,画出来的时序图不会出现“消息顺序和代码实际执行顺序不一致”的硬伤。
7. 把三张大图嵌入稿件和博客的规范做法
图画完之后,要把它们放入技术方案文档或 CSDN 博客时,这里有几个值得长期坚持的习惯。
第一,尽量导出 SVG 而不是仅用 PNG。SVG 是矢量图,在视网膜屏幕和各类浏览器下都能保持清晰,用户放大看细节也不会糊。PNG 在部分老旧编辑器里兼容性更好,但清晰度受限于导出时的分辨率。如果对清晰度要求高又不确定阅读设备,建议 SVG 和 PNG 各导出一份,文档里优先使用 SVG。
第二,图源文件和图片文件分开存放。一个推荐目录结构如下:
docs/ diagrams/ source/ architecture.dot order-process.puml order-interaction.puml images/ architecture.svg order-process.svg order-interaction.svg design/ order-design.mdsource 目录保存可编辑的文本源码,images 目录保存渲染后的图片。这样既能在文档中稳定引用图片,又能在后续修改时找到源头,不会出现“图片过期但改不动”的局面。
第三,在 Markdown 文档中引用图片时,路径要写成相对路径,并给图片加上有意义的文件名。比如:
<!-- 文件路径:docs/design/order-design.md --> ## 下单流程设计 整体架构如下图:  下单主链路如下:  核心交互顺序如下: 在 CSDN 发布博客时,图片会转存到平台图床。这里提醒一下:上传后建议检查图片是否正常显示,因为图床转存偶尔会出现样式丢失或链接过期的情况。如果博客里引用了多张图,建议一次上传完成后预览全文,确认图片顺序和文字描述一致。
还有一个经常被忽略的细节:图片命名。不要用1.png、2.png、未命名.png这种命名方式,建议用“文档主题 + 图类型 + 序号”的格式。比如order-architecture-01.svg、order-flow-02.svg。这样别人下载图片后也能从文件名判断图片内容,搜索引擎收录时也多了一份文字信息。
8. 常见问题与排查方法
写图和渲染图的过程中,有几类问题出现频率很高,整理成一张排查表,方便直接对照处理。
| 问题现象 | 可能原因 | 排查方式 | 解决方案 |
|---|---|---|---|
| 导出的图片中文字乱码 | 渲染环境缺少中文字体,或未指定字体 | 查看渲染日志,检查系统中文字体 | 统一指定 Microsoft YaHei / Noto Sans CJK 等中文字体 |
| 图片放大后模糊 | 只导出 PNG 且分辨率过低 | 查看图片实际像素 | 换用 SVG,或导出时提高 DPI |
| PlantUML 渲染慢 | 首次需要下载 jar 或依赖网络资源 | 查看执行时间,检查网络 | 使用本地 CLI 或提前缓存依赖 |
| Graphviz 布局混乱、连线交叉多 | 节点间没有合理分组或缺少约束 | 观察连线关系和节点数量 | 使用subgraph cluster分组,用rank控制层级 |
| 图源变更后文档图片未更新 | 只改了源文件没重新渲染 | 对比源文件和图片时间戳 | 把渲染命令写进脚本,或增加检查步骤 |
| 多人协作修改图源冲突 | 多个成员同时编辑同一份绘图文件 | 查看 Git 冲突文件 | 图源拆分为模块文件,或约定变更窗口 |
9. 最佳实践与工程建议
三张大图只是起点,真正决定长期价值的是围绕图建立起来的规范。下面几条经验是从多次评审实践中沉淀下来的,适用于技术方案、团队文档和 CSDN 博客三类场景。
第一,一张图只表达一个主题。架构图就讲组成与依赖,流程图就讲推进顺序,时序图就讲跨对象交互。既有“画面的能力”,还要有“不画什么的克制”。当一张图开始变得拥挤时,不是继续往里填内容,而是拆图。拆开的图可以用文字链接串联,读者需要宏观视角就看主图,需要细节就看局部图。
第二,图的变更要和代码变更一起评审。很多团队文档过期,是因为“写完就没人维护”。如果用的是文本化图源,可以把图渲染命令写进持续集成脚本,或者在 MR/PR 模板里增加一项“本次变更是否涉及架构图/流程图/时序图更新”。这项检查能在代码评审阶段就发现文档需要同步修改,避免图和代码分叉。
第三,评审方案时遵循“先看图后看字”的流程。技术评审的组织者,可以先花两分钟让所有人独立阅读三张大图,再进入提问和讨论环节。这样做的好处是让空降到项目的成员也能快速获得上下文。很多无效讨论都源于成员在脑内建立了不同的“图”,而用统一的大图对齐视点,能从源头上减少分歧。
第四,图的配色和风格尽量统一。不是为了好看,而是为了降低阅读成本。比如统一用虚线表示异步或返回消息,用实线表示同步调用,用不同颜色区分外部依赖和内部模块,用相同的字体和字号保证导出图片在文档中视觉一致。建议在团队内约定一套简单的绘图规范,写入 README。
第五,涉及安全或合规信息的图要特殊处理。架构图通常会暴露内网拓扑、服务名、端口关系、中间件版本。公开发布博客或外部分享时,要检查是否需要打码、替换服务名、去掉真实域名。内部文档和外部文档的图中内容可以不同,不要图省事直接把内部图脱敏后发出去,脱敏必须经过反复确认。
第六,画图工具本身不是重点,可维护性才是。与其用最炫酷的工具画一张只能看不能改的图,不如用大家都会的文本化方案画一张能持续维护的图。技术方案的价值在于它被一次次修改、应用、验证,而不是一次性展示完就定格。
10. 总结:用三张大图重构你的下一份方案
回到开头那个问题:为什么很多方案评审“看不懂”?因为文字只能线性描述结构,而技术方案往往是个网状结构。三张大图的价值,就是让你把网状信息转化为图形结构,给评审者一个统一的心智模型。
真正的交付标准应该是这样的:一个人没有参加过你的项目,但看完架构图能说出系统分了几层、核心服务有哪几个;看完流程图能说出主链路和两个关键异常分支;看完时序图能说出核心链路里哪一步是同步、哪一步是异步、失败后走什么分支。达到这个标准,你的方案就已经成功了一大半。
很难达到这个标准?具体建议是:把手头最近一篇旧方案翻出来,试着只保留三张大图,把文字压缩到图下方作为补充说明,然后发给一个不了解项目的人看,问他能否在三分钟内复述方案的核心结构。不能,就继续改图;能,说明你已经掌握了这套方法。技术写作如此,代码设计也是如此,真正高效的信息传递,永远是结构先于细节。所以,下一次写方案时,先把三张大图画出来。