假设要给老家盖一栋三层小楼,你绝不会只对施工队说一句“要一栋漂亮的房子”就转身离开。你会先请设计师画一整套图纸:楼在院子哪个位置、和邻居隔多远、每层怎么隔间、水电怎么走、台风天会不会漏水。而且图纸绝不止一张——有总平面图、楼层平面图、房间详图、管线图,比例尺各不相同。软件的世界也一样。当系统复杂到三五个人说不清时,团队就需要一份“架构文档”:它不是一篇作文,而是一套图纸,记录系统整体的设计决策与组件关系。新成员靠它快速上手,评审靠它做判断,演进靠它不迷路。这篇文章,我们就用“盖房子的一套图纸”贯穿始终,把架构文档从价值、视图、写法到维护讲个透彻。

岗位关联

对 AI 从业者来说,架构文档是“会写代码”走向“能设计系统”的分水岭。把设计讲清楚、让团队少踩坑,是与模型能力同样硬核的职场软实力。

目录
  1. 可视化演示
  2. 蓝图为何重要——架构文档价值
  3. 一套图纸的分层——视图体系
  4. 区位图——上下文图
  5. 平面图——容器图
  6. 详图与管线——组件与部署
  7. 绘图规范——写作原则
  8. 极端天气预案——边界与异常
  9. 改造记录——演化与维护
  10. AI 应用场景
  11. Python 演示
  12. 常见误区
  13. 面试题

可视化演示

本节配有交互动效(进入视口后自动加载,约 3KB)。

C4模型——架构视图的四层缩放 L1上下文:系统边界与外部交互者 L2容器:应用与数据存储 L3组件:模块与内部结构 L4代码:类与函数细节 类比地图:国家→城市→建筑→室内

蓝图为何重要——架构文档价值

想象你要给老家盖一栋三层小楼。如果施工队没有图纸,全凭口头描述开工,会发生什么?墙砌歪了没人发现,二楼楼梯口正好撞上横梁,卫生间和卧室换了位置。等盖到一半,任何改动都要拆墙返工。软件系统比房子复杂成百上千倍——几十个服务、上百张表、多个团队——如果只有口头约定,每个人对“系统长什么样”都有自己的想象,协作很快就会变成互相甩锅的灾难。架构文档,就是那套让所有人停止争论、抬头看图的“设计蓝图”。

架构文档不是事后补写的工作总结,而是一份面向未来的技术资产。它记录的是一类特殊的知识:系统整体的设计决策(为什么选这个方案而不是那个)、组件之间的关系(谁依赖谁、谁调用谁)、以及设计时不得不接受的约束与权衡。有了这份文档,“我觉得应该……”式的讨论就会变成“按图来看应该是……”式的验证,沟通成本断崖式下降。

具体来说,一份合格的架构文档有四个价值主张。第一,记录设计决策:把每个关键选择的背景、候选方案和取舍写清楚,避免后人重复争论同一问题;第二,充当协作载体:前端、后端、测试、运维都以同一份文档为共识基线,跨团队对齐从“开十次会议”变成“看一遍图”;第三,加速新人上手:新成员先看全局再进入代码,把“听故事”的时间从几周压缩到几天;第四,支撑评审演进:架构评审、重构方案、容量规划都从文档出发,而不是依赖某位资深同事的个人记忆。

V文档=I可用+I一致C寻找+C理解\displaystyle V_{文档} = \frac{I_{可用} + I_{一致}}{C_{寻找} + C_{理解}}

1. V_文档:文档的团队价值,衡量这份文档对团队的真实贡献。数值越高,说明文档越“有用”。

V文档V_{文档}

2. I_可用:信息可用性。团队需要某个设计决策时能否在文档里找到——找不到,价值直接归零。

I可用I_{可用}

3. I_一致:信息一致性。文档描述的架构与真实运行的架构是否吻合,越吻合价值越高。

I一致I_{一致}

4. C_寻找:寻找成本。从打开文档库到定位到正确页面所花的时间,成本越高,价值越低。

C寻找C_{寻找}

