《互联网产品的客户端架构·规模化与架构演进》前言

卷四前言:说明四卷分工与本卷的位置,交代每章「现场—模型—代码—判据」的四段写法、evolve-lab 的模块地图与三级验证命令、代码与命名约定、章与章之间的依赖、每章应留下的产出物清单,以及如何在团队中把书里的判断落地;并附三个动手练习、自检清单与勘误渠道。

这是一本判据书,不是教程

读者拿起架构书,通常期待两种东西:一套可以照抄的目录结构,或者一组可以套用的设计模式。卷四两种都不给。

它给的是判据:在什么条件下应该共享,在什么条件下必须分开;什么差异可以保留,什么差异必须消除;什么时候该迁移,什么时候该停下。判据的特点是它不替你决定,但它让决定可被讨论、可被复核。

这也决定了阅读方式。教程可以跳读代码,判据书必须读反例。每一章末尾的「常见错误与边界」比正文更重要,因为判据的价值往往体现在它排除的那些选项上。

四卷的位置

《互联网产品的客户端架构》四卷,各 45 篇,按承诺强度由内向外展开:

卷主题核心承诺失败代价
卷一端形态与体验基础结构稳定一个版本可修
卷二内容、社交与实时互动消息可达用户可感知,大多可恢复
卷三交易、增长与平台化事实唯一资金损失,需人工介入
卷四规模化与架构演进长期一致慢性成本,逐月累积

前三卷回答「怎么把一件事做对」,卷四回答「怎么让五件事长期都做对」。它不重复前三卷的基础,而是把前三卷的方法放进多端、多团队、多版本的约束里重新检验。

如果前三卷是造一辆车,卷四是如何让五个工厂造出同一款车,并且随时能换发动机。

每章的四段写法

十三章结构一致,每章三节,每节按四段展开:

第一段:现场。 一个具体的多端问题,通常带数字与症状。例如「五个端的提交订单按钮有三种防抖策略」,或者「同一笔退款在 Web 显示已到账、在 iOS 显示处理中」。现场的作用是让抽象判断有落点。

第二段:模型。 把现场拆成可计算的结构:矩阵、层级、状态机、预算、清单。模型要能回答「这一格为什么是这个值」,而不只是给出一张好看的图。

第三段:代码。 用 evolve-lab 里可运行的 TypeScript 模块把模型固化。代码不大,通常几十到一百多行,但覆盖边界条件:未知输入、缺失能力、循环依赖、越界预算。

第四段:判据。 给出采用与放弃的条件、验收方式与反例。判据部分不写「最佳实践」,因为最佳实践依赖上下文;它写「如果……那么……否则……」。

三节之间也有节奏:第一节定义问题与模型,第二节落到工程实现,第三节讨论治理与退出条件。时间紧的读者可以只读第一、三节,但会错过实现中的坑。

evolve-lab 的模块地图

实验工程与前三卷同构,按章分目录,全部使用 Node 26 原生类型剥离,零第三方依赖:

evolve-lab/
  src/platform/        # 端矩阵、共享内核、能力探测(第 1 章)
  src/design/          # token、组件契约、主题(第 2 章)
  src/plugin/          # 插件协议、沙箱、热更新(第 3 章)
  src/perf/            # 预算、归因、回归(第 4 章)
  src/stability/       # 故障域、降级、演练(第 5 章)
  src/build/           # 依赖图、产物、流水线(第 6 章)
  src/observability/   # 日志指标追踪、采样、告警(第 7 章)
  src/security/        # 数据分级、SDK、隐私(第 8 章)
  src/i18n/            # 格式化、RTL、区域能力(第 9 章)
  src/a11y/            # 语义、偏好、审计(第 10 章)
  src/governance/      # ADR、所有权、技术债(第 11 章)
  src/migration/       # 绞杀者、双写、退出(第 12 章)
  src/summary/         # 多端端到端、平台矩阵、收官(第 13 章)
  test/                # 与 src 同构的测试目录

模块之间刻意保持低耦合:每一章只依赖 node: 内置模块与同章文件,不跨章引用。这样读者可以单独抽出某一章运行,而不需要先跑通整本书。

唯一的例外是第 13 章,它会引用前十二章的数据结构,作为收口验收。

三级可运行性怎么自测

每节代码块的第一行标注级别:

  • L1:纯函数与纯判断,无 I/O。直接 node --test。
  • L2:进程内模拟,使用注入的时钟与内存实现。同样 node --test,但通常需要固定并发。
  • L3:本地真实依赖,如真实文件系统、真实 HTTP 服务。需要先启动依赖。

