这一卷要解决的问题
卷二讨论的是「内容怎么流动」:信息流、互动、实时消息。它的失败大多可以被用户容忍——刷新一下、等一会儿、少看一条。
卷三讨论的是「钱怎么流动」。同样的客户端分层,一旦进入交易场景,失败边界立刻变硬:
- 金额算错,是资金损失。
- 库存判错,是超卖与履约纠纷。
- 订单状态判错,是重复下单或用户以为没下单。
- 支付结果判错,是重复扣款。
- 退款与售后判错,是投诉与监管风险。
所以这一卷不写「电商 App 怎么搭页面」,而是回答一组更窄、更硬的问题:端上哪些值可以自己算、哪些必须等服务端;哪些动作可以乐观,哪些必须幂等;哪些状态可以降级展示,哪些必须确认后再渲染。
十三章的排布
全卷 13 章 39 节,外加序、前言与本目录,以及三篇附录,共 45 篇。
| 章 | 主题 | 回答的问题 |
|---|---|---|
| 第 1 章 | 交易端架构与 trade-lab | 四条链路各自的失败边界是什么?实验怎么分级? |
| 第 2 章 | 商品与库存展示 | 价格、库存、时效来自三份数据,怎么拼成一个可信的商品? |
| 第 3 章 | 购物车与价格计算 | 本地车与服务端车怎么合并?端上能算到哪一步? |
| 第 4 章 | 下单与订单状态 | 怎么保证一次提交只产生一张订单? |
| 第 5 章 | 支付流程与回调 | 拉起、轮询、回跳三件事怎么编排?结果不确定时怎么办? |
| 第 6 章 | 支付对账与重复支付 | 端上怎么避免重复付款?退款状态怎么跟? |
| 第 7 章 | 优惠券与营销规则 | 券能不能用、能不能叠,端上判定到什么程度? |
| 第 8 章 | 会员、积分与权益 | 会员价、积分账本、权益到期怎么展示才不误导? |
| 第 9 章 | 分享、拉新与增长链路 | 分享参数、邀请绑定、活动页降级怎么做? |
| 第 10 章 | A/B 实验与远端配置 | 分流、曝光、配置缓存与实验污染怎么处理? |
| 第 11 章 | 客服、售后与工单 | 上下文怎么带?证据怎么留?离线怎么恢复? |
| 第 12 章 | 数据埋点与增长分析 | 事件契约、上报队列、漏斗口径的端上边界在哪? |
| 第 13 章 | 卷三收口:trade-lab 端到端 | 把选品、下单、支付、退款串起来,还差什么? |
这个顺序不是按「页面」排的,而是按承诺的强度排的:前三章是展示与预演,从第 4 章开始进入不可逆动作,第 5、6 章处理最不可控的外部系统,第 7 到 12 章是围绕交易的增长与支撑能力,第 13 章收口。
章节依赖
有些章必须按顺序读,有些可以跳。
必须连读的链:
- 第 1 章 → 第 4 章 → 第 5 章 → 第 6 章。所有权、幂等、支付状态、对账是同一个问题的四层,跳过任何一层都会得到「看起来能跑」的方案。
- 第 2 章 → 第 3 章。商品快照与购物车价格明细共享「同一份结算快照」的概念。
- 第 10 章 → 第 12 章。实验分流决定埋点口径,埋点口径反过来校验分流是否正确。
可以单独读的章:
- 第 7 章(优惠券):依赖第 3 章的价格明细,但不依赖支付。
- 第 8 章(会员积分):依赖第 2 章的商品价格,可与第 7 章互换顺序。
- 第 9 章(增长):主要是参数与归因,独立性强。
- 第 11 章(客服售后):依赖第 4、6 章的订单与退款状态。
第 13 章必须最后读。 它引用前面所有章的模块,单独读会变成一份名词清单。
每章留下什么
每一章都会在 trade-lab 里留下可运行的产物。读的时候可以对照下表,确认自己不是只看懂了文字。
| 章 | 主要产物 | 验证级别 |
|---|---|---|
| 1 | 金额与订单模型、所有权规则、分级判定 | L1 |
| 2 | 商品快照合并、SKU 约束、库存语义 | L1 |
| 3 | 购物车合并、价格明细、勾选与限购 | L1 |
| 4 | 提交幂等、状态映射、超时取消 | L2 |
| 5 | 支付编排、结果查询、回调时序 | L2 + L3 |
| 6 | 重复支付防护、对账口径、退款状态 | L2 + L3 |
| 7 | 券可用性、叠加规则、展示口径 | L1 |
| 8 | 会员展示、积分账本、权益到期 | L1 |
| 9 | 分享参数、邀请绑定、活动降级 | L1 |
| 10 | 分流、配置缓存、实验互斥 | L1 |
| 11 | 客服上下文、售后证据、工单恢复 | L2 |
| 12 | 事件契约、上报队列、漏斗边界 | L1 + L2 |
| 13 | 端到端流程、故障注入、质量场景 | L2 + L3 |
表中的「验证级别」不是难度,而是这条逻辑最低需要哪一级证据。第 1.3 节会解释为什么支付不能停在 L2。
三条阅读路径
路径一:客户端工程师的系统读法
从第 1 章开始,按 1.1 到 13.3 顺序推进。重点是每章的代码与测试:trade-lab 的模块是逐步长出来的,前面定义的 Money、OrderState、OrderLine 会在后面反复出现。
适合:要接手交易模块、要重构结算页、要补支付链路的工程师。
预计投入:每天 2–3 节,两周左右。
路径二:产品与设计的判断读法
读第 1 章(四条链路)、第 3 章(价格明细)、第 4 章(提交与状态)、第 5 章(支付结果)、第 7 章(优惠展示)、第 9 章(增长链路)、第 11 章(售后)。
跳过代码块,重点看每节的「关键决策」表格与「失败复盘」。这条路线的目标是:能判断一个方案在哪些地方必须等 service 端确认,哪些地方可以给即时反馈。
适合:交易产品经理、交互设计师、增长产品经理。
预计投入:一周左右。
路径三:技术负责人的风险读法
读第 1 章、第 4 章、第 5 章、第 6 章、第 10 章、第 13 章,再读附录 C 的评审清单。
重点是每章的「边界」与「常见错误」:哪些问题属于客户端、哪些必须服务端解决、哪些是协议层问题。这条路线的目标是:能在评审会上问出正确的问题,而不是替团队写代码。
适合:技术负责人、架构师、质量负责人。
预计投入:三天左右。
读完应能回答的六个问题
- 一个价格从商品页到支付成功,中间经过几次「确认」?每次确认的失败边界是什么?
- 为什么下单需要幂等键,而点赞不需要?幂等键应该在什么时机生成、什么时候复用?
- 支付结果有几种?「不确定」这一种为什么不能归入成功或失败?
- 购物车、结算页、订单详情三处的金额,为什么可能不一致?哪一处是权威?
- 优惠券的「可用」判定,端上能算到什么程度?哪些必须服务端算?
- A/B 实验的曝光口径与埋点口径不一致时,应该相信哪一个?
如果读完之后对每个问题都能给出「取决于什么」而不只是一个结论,这一卷的目的就达到了。
trade-lab 的结构
本卷的实验工程叫 trade-lab,与卷二的 social-client-lab 同构:Node 26 原生 TypeScript,零第三方依赖,node --test 是硬门禁。
目录按章划分:
trade-lab/
src/core/ # 金额、订单模型、所有权、分级
src/product/ # 商品快照、SKU、库存
src/cart/ # 购物车合并、价格明细、勾选
src/order/ # 提交、状态机、超时
src/pay/ # 支付编排、结果查询、回调
src/reconcile/ # 对账、退款
src/coupon/ # 券判定、叠加、展示
src/member/ # 会员、积分、权益
src/growth/ # 分享、邀请、活动
src/experiment/ # 分流、配置、互斥
src/support/ # 客服、售后、工单
src/analytics/ # 埋点契约、上报、漏斗
src/summary/ # 端到端、故障注入、质量场景
每章的源文件在正文里完整出现,带 // file:、// tier:、// verify: 三行头,可以用脚本反向抽取,与工程文件逐字节比对。
三级可运行性在交易场景的含义
卷二的分级按通道:纯逻辑、进程内、真实端口。卷三分级按链路风险:
- L1:金额计算、状态迁移、规则判定。纯函数,毫秒级反馈。
- L2:提交、轮询、超时、取消。进程内服务端加假时钟,验证时序。
- L3:支付回调、结果查询、重复通知。本地 HTTP 边界,验证协议与时序竞争。
第 1.3 节会把这条规则写成代码,并解释为什么支付必须有 L3。
与卷一、卷二的关系
- 卷一《端形态与体验基础》给出分层、状态、路由、渲染的基础结构。卷三假设这些结构已经成立。
- 卷二《内容、社交与实时互动》给出持续流动数据的处理方式。卷三复用其中的「状态归属」「乐观更新」「重连补拉」,但把容错收紧。
- 卷三不重复讲 TypeScript 语法、不重复讲通用分层。遇到需要回看的概念,正文会用
relref指回前两卷。
本卷不承诺什么
三件事需要提前说明:
- 不接真实支付渠道。 trade-lab 用本地 HTTP 模拟回调,验证协议与时序;真实渠道的签名、证书、限额不在本书范围内。
- 不做真实压测。 交易端的容量与数据库性能属于服务端架构,本卷只讨论端上能观测到的部分。
- 不覆盖全部行业规则。 跨境电商的税费、合规、外汇,以及线下核销、预售、拼团等玩法,只在必要处作为边界提及。
怎么使用附录
- 附录 A:订单与支付状态、金额字段的速查表,适合评审时对照。
- 附录 B:交易端问题排查手册,按症状(价格不对、重复下单、支付不回跳、退款卡住)组织。
- 附录 C:交易端评审清单,七组判据与证据要求。
三篇附录都不替代正文,只在需要快速定位时使用。
读之前的准备
三样东西就够:
- 一台装了 Node 26 的机器。实验用的是原生类型剥离,不需要
tsc、ts-node或任何构建工具。 - 读过卷二的第 1 章与第 5 章。状态归属与乐观更新是卷三的前置概念,没读过会反复卡住。
- 一个真实的交易流程体验。打开任意电商应用,从商详页走到支付成功,记录每一步显示了什么、哪一步需要等待。这份记录会比任何定义都更能帮你理解后面的取舍。
不需要准备支付渠道账号、数据库或消息队列。本卷的实验全部在进程内完成,L3 只用到 Node 标准库的 HTTP 服务。
怎么跑实验
trade-lab 不需要安装依赖,也不需要编译。进入目录后直接运行:
cd trade-lab
node --test test/core
node --test --test-concurrency=1 test/order
第一条跑纯函数测试,可以并发;第二条跑进程内流程,必须串行,因为假时钟与内存服务端是进程级共享状态。
如果你想只跑某一节:
node --test test/cart/cart-merge.test.ts
正文里的测试输出就是按这种方式跑出来的。用例名、数量与通过数可以直接对照;耗时数字会随机器负载波动,不必强求一致。
一个建议:读到某一章时,先把该章的测试跑一遍,再读正文。测试名本身就是这一章的小结。
术语约定
交易场景的术语在不同公司叫法不同,本书统一如下:
- SKU:最小可售单元,规格组合后的具体商品。价格、库存、限购都挂在 SKU 上。
- 订单快照:下单时冻结的商品、价格、优惠与收货信息,后续商品改价不影响它。
- 幂等键:一次提交的唯一标识,重试复用,用于区分「同一笔」与「两笔」。
- 支付单:一次支付尝试的记录,与订单是一对多关系;一张订单可能有多次支付尝试。
- 可售库存:扣除锁定与预留后,当前可以下单的数量,不等于物理库存。
- 曝光:实验或推荐位把内容展示给用户的一次事件,与「点击」「转化」分开统计。
遇到与你的团队叫法冲突时,以文中的定义为准,不要用本团队的语义去套代码。
小结
这一卷的主线是一条:每个值都要能回答「谁写的、能不能改、错了退到哪里」。
十三章按承诺强度排布,前松后紧;三条阅读路径分别面向实现、判断与风险。读完之后,你应该能在一个交易方案里指出哪些地方必须等服务端、哪些地方端上可以先行、哪些地方根本不该由端上决定。
从1.1 交易端的四条链路 开始。
常见错误与边界
- 把这一卷当成电商页面搭建指南。它讨论的是状态与失败边界,不是布局。
- 跳过第 1 章直接看支付。所有权没定清楚,后面的幂等与对账都会歪。
- 只读代码不看复盘。每节的失败复盘才是判断依据。
- 把 trade-lab 当成生产代码。它是用来验证判断的最小实现。
- 认为 L3 一定优于 L1。级别是成本,不是质量评级。
- 把附录当正文读。附录只用于快速定位。
- 忽略卷二的状态归属。卷三的严格规则是卷二规则的收紧版。
- 期待真实渠道接入。实验只到本地 HTTP 回调。
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。