5. C_理解:理解成本。读者看懂这张图需要多少认知努力——图越乱、术语越生僻,成本越高。

C理解C_{理解}

老话说“图纸省一斗,施工跑断腿”。蓝图的价值不在纸面,而在它让所有人的力气往一处使。没有图纸也能盖起房子,但那叫违章建筑;没有架构文档也能跑通系统,但那往往就是技术债的起点——今天欠下的“说不清”,明天要用无数次返工来还。

一套图纸的分层——视图体系

拿到一套建筑图纸,你会发现文件夹里不止一张图:楼在小区里的区位图、楼层平面图、房间布置详图、水电管线走向图。它们画的是同一栋楼,但比例尺和详略完全不同。为什么?因为看区位图的人关心“楼与周边的关系”,看平面图的人关心“房间怎么分”——把两种信息塞进一张图,反而谁都看不清。架构文档面对同样的问题,于是有了分层画图的思路。

软件行业最著名的分层标准,是 Simon Brown 提出的 C4 模型。C4 把架构文档拆成四个由外到内的层次:系统上下文(Context)、容器(Container)、组件(Component)、代码(Code)。每一层都是上一层的“放大镜”:先把整个系统画成一个方框,再放大看方框里有哪几个可独立部署的单元,再放大看每个单元内部有哪些模块。这样一层层“钻”进去,读者始终只面对自己关心的那一个抽象层级。

C4 的聪明之处在于强制规定了“每层画什么、不画什么”。上下文层只画外部世界,不画内部结构;容器层只画部署单元和它们的通信,不画内部类;组件层只画模块和接口。这个约束避免了新手最常见的错误——一张图把自己知道的全部细节都堆上去,最后谁也看不懂。很多团队画架构图“一图流”画到天昏地暗,正是因为缺少这种“层间纪律”。

C1→C2→C3→C4\displaystyle C_1 \rightarrow C_2 \rightarrow C_3 \rightarrow C_4

1. C1:Context,系统上下文层。整个系统画成一个方框,重点交代它与外部世界的关系。

C1C_1

2. 箭头 →:表示“放大”操作。每次进入下一层,就像拿着放大镜往图纸深处走一步。

→\rightarrow

3. C2:Container,容器层。系统被拆成可独立部署的运行单元,如 Web 应用、API 服务、数据库。

C2C_2

4. C3:Component,组件层。某个容器被拆开,展示内部的功能模块与调用关系。

C3C_3

5. C4:Code,代码层。对应类与方法级别的实现细节。实践中通常不单独画,交给代码注释和 IDE。

C4C_4

回到盖楼的比喻:总平面图告诉你楼在城市的哪个角落,平面图告诉你楼里怎么分区,详图告诉施工队每面墙怎么砌。四层图纸缺一不可,但绝不能互相替代。架构文档同理——层与层之间保持“抽象级差”,才是好图纸的核心秘密。

区位图——上下文图

盖楼之前,建筑师画的不是楼本身,而是“区位图”:楼打算建在院子的哪个位置,大门朝哪条路开,与邻居的墙要隔多少米。区位图上的“主角”其实是周围的邻居、道路和市政管线。架构文档的第一张图——上下文图,就是软件系统的“区位图”,只不过它画的不是街道,而是系统与外部世界的关系。

上下文图回答一个最关键的问题:这个系统的边界在哪里,它管什么、不管什么。整张图上,你的系统只画一个方框,放在正中央;四周画的是它需要打交道的外部角色——用户、上下游系统、第三方服务、甚至监管机构;角色与系统之间的箭头标注着交互动作,比如“发起支付”“发送短信”。这张图撑死了七八个方框,却决定了整套文档的格局。

别小看这张“最简单”的图。很多团队的架构文档第一张图就画错:把内部模块画进了上下文图,或者把数据库画成了外部系统。正确的做法是严格区分“系统之内”和“系统之外”——凡是你能改代码的部分,都属于系统内部;凡是只能通过接口协商的部分,都是外部角色。边界画得越清晰,后续的容器图、组件图才越有根基。

图上下文={S系统}∪{P角色}∪{E交互}\displaystyle 图_{上下文} = \{S_{系统}\} \cup \{P_{角色}\} \cup \{E_{交互}\}

1. 图_上下文:上下文图这个视图本身,它是整套蓝图的“目录页”,也是新人入职的第一站。

图上下文图_{上下文}

2. S_系统:系统本身。整张图上唯一的“大楼”,画在正中央,内部细节一律不画。

S系统S_{系统}

3. P_角色:外部角色集合,包括人(用户、运营)、系统(支付、短信)、组织(银行、监管)。

P角色P_{角色}

4. E_交互:交互关系集合,每条关系用一条带动词的连线表示,例如“用户发起下单”。

E交互E_{交互}

5. 并集 ∪:三个部分合在一起才构成完整的上下文图。缺了角色,边界就说不清——就像区位图缺了邻居和马路。

∪\cup

画区位图时,建筑师会研究周边道路的承载能力、邻居楼的采光权;画上下文图时,架构师要认真识别每一个外部依赖,包括那些“很少提起但每次事故都会出现的”重试组件、定时任务。边界画得越清楚,改天系统要接入新支付渠道时,大家才知道要动的是哪条“市政管线”。

平面图——容器图

区位图确认了楼的位置,接下来施工队需要的是楼层平面图:一楼是大堂和接待,二楼是办公区,三楼是机房,每层用隔断墙划分功能,楼梯和电梯连接上下。架构文档的第二张图——容器图,就是系统的“楼层平面图”:它把系统拆成一个个可独立部署、独立演进的单元,并画清楚它们之间如何连接。

这里先澄清一个概念:C4 里的“容器”不是 Docker 容器,而是一个更抽象的词——任何可以独立部署运行的软件单元,包括 Web 应用、后台服务、数据库、消息队列。它是架构师在讲“系统由哪几大块组成”时的自然粒度。比如一个电商系统,容器图通常画四个方框:前端 Web 应用、订单 API 服务、用户数据库、消息队列。容器之间有连线,线上标注通信方式。

一张合格的容器图,要为每个容器标注四类信息:职责——一句话说清它负责什么;技术选型——用什么框架和中间件;数据归属——它持有哪份数据,谁是“真相源”;通信协议——与其他容器之间是 HTTP、gRPC 还是异步消息。这四个信息,恰好回答了架构评审会上最常被追问的四个问题。把这四栏写清楚,容器图就成功了一大半。

容器i=(职责i, 技术i, 数据i, 协议i)\displaystyle 容器_i = (职责_i,\ 技术_i,\ 数据_i,\ 协议_i)

1. 容器_i:第 i 个容器。它是“可独立部署的单元”,可以是一个进程、一个应用或一个中间件实例。

容器i容器_i

2. 职责_i:这个容器在系统里负责什么,必须一句话说清。说不清就说明这个容器拆错了。

职责i职责_i

3. 技术_i:用什么技术实现,例如"React + Nginx""Spring Boot""MySQL 8"。

技术i技术_i

4. 数据_i:容器持有哪些数据,哪个是它的“真相源”。两个容器同时写同一份数据,往往是设计坏味道。

数据i数据_i

5. 协议_i:容器之间如何通信,HTTP/REST、gRPC、消息队列,必须标注在连线上。

协议i协议_i

楼层平面图上,施工队能看出厨房和卫生间不能相邻、承重墙不能随便敲;容器图上,团队能看出哪些服务必须分开部署、哪些数据不能共享、哪些链路不能引入同步调用。平面图决定了房子的骨架,容器图决定了系统的骨架——画错了,返工成本同样惨烈。

详图与管线——组件与部署

平面图定下房间布局后,施工队还要看更细的图纸:装修队需要“房间详图”,知道每面墙的插座位置、衣柜尺寸;水电工需要“管线图”,知道冷热水管和电线怎么走、总闸在哪。架构文档的第三、四张图——组件图和部署图,分别扮演这两个角色。

