这本书怎么用
序里说明了为什么写这本书。前言只回答一个更具体的问题:拿到这一卷之后,应该怎么读、怎么验、读到什么程度算读完。
卷一不是散文集,它的每一节都遵循同一套结构,每一个结论都能落到一个可运行的产物或一张可核对的表上。下面把使用约定一次讲清楚,后面正文不再重复。
双案例:一组刻意设计的对照
卷一使用同一 IP 下的两款产品作为案例。它们不是「大厂 vs 小厂」的对比,而是同一工作室、同一套中台、同一批人面对两种约束:
| 维度 | 《潮汐消消》 | 《潮汐方舟》 |
|---|---|---|
| 品类 | 三消 + 家园装饰(休闲) | 卡牌策略 RPG(中重度) |
| 上线时间 | 2024-03 | 2025-06 |
| DAU / MAU | 80 万 / 620 万 | 25 万 / 180 万 |
| 平台占比 | Android 60% / iOS 40% | Android 65% / iOS 35% |
| 低端机占比(4GB RAM 以下) | 35% | 15% |
| 首包 / 总资源 | 120MB / 480MB | 350MB / 1.8GB |
| 默认帧率 | 30fps(高档 60fps) | 60fps(低档 30fps) |
| 单局/单场时长 | 90 秒 | 8–12 分钟 |
| 联网形态 | 弱联网 | 强联网战斗 + 异步 PvP + 赛季 |
客户端基线的完整口径在附录 B,包括冷启动 P50/P95、热启动、首帧时间、稳态内存、内存水位、崩溃率、ANR 率、Jank 率与每帧预算。全书只使用这一套数字,任何章节不得出现第二套 DAU、包体、帧率或时延。
有三条使用规则需要提前说明:
- 每节一个主案例。 例如第 7 章 UI 以消消为主,因为休闲产品的弹窗密度和返回键语义最复杂;第 10 章存档以方舟为主,因为它有战斗中途恢复和赛季结算。另一个案例只在关键分歧处作对照,且每段不超过 150 字。
- 所有数字都是案例设定。 它们用于演练口径与决策,不是某台设备的跑分。正文统一写「案例设定」或「基线口径」,不会出现「实测」「生产数据」这类措辞,除非同时给出本机命令和输出。
- 数字一旦矛盾,以附录 B 为准。 如果你发现正文与附录 B 不一致,那是正文的错,请以附录为准并记下来。
mga-lab:可运行的实验工程
卷一附带的实验工程叫 mga-lab,写作期位于仓库的 .local/checks/mga-lab/。它有三个刻意的设计约束:
- TypeScript,Node 26.5.0 原生类型剥离。 不需要编译步骤,
node file.ts直接运行。代价是只能用可擦除语法:禁止enum、namespace、构造函数参数属性和装饰器。 - 零第三方依赖。 只用
node:内置模块。测试用node:test加node:assert/strict,断言风格与内置测试器一致。 - 本地导入必须带
.ts后缀。 这是原生类型剥离的运行要求,不是风格偏好。
目录结构按「层」组织,和正文第 2 章的分层一一对应:
mga-lab/
├─ package.json # type: module
├─ src/core/ # 时钟、事件、结果类型、分层规则
├─ src/domain/ # 三消与卡牌玩法的纯逻辑内核
├─ src/platform/ # Host 契约与 mock 实现
├─ src/runtime/ # 生命周期、恢复、帧预算、温控
├─ src/config/ # 配置 schema、表、版本迁移
├─ src/resource/ # 资源图、内存预算、缓存
├─ src/ui/ # UI 栈、布局模型、弹窗仲裁
├─ src/input/ # 手势、机型分档、形态因子
├─ src/save/ # 存档、合并、完整性
├─ src/i18n/ # 文本目录、时区、区域配置
├─ src/obs/ # 事件、采样、崩溃模型
└─ test/ # 与 src 镜像的 node:test 用例
运行全部测试:
cd .local/checks/mga-lab
node --test test/*/*.test.ts
只跑某一章的测试(通配符必须落到具体文件,这是 node --test 在 Node 26 下的行为):
node --test test/runtime/lifecycle.test.ts
正文中的每一个可运行代码块都以三行注释开头,依次是:
| 行 | 形式 | 含义 |
|---|---|---|
| 第 1 行 | file: 加相对路径 | 这段代码在实验工程里的位置 |
| 第 2 行 | tier: 加 L1 或 L2 | 可运行层级 |
| 第 3 行 | verify: 加命令 | 验证它的测试命令 |
例如第 4 章的状态机代码会标注 file: src/runtime/lifecycle.ts、tier: L2、verify: node --test test/runtime/lifecycle.test.ts,三者都能在实验工程里对应上。正文代码块与该文件逐字节一致——这不是排版约定,而是写作期的门禁:任何一个字符不同,校验脚本都会失败。
L1 与 L2 是什么意思
| 层级 | 含义 | 典型内容 |
|---|---|---|
| L1 | 纯逻辑,可在 Node 下直接运行并断言 | 状态机、依赖规则、配置迁移、合并算法、时区换算 |
| L2 | 依赖 Host 接口,运行的是 mock 而非真机 | 桥接消息、生命周期事件、帧预算调度、崩溃采集 |
L2 不是「没写完」,而是刻意把设备相关部分抽象成接口。凡属于 L2 的段落,正文会明确写出「这里是模型,不是设备实测」。读到这类代码,请关注结构:接口切在哪里、失败怎么降级、状态如何恢复;不要把它当作性能结论。
每一节的固定结构
卷一每一节都是六段,顺序固定:
- 开场:一个具体事故或决策场景,说明这一节要解决什么。
- 分析:三到五个小节,至少一张表,给出判断依据、取舍与后果。
- 与相邻章节的关系:说明这一节的结论依赖谁、被谁依赖,避免读者误以为可以单独套用。
- 小结:三到五条可以直接带走的判断。
- 阅读导航:一行,指向上一个和下一个可读单元。
- 常见错误与边界:至少五条可操作的错误清单,每条都说明后果。
这种结构是为了防止两种常见的架构写作病:只讲原理不讲取舍,以及只讲结论不讲前提。如果你读某一节时发现「分析」部分没有表,或者「常见错误」在说空话,那大概率是写作缺陷,可以直接跳过那一节去读相邻内容。
三类阅读路径
路径一:顺序读。 适合第一次接触移动客户端架构,或正准备为新产品搭骨架的人。按 1 → 13 章顺序读,每章三节连着读。第 13 章会把前 12 章的结论收口成一张基线表,顺序读到这里会有明显的「对上了」的感觉。
路径二:带问题查。 适合已经在维护线上产品的人。先看下面这张问题索引,直接跳到对应章节,再回头补读它依赖的前置章节:
| 你遇到的问题 | 先读 | 再补 |
|---|---|---|
| 切后台回来进度丢了 | 4.1、4.2 | 4.3、10.1 |
| 低端机闪退或卡顿 | 6.2、8.2 | 9.1、12.1 |
| 活动配置上线后老版本白屏 | 5.1、5.2 | 5.3、11.3 |
| 帧率不稳、手机发烫 | 9.1、9.2 | 9.3、8.2 |
| 存档被改、奖励重复领 | 10.3 | 11.2、12.2 |
| 线上问题定位慢 | 12.1、12.3 | 12.2、4.3 |
| 两款产品想复用一套框架 | 2.1、3.1 | 3.3、13.1 |
路径三:只读产物。 适合想直接看代码的人。按 src/core → src/runtime → src/resource → src/save 的顺序读实验工程,先跑测试再读实现。这种读法会错过一部分决策背景,但能最快建立「结构长什么样」的直觉。
与站内其他书稿的分工
卷一与站内已有的几套书稿有明确边界,读到重叠概念时不必怀疑重复:
- 分层、依赖方向、页面栈与崩溃可观测性的通用方法,在《互联网产品的客户端架构》里有更完整的展开;卷一只取与移动游戏相关的那部分,并补上游戏特有的资源、帧预算和存档问题。
- 引擎资源包、JSB、UI 适配的用法,在《Cocos 游戏开发》里;卷一不重复引擎 API,只讨论引擎之上怎么组织。
- 服务端拓扑、协议内核、战斗同步算法,在《游戏服务端架构》和《MMO 服务器开发》里;卷一只写客户端在网络契约中的责任。
- 小游戏/H5/小程序生态,在《小游戏开发实战》里;卷一只写原生 Android/iOS 与渠道包。
遇到这些重叠点时,正文会用一段概述加一个站内链接带过,然后把篇幅留给本书真正新增的部分:可运行产物、双案例对照,或带后果的决策记录。
读完一卷的标准
最后一节 13.3 会给出一份评审清单。在那之前,你可以用下面四条自检:
- 能画出自己产品的四层依赖图,并指出至少一条当前违反依赖方向的调用;
- 能说出冷启动、热启动、杀进程恢复三条路径分别保存了什么、丢了什么;
- 能给出低端机的内存水位和降级顺序,并说明为什么是这个顺序;
- 能列出线上崩溃、ANR、卡顿各自的采集边界和分母。
四条都能答上来,卷一就算读完了。答不上来的那一条,就是下一次重读的入口。
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。