自测命令如下(在 evolve-lab 目录内):

node --test test/platform/*.test.ts
node --test test/design/*.test.ts
node --test test/plugin/*.test.ts

注意 Node 26 的测试运行器要求传入文件 glob,直接传目录会报 MODULE_NOT_FOUND。涉及共享状态的测试使用 --test-concurrency=1,避免假时钟互相干扰。

书里的代码块与工程文件逐字节一致,校验方式是用 // file: 头找到目标路径再比对。这意味着如果你发现书里与工程不一致,那不是排版问题,而是真错误,值得提一个 issue。

代码与命名约定

  • 文件与目录用英文 kebab-case,如 endpoint-matrix.ts、hot-update.ts。
  • 类型与接口用大驼峰,函数与变量用小驼峰,常量用大写蛇形。
  • 不使用 enum 与 namespace:Node 的类型剥离不支持它们,运行时会直接报错。
  • 本地导入带 .ts 后缀,这是 Node 原生类型剥离的要求,不是风格选择。
  • 金额一律用整数分,时间一律注入,不调用 Date.now()。
  • 所有「未知输入」返回 undefined 或显式错误,不返回默认值。

这些约定不是为了统一风格,而是为了让代码在五个端上都能被同一套判断复用。风格分歧可以容忍,语义分歧不行。

错误处理的口径

卷四讨论的多端问题,大多不是「代码抛异常」,而是「某个端静默地做了不同的事」。因此错误处理的重点在暴露,不在捕获:

  • 能力缺失默认按 absent 处理,不假设支持。
  • 承诺未声明默认按最低等级处理,不假设一致。
  • 依赖越界直接报错,不自动降级为警告。
  • 预算超限返回超限明细,不只返回一个布尔值。

这套口径会让开发阶段更吵,但能让发布阶段更安静。反过来做,问题会推迟到线上,由用户替你发现。

为什么用 TypeScript 与 Node 26

四个理由。

第一,可验证。 卷四的很多判断是「集合运算」:承诺矩阵取最强等级、依赖图找环、能力表算得分、预算表找超限项。这些判断用任何语言都能写,但 TypeScript 的类型系统能让「允不允许」在编译期就暴露,读者不必运行也能看懂约束。

第二,跨端中性。 书里讨论 Web、iOS、Android、小程序与桌面,但实验代码不绑定任何一个端的运行时。同一段承诺计算逻辑,可以直接翻译成 Swift、Kotlin 或 WXML 逻辑层的等价实现,判断不变。

第三,零依赖。 没有 package.json、没有锁文件、没有构建步骤。Node 26 原生剥离类型,node file.ts 直接运行。这让代码块可以逐字节复制到工程里,不产生版本漂移。

第四,测试即文档。 node --test 的断言同时是规格说明。读测试比读实现更快理解一个模块承诺了什么。

不选框架、不选平台 SDK,是刻意的边界。框架会变,判断不会。

章与章之间的依赖

十三章不是十三条平行线,存在三条主依赖:

第 1 章(承诺与边界)
  ├─→ 第 2 章(设计系统)─→ 第 9、10 章(国际化、无障碍)
  ├─→ 第 3 章(插件化)
  ├─→ 第 4、5 章(性能、稳定性)─→ 第 7 章(可观测性)
  ├─→ 第 6 章(构建交付)
  └─→ 第 8 章(安全隐私)

第 11 章(治理)依赖 1、2、6
第 12 章(迁移)依赖 1、11
第 13 章(收口)依赖全部

依赖的含义是「概念前置」,不是「必须按序读」。例如第 9 章的时区与货币判断,需要第 1 章的承诺等级才能说清「哪个端可以不同」;但没有读第 2 章,也能理解格式化的正确性。

如果只想读一章,选第 1 章或第 11 章。前者定义问题,后者定义谁负责。

关于数字与实测

书里出现两类数字,需要区分:

  • 构造数据:案例中的订单量、团队人数、版本号、耗时。它们用于让场景自洽,不代表任何真实系统。
  • 实跑结果:实验工程的测试数量、构建耗时、依赖扫描结果。这类数字附有命令与版本,可以复现。

写作时遵守一条规则:没有真跑过的,不写「实测」;只跑过一次的,不写「稳定在」。如果读者发现某个数字与自己的环境差异很大,那通常是正常的——架构判断不该依赖精确数字,而该依赖数量级与趋势。

在团队里怎么用这本书

书里的方法只有在团队里跑起来才有价值。三种常见用法:

读书会。 每周一章,先读现场与判据,再让负责该领域的同学补充本团队的真实数据。不要逐行读代码,代码是课后材料。

架构评审。 直接使用附录 C 的清单。每个问题要求回答「现状、证据、缺口、owner」,答不上来的项就是风险项。

落地顺序。 先做第 1 章的承诺矩阵,再做第 11 章的 ADR 与所有权,然后才是第 2、6 章的平台建设。顺序反了会变成「先建平台,再找用途」。

三种用法可以叠加,但不要同时启动。治理动作太多,团队会把它们当成流程负担而不是工具。

三个动手练习

练习一:给你的产品填一张承诺矩阵。 选五个核心功能、三个端,填 15 个格子。填不出来的格子标「未定义」,统计数量。多数团队第一次填会有三到五格填不出来,这些格子就是下一轮联调吵架的位置。

练习二:审计一次依赖方向。 把客户端仓库的模块画成图,标出层级(core / protocol / adapter / ui),找出所有反向依赖。不用修,先数清楚有多少条。

练习三:写一条可执行的治理规则。 从「core 不得依赖 ui」开始,用脚本或 lint 规则实现,接入 CI。规则要能在一次提交内给出明确错误,而不是一份需要人读的文档。

三个练习的产出可以直接作为第 11 章治理清单的输入。

自检清单

读完一卷,可以用下面六个问题自检:

  1. 能否说出五个端上哪三个行为必须逐字一致?
  2. 能否指出共享代码里最容易被误用的一个模块,以及它的边界?
  3. 能否在十分钟内定位「某功能在某端不可用」的原因?
  4. 能否说出当前架构下一次迁移的退出条件?
  5. 能否列出三条已经自动化检查的架构规则?
  6. 能否说出一次故障演练的最近日期与结论?

答不上来的问题,对应章节值得重读。

勘误与反馈

书稿与实验工程同步维护。发现代码不一致、结论有反例、或者某个判据在你的场景里失效,欢迎带着复现步骤反馈。最有价值的反馈不是「这里不对」,而是「在我们的条件下,这个判据给出了错误结论,原因是……」。

版本信息:实验使用 Node v26.5.0,站点构建使用 Hugo v0.163.3+extended。正文中的日期、订单号、版本号均为构造数据。

每章的产出物

读完一章,不应该只留下印象,而应该留下可交接的东西。卷四每章对应一类产出:

章产出物形态
1承诺矩阵、依赖图、能力表表格 + 代码
2token 表、组件契约、主题配置JSON + 类型定义
3插件协议、权限清单、热更新开关接口 + 策略
4性能预算、归因表、回归基线指标 + 阈值
5故障域图、降级清单、演练记录图 + 清单
6依赖图、产物清单、发布流水线配置 + 脚本
7观测契约、采样策略、告警路由字段 + 规则
8数据分级、SDK 清单、同意记录表 + 流程
9格式化规则、RTL 清单、区域能力表函数 + 表
10语义结构、偏好映射、验收用例代码 + 用例
11ADR、所有权表、技术债台账文档 + 表
12迁移计划、双写窗口、退出条件计划 + 判据
13端到端报告、平台矩阵、治理清单报告

产出物不必一次做完。第一轮可以是「一页纸 + 三个待办」,重点是让判断留下痕迹。没有痕迹的架构讨论,三个月后只能靠记忆复现。

小结

卷四是一本判据书。它不提供可以照抄的架构,而提供一组让架构可被讨论、可被验收、可被演进的方法。

读法建议:先读每章的现场与判据,再回来读代码;先填自己的承诺矩阵,再看书里的例子;先在小范围跑一条治理规则,再谈平台化。

从目录与学习路径 开始。

常见错误与边界

  • 把判据当成结论,跳过「如果……那么……」直接照搬。
  • 只读代码不读反例,误以为模型覆盖了所有情况。
  • 先建平台再找用途,导致组件很多但没人用。
  • 同时启动多项治理,团队把它们当成流程负担。
  • 把 L1 的纯判断当成真机验证,忽略平台差异。
  • 用「测试全绿」替代证据,不记录跑了哪一级、断言了什么。

继续阅读

探索更多技术文章

浏览归档,发现更多关于系统设计、工具链和工程实践的内容。

全部文章 返回首页

「books」更多文章

  1. 《互联网产品的 AI 架构·平台化与治理》附录 C 平台化评审清单
  2. 《互联网产品的 AI 架构·平台化与治理》附录 B 能力目录与配额字段速查
  3. 《互联网产品的 AI 架构·平台化与治理》附录 A 治理角色与职责速查