组件图把某个容器再放大一层,展示它内部的功能模块和模块之间的调用关系。比如把订单 API 容器拆开,会看到“接口网关”“订单业务”“数据访问”三个组件,以及它们之间的调用链。组件图的粒度恰好在“类之上、系统之下”,这是代码评审和模块划分最容易产生共识的层面。组件图画清楚了,开发团队拆分任务、定义接口时就有了一张“车间工序图”。

部署图则回答“软件跑在哪里”:哪些物理节点承载哪些容器、测试环境与生产环境的差异、网络分区分层、单点故障在哪。部署图画得好的团队,做容量规划时直接数节点就行;画得粗的团队,每次线上故障都要靠猜。部署图中最值得标注的是“可用性链路”——一个请求穿过的节点越多,整体可用性越低,这是分布式系统最反直觉的规律之一。

A系统=∏i=1nA节点i\displaystyle A_{系统} = \prod_{i=1}^{n} A_{节点_i}

1. A_系统:整个系统的可用性,即系统正常运行时间占总时间的比例。

A系统A_{系统}

2. ∏:连乘符号。一个请求要穿过多个节点,每个节点都必须存活,相当于水电管线上的每一个接头。

∏\prod

3. A_节点_i:第 i 个节点的可用性,生产环境通常标注 99.9% 这类 SLA 数值。

A节点iA_{节点_i}

4. i=1 到 n:从第一个节点乘到最后一个节点。n 越大,乘积越小——这就是“链路越长越脆弱”。

i=1…ni=1 \ldots n

5. 结论:想要整体可用性高,要么缩短链路,要么给关键节点做冗余(并联),这是部署图上最重要的设计点。

A系统≤min⁡(A节点i)A_{系统} \leq \min(A_{节点_i})

装修详图和水电图通常不会画进同一张图,因为服务不同工种。架构文档也一样:组件图给开发团队看,部署图给运维团队看,两者分开画、分开维护,才能在各自领域做到足够精细。把“谁负责什么”和“跑在哪台机器”混在一张图里,往往是架构图“看上去很花、实则无用”的根源。

绘图规范——写作原则

图纸画得再专业,如果图例不统一、比例尺混乱、标注潦草,施工队照样抓瞎。一套好图纸必然会约定统一的线型、符号和标注规则。架构文档也有它的“绘图规范”——这些规范看似是形式问题,实际上决定了文档到底有没有人愿意读。

第一条规范是“先问读者是谁”。文档的读者有新人、开发、运维、产品和评审委员会,背景和诉求完全不同。给新人的文档要先讲边界和整体,给运维的文档要突出节点和告警,给评审的文档要写清决策与权衡。第二条规范是“一张图一个主题”,不要试图在一张图里同时回答“系统长什么样”和“消息怎么流转”两个问题。每张图只讲一件事,讲透,然后收笔。

第三条规范与人类的认知能力有关。心理学家米勒发现,人的短期记忆大约能同时把握 7±2 个信息块,这就是著名的“7±2 法则”。放到架构图上,意味着每一张图的元素(方框加连线)尽量控制在 9 个以内;超过这个数,读者就需要来回比对,理解成本急剧上升。这也是 C4 分层存在的认知心理学依据——不是不想画细,是人的大脑不允许。

N元素≤7±2\displaystyle N_{元素} \le 7 \pm 2

1. N_元素:一张架构图中出现的独立节点数量,方框、圆角框都算一个元素。

N元素N_{元素}

2. ≤:表示“不要超过”这个上限。它是设计约束,不是事后修剪的参考值。

≤\le

3. 7±2:米勒定律——人类短期记忆大约能同时把握 5 到 9 个信息块。超过 9 个,理解成本陡增。

7±27 \pm 2

4. 含义:画图前先数一数节点数;超过 9 个,就拆成两张图,或把细节放到下一层视图。

N元素∈[5,9]N_{元素} \in [5, 9]

回到盖楼:老师傅画图用的线型、图标都是行业通用语言,换个施工队也看得懂。架构文档的规范,本质上是在建立团队的“通用语言”——术语统一、图例统一、层级统一。语言统一了,沟通成本才降得下来。

极端天气预案——边界与异常

图纸不只是为晴天画的。建筑师必须考虑台风天屋顶的承压、地震时承重结构的传力路径、水管爆裂时总阀门的位置。这些“极端天气”在图纸上往往只占几行批注,但真正决定房子能否在灾难中存活。架构文档同样不能只写“一切都好”的主流程,边界条件与异常处理才是实战里最见功力的部分。

一份工程化的架构文档,至少要在边界条件章节覆盖三类内容。第一类是质量属性约束:性能指标(如 P99 延迟不超过 200ms)、可用性目标(如 99.9%)、安全要求(传输加密、权限最小化)。第二类是失败模式:某个下游服务挂了怎么办、消息积压了怎么办、缓存穿透了怎么办,每个都要写清楚降级、重试、熔断的策略。第三类是合规要求:数据存储地域、日志保留期限、审计要求。

但边界条件千千万万,不可能全部写进文档。怎么取舍?用一个经典的风险公式排序:风险等于发生概率乘以影响程度。概率高、影响大的情况必须写进文档;概率低、影响小的情况可以只交给监控系统。把候选的边界条件按这个公式打分排序,文档就永远不会被无关紧要的细节淹没,而会把注意力留给真正要命的问题。

风险=P发生×I影响\displaystyle 风险 = P_{发生} \times I_{影响}

1. 风险:某个边界条件的风险评分,决定它在文档中的优先级。分数越高,越要显式标注。

风险风险

2. P_发生:发生的概率。例如“支付超时”几乎每天都会发生,概率接近 1。

P发生P_{发生}

3. I_影响:影响的程度。例如“订单主库宕机”影响所有交易,影响分给到最高档。

I影响I_{影响}

4. × 相乘:两者相乘得到优先级的排序依据。低概率高影响、高概率低影响,都要在文档里写清楚。

×\times

台风天预案做得深的房子,住起来才安心;异常处理写得细的系统,评审会上才让人放心。图纸上那些不起眼的批注,恰恰是建筑师经验最值钱的地方——架构文档里那些边界条件章节,也是资深架构师“踩过坑”才写得出来的部分。

改造记录——演化与维护

房子住上十年,总要改造:加个阳光房、把书房改成卧室、老化的水管换新。每改一次,图纸就要跟着更新一次。如果图纸不更新,下次装修时工人按旧图凿墙,很可能凿到已经移位的水管。架构文档最大的敌人不是“没写过”,而是“写过之后没人维护”。

现代团队普遍接受“文档即代码”的理念:架构文档与源代码放在同一套版本库里,和代码一起走评审、一起发布。每次架构调整都要“顺手”更新文档,文档与代码共同演进。更进一步,许多团队要求架构变更的 PR 必须附带对应文档的 diff,否则不能合并——用工程手段保证“文档不漂移”。

衡量文档是否跟得上系统,可以用“漂移率”这个指标:统计一段时间内代码变更的次数与文档更新的次数,算出“没被文档跟上的变更比例”。实践中,超过 20% 的漂移率就应该触发一次架构文档专项更新。定期做架构评审时,把漂移率作为评审输入,文档维护就从“靠自觉”变成了“有数据、有流程”。

漂移率=N代码变更−N文档更新N代码变更×100%\displaystyle 漂移率 = \frac{N_{代码变更} - N_{文档更新}}{N_{代码变更}} \times 100\%

1. 漂移率:文档与线上系统脱节的程度,是文档健康度的核心指标。

漂移率漂移率

2. N_代码变更:一个统计周期内代码合并或提交的次数,代表系统“实际变化”的量。

N代码变更N_{代码变更}

3. N_文档更新:同一周期内文档更新的次数,代表“记录变化”的量。

N文档更新N_{文档更新}

4. 减法:先算出“没被文档跟上的变更数”。如果文档更新次数超过代码变更次数,分子为负,表示文档超前。

N代码变更−N文档更新N_{代码变更} - N_{文档更新}

5. 除法与百分号:除以总变更数得到比例,再换算成百分比,便于设定阈值(比如 20% 报警)。

×100%\times 100\%

老房子有“房屋档案”,每一次改造、每一次维修都有记录,后人才知道哪面墙能动。架构文档就是软件系统的“房屋档案”。它不必完美,但必须真实、必须持续更新。十年后接手这套系统的人,会感谢你今天写下的每一行决策记录——就像你感谢当年为老房子画图纸的那位设计师。

AI 应用场景

新人入职智能导览

阶段:知识传递与工程化落地的辅助

解决的问题:传统方式下,新人要把架构文档、代码仓库、老同事的口头经验三块信息拼起来,至少两周才能上手。AI 把四层视图(上下文、容器、组件、部署)变成一条自适应学习路径,新人按图索骥、随问随答。

具体案例:某支付公司把架构文档接入企业知识库,新人小张入职第一天就能问“订单服务在哪个容器?”AI 基于容器图回答“订单业务在 order-api 容器,与支付容器通过 gRPC 通信”,并自动推荐下一步该看哪张图。上手时间从三周缩至三天。

架构一致性巡检

阶段:数据采集与分析

解决的问题:传统代码评审靠人肉发现“实现偏离架构”,效率低且滞后。AI 定期对比代码依赖图与容器图、组件图,自动生成架构漂移报告,并在评审会上标出“不该出现在这个模块”的依赖。

具体案例:某 SaaS 团队每月跑一次“架构漂移扫描”,AI 发现网关容器里被塞进了报表模块,自动在评审记录中标红提醒。团队提前三周发现了一次潜在的性能事故,事后把这次扫描纳入了 CI 流程。

架构知识问答机器人

阶段:推理与生成

解决的问题:架构师每天被大量重复问题淹没,比如“为什么这里用消息队列而不是同步调用?”这些问题的答案其实都在文档的决策记录里。用 RAG(检索增强生成)把架构文档变成问答机器人,既降低答疑成本,又让隐性知识显性化。

具体案例:某中台团队把架构文档和 ADR(架构决策记录)喂给企业级 AI 助手,新老成员随时问“订单状态为什么用事件驱动?”机器人引用容器图和决策记录作答,并附上原文链接。架构师每周省出约五小时的答疑时间。

Python 演示

python47 行
"""Architecture doc drift checker: compare code changes vs doc updates"""import osimport sys  def file_time(path):    """return last modified timestamp of a file"""    return os.path.getmtime(path)  def scan_code(code_dir, doc_path):    """return total file count and files changed after doc update"""    doc_time = file_time(doc_path)    total = 0    changed = []    for root, _, files in os.walk(code_dir):        for name in files:            if name.endswith(('.py', '.ts', '.java')):                total += 1                p = os.path.join(root, name)                if file_time(p) > doc_time:                    changed.append(p)    return total, changed  def drift_rate(total, changed_count):    """drift rate = unsynced files / total files"""    if total == 0:        return 0.0    return changed_count / total  if __name__ == '__main__':    code_dir = sys.argv[1] if len(sys.argv) > 1 else './src'    doc_path = sys.argv[2] if len(sys.argv) > 2 else './docs/architecture.md'    if not os.path.exists(doc_path):        print('architecture doc not found:', doc_path)        sys.exit(1)    total, changed = scan_code(code_dir, doc_path)    rate = drift_rate(total, len(changed))    print('code files:', total)    print('changed after doc update:', len(changed))    print('drift rate: {:.1%}'.format(rate))    if rate > 0.2:        print('warning: doc needs refresh!')    else:        print('ok: doc is healthy')
目的:这个脚本实现“漂移率检测”——扫描源码目录,找出所有比架构文档更新得晚的代码文件,据此判断文档是否已经与系统脱节。它是正文中“演化与维护”一节的落地工具。
  1. def scan_code(code_dir, doc_path):扫描的核心函数,遍历整个代码目录并对比修改时间
  2. doc_time = file_time(doc_path)以文档的最后修改时间作为“基准线”
  3. if name.endswith(('.py', '.ts', '.java')):只统计源码文件,跳过图片和依赖包
  4. if file_time(p) > doc_time:关键判断:代码比文档新,说明这段代码没有被文档覆盖
  5. rate = drift_rate(total, len(changed))计算漂移率,即未同步文件占比
  6. print('drift rate: {:.1%}'.format(rate))输出百分比格式的漂移率
  7. if rate > 0.2:超过 20% 阈值就触发告警,对应正文中的“两成漂移率该补图”

常见误区

误区我为了让文档显得专业,把数据库表、每个函数的参数都画进架构图,一张图塞了三十几个方框。结果没人看得懂,连我自己下次打开也要看半天。

正解架构文档的价值不是信息量,而是“恰当抽象”。C4 模型就是为这个问题设计的:每一层只画当前抽象级别的概貌,具体实现留给下一层甚至代码本身。一张图超过 9 个元素(7±2 法则)就应该考虑拆图。图纸不是地图,不需要 1:1 还原每一块砖。

为何常见:新手常把“详尽”当成“专业”,就像刚学画建筑图的人恨不得画出每一道砖缝,而老师傅知道图纸只画到“看得懂、盖得出来”就正好。

误区我把四张图一口气画完,觉得架构文档大功告成。之后半年再也没动过它,直到新同事照着旧图去排查故障,发现系统早就不长这样了。

正解架构文档是活物。代码每周在变,文档不跟着变,漂移率就会上升。它应该像“文档即代码”一样进入版本库、参与评审、随迭代更新。图纸必须跟着房子的每一次改造走,否则下次装修就会凿穿承重墙。

为何常见:写文档是一次性的“交付”,有完成感;维护文档是持续的“习惯”,没有仪式感,最容易被忽略。

误区我觉得架构文档把主流程画清楚就行了,支付超时、服务降级这些“意外情况”等出了事再说,写多了反而吓人。

正解边界条件恰恰是架构文档最该写的内容。质量属性(性能、安全、可用性)、失败模式(重试、熔断、降级)决定了系统在真实世界的生存能力。用风险公式(概率乘影响)筛一遍:凡是风险值高的边界情况,都必须写进文档。房子图纸不写台风天怎么办,施工队就按晴天标准盖。

为何常见:人脑天然偏好“快乐路径”,写文档时容易沉浸在主流程的顺畅感里,而异常处理枯燥且让人联想到事故,于是下意识回避。

误区我觉得架构文档就是给开发团队看的,运维、测试、产品经理看不懂也不用看,反正他们也不写代码。

正解架构文档的读者遍布全生命周期:运维要看部署图做容量规划,测试要看组件图设计用例,新产品经理要看上下文图理解边界,评审委员会要看决策记录做技术判断。只给程序员看的文档,相当于整栋楼只给施工队发了图纸,物业和消防都蒙在鼓里。

为何常见:写文档的人通常就是程序员,容易默认“读者等于同行”,忘了文档是团队的公共资产,而不是自己的技术笔记。

面试题

Q1. C4 模型的四层分别是什么?

单选题 · easy

  • A.上下文容器组件代码← 正确答案
  • B.并发容器组件编码
  • C.云计算网络资源池化
  • D.持续集成持续部署

答案:A。C4 是 Simon Brown 提出的分层模型,四个 C 代表 Context、Container、Component、Code。它就像建筑图纸的总图、平面图、详图、大样,每层一层放大镜。B 错在把 Container 记成“并发”,D 是 CI/CD 的缩写,C 是云计算术语,都与 C4 无关。

Q2. 上下文图的核心作用是什么?

单选题 · mid

  • A.画清系统与外部角色的交互边界← 正确答案
  • B.展示容器内部模块的依赖关系
  • C.描述服务器节点的物理分布情况
  • D.详细设计数据库表的字段结构

答案:A。上下文图只回答一个问题:系统与外部世界怎么相处,相当于盖楼前的区位图,全图只有一个系统方框。B 是容器图或组件图的内容,C 属于部署图,D 属于数据库设计文档,都不在上下文图的职责范围内。

Q3. 容器图应该包含哪些信息?

多选题 · mid

  • A.容器技术选型的标注← 正确答案
  • B.容器间的通信协议← 正确答案
  • C.容器内每个方法的实现
  • D.容器负责的职责边界← 正确答案

答案:ABD。容器图要为每个容器标注职责、技术选型、数据归属和通信协议,就像平面图上标注“这是厨房、用燃气灶、通上下水”。C 属于组件甚至代码层才关心的事,把方法实现塞进容器图会让图迅速超载,违反一图一主题原则。

Q4. 新成员入职后,最适合从哪张图开始看?

单选题 · easy

  • A.上下文图了解系统边界← 正确答案
  • B.部署图了解机器分布
  • C.组件图了解内部模块
  • D.代码注释了解实现细节

答案:A。新成员应该先读“区位图”——上下文图,知道这栋楼在哪条街、和什么相邻,再逐层走进平面图和详图。跳过上下文直接看代码,就像不看地图在陌生城市里乱逛,东看一块西看一块,形不成整体认知。

Q5. 关于“文档漂移率”下列说法正确的是?

单选题 · hard

  • A.漂移率越高文档越准确
  • B.漂移率与代码变更次数无关
  • C.漂移率越高文档越需更新← 正确答案
  • D.漂移率由测试覆盖率确定

答案:C。漂移率等于未同步的变更数除以总变更数,越高说明文档越脱离现实,越需要更新。B 恰恰说反了——漂移率正是由代码变更与文档更新的差额定义的。D 把文档健康度与测试覆盖率两个不同概念混为一谈。

Q6. 以下哪些属于架构文档中的边界条件?

多选题 · mid

  • A.质量属性与安全合规约束← 正确答案
  • B.高并发场景的失败降级← 正确答案
  • C.数据库中所有表的字段定义
  • D.系统异常时的重试与熔断← 正确答案

答案:ABD。边界条件包括质量属性(性能、安全、合规)、失败模式(降级、重试、熔断),就像房屋图纸要标“台风天门窗怎么关”。C 的表字段属于数据库设计文档的范畴,不是架构文档的重点,不应占用边界章节。

Q7. “7±2 法则”在架构文档中的应用是?

单选题 · easy

  • A.一张图元素不要超过九个← 正确答案
  • B.一个系统最多部署七个容器
  • C.一篇文档篇幅不要超过七页
  • D.一个团队规模最好不要超过七人

答案:A。米勒定律指出人类短期记忆大约能同时把握 7±2 个信息块,所以一张架构图尽量不超过 9 个元素。B、C、D 都是对这个法则的机械套用,把适用对象从“图里的元素数”错搬到了容器数、页数和团队人数上。

Q8. 可用性公式 A=∏Ai 说明什么?

单选题 · hard

  • A.节点越多整体可用性越低← 正确答案
  • B.节点越多整体可用性越高
  • C.可用性是所有节点的平均值
  • D.可用性只取决于最差的节点

答案:A。串联可用性要连乘而非取平均或取最差:两个 99.9% 的节点串联,整体约 99.8%。就像水管上任意一个接头漏水,整条供水就废了。D 是“最弱链路”直觉,虽然方向接近,但忽略了一串非最差节点同样会拉低整体。

Q9. 一份架构文档通常服务哪些读者?

多选题 · easy

  • A.新入职的研发工程师← 正确答案
  • B.运维部署团队工程师← 正确答案
  • C.参与评审的产品经理← 正确答案
  • D.只有架构师自己一个人

答案:ABC。架构文档的读者包括研发、运维、测试、产品和评审委员会。只给自己看的文档是“日记”,给团队看的文档才是“图纸”。D 违背了文档的协作本质——它回答的是“团队怎么对齐”,而不是“我怎么记住”。

Q10. “文档即代码”的核心思想是什么?

单选题 · extreme

  • A.文档与源码一起版本管理← 正确答案
  • B.文档必须由编译器自动生成
  • C.文档只能用英文编写维护
  • D.文档要写进每条代码注释

答案:A。“文档即代码”指把文档放进 Git,与代码一起走评审、版本化,让文档随系统改造同步更新。B 说得太绝对,文档仍以人写为主、AI 辅助生成;C 是语言风格问题,与思想无关;D 把思想窄化成了注释规范,失去了架构文档的全局视角。