第十六章 独立负责

一

赵北辰走的那天,把一个文件夹拷给了王志远。

文件夹里有三样东西:一份系统架构图、一份模块负责人清单、一份技术债务清单。

架构图上,"订单履约模块"旁边的负责人从"赵北辰"改成了"王志远"。

"这个模块以后你负责。"赵北辰说。"日常开发、技术方案、线上问题,都是你的。"

王志远盯着屏幕上自己的名字,下意识地把手从键盘上挪开了——怕手汗把键盘弄湿。

订单履约模块是整个系统的核心之一——从用户下单到商品发货,中间涉及库存扣减、支付确认、物流对接、状态流转,逻辑复杂,上下游依赖多。

"我能行吗?"他问。

"你觉得呢?"

王志远想了想。半年前他会说"不行"。现在他说:"我试试。"

赵北辰笑了:"'试试'比'不行'好,但不如'我来'。"

王志远深吸一口气:"我来。"

"这就对了。"

二

独立负责的第一周,王志远就遇到了挑战。

产品经理李想提了一个需求:给订单履约流程加一个"拆单"功能——当一个订单包含多个仓库的商品时,自动拆成多个子订单,分别发货。

这个需求涉及订单模型的改造、库存扣减逻辑的调整、物流对接接口的扩展,影响面很大。

以前这种需求,赵北辰会先出一个大致的方案,然后让王志远去细化和实现。现在赵北辰不在了,从方案到实现,全是他一个人的事。

他花了两天时间做调研和设计,写了一份技术方案文档。然后他约了一个技术方案评审会。

参加评审的有苏薇、陈锐、周旋经理,还有仓储组的一个同事老孙。

三

评审会上,王志远打开了他的设计文档,开始讲解。

他讲了拆单的触发条件、拆单算法、子订单的状态流转、与库存和物流的交互方式。他画了时序图、类图、状态机图,还准备了一份数据库变更方案。

讲完之后,提问环节开始了。

苏薇第一个问:"拆单之后,如果其中一个子订单发货失败,主订单的状态怎么处理?"

王志远回答:"主订单的状态由所有子订单的状态决定。如果所有子订单都发货成功,主订单状态变为'已发货'。如果有子订单失败,主订单状态变为'部分发货'。"

"那用户看到'部分发货'之后,能不能取消未发货的子订单?"

王志远愣了一下。他没有考虑过这个场景。

"这个……我回去补充一下。"

苏薇点了点头,没有追问。

老孙问了一个更尖锐的问题:"拆单的时候,库存扣减是在拆单前还是拆单后?如果拆单前扣减,拆单失败了怎么回滚?如果拆单后扣减,拆单成功但库存不足怎么办?"

王志远的额头开始冒汗。这个问题他想过,但没有想透。

"我的方案是拆单后扣减。"他说。"拆单成功后,每个子订单独立扣减对应仓库的库存。如果某个仓库库存不足——"

他停了一下,脑子飞速运转。

"如果某个仓库库存不足,那个子订单标记为'待补货',不影响其他子订单的发货。同时通知用户,给出预计补货时间。"

老孙想了想:"可以。但你需要考虑一个边界情况——如果用户在下单时看到的是'有货',拆单后变成'待补货',用户体验不好。建议在下单前就做库存预校验,按仓库维度检查。"

"好的,我补充这个逻辑。"

陈锐问了一个技术细节:"拆单算法的时间复杂度是多少?如果一个订单有一百个商品,分布在十个仓库,拆单的性能能保证吗?"

这个问题王志远有准备:"拆单算法的核心是按仓库分组,时间复杂度是 O(n),n 是商品数量。一百个商品、十个仓库的场景,我做了性能测试,拆单耗时不到 5 毫秒。"

陈锐没有再追问。

周旋经理全程没有提技术问题,但在最后说了一句:"方案整体可行,但有几个细节需要补充。志远,给你两天时间完善,完善后再发一版给大家确认。"

四

评审会结束后,王志远回到工位上,后背全是汗。

他数了一下——评审会上一共被问了十一个问题,他当场回答了七个,有四个需要回去补充。

四个没答上来的问题,每一个都是他设计时的盲点。

他想起赵北辰说过的话:"设计评审不是来展示你的方案有多好的,是来发现你的方案有什么漏洞的。被问倒不丢人,被问倒了还不改才丢人。"

他花了两天时间,把四个问题全部想清楚,补充到了设计文档里。他还加了一节"风险与应对",把评审会上提到的所有边界情况都列了出来。

修改后的文档发出去,苏薇回复了一个字:"可。"

这个"可"字,比任何长篇大论都让他安心。

五

拆单功能的开发用了三周。

过程中遇到了不少问题,但王志远发现,因为设计阶段想得足够充分,编码阶段的问题大多是实现层面的,不涉及架构调整。

最大的挑战是状态机。

订单的状态流转本来就复杂——待支付、已支付、待发货、已发货、已签收、已取消、已退款。加上拆单之后,主订单和子订单各有一套状态,而且子订单的状态变化会影响主订单的状态。

他画了一张状态机图:

主订单状态:
待支付 → 已支付 → 待拆单 → 已拆单 → 部分发货 → 全部发货 → 已完成
                                    ↓
                              部分取消 → 全部取消

子订单状态:
待发货 → 已发货 → 已签收
  ↓        ↓
待补货   退货中 → 已退货
  ↓
已取消

状态之间的转换规则有二十多条。他用了一个状态机框架来管理,每条转换规则都写了单元测试。

测试写了四十多个用例,覆盖了正常流程、边界条件、异常情况。他特别注意了并发场景——如果两个子订单同时更新状态,主订单的状态计算会不会出错?

他用乐观锁解决了这个问题,并写了一个并发测试来验证。

六

三周后,拆单功能上线了。

上线前,他做了一件赵北辰教他的事——写了一份上线检查清单:

## 上线检查清单

### 代码
- [x] 所有代码已通过 Code Review
- [x] 单元测试覆盖率 > 85%
- [x] 集成测试全部通过
- [x] 无 P0/P1 级别的 SonarQube 告警

### 数据库
- [x] 数据库变更脚本已 Review
- [x] 变更脚本在测试环境执行成功
- [x] 有回滚脚本

### 配置
- [x] 新增配置项已添加到配置中心
- [x] 配置项有默认值和说明

### 监控
- [x] 关键指标已添加监控(拆单成功率、拆单耗时)
- [x] 告警规则已配置

### 灰度
- [x] 灰度发布方案已确认(先 10% 流量,观察 1 小时)
- [x] 回滚方案已确认

### 通知
- [x] 已通知上下游团队(仓储组、物流组)
- [x] 已通知客服团队(新功能说明)

上线过程很顺利。灰度 10% 流量,观察一小时,各项指标正常。全量放开后,拆单成功率 99.8%,平均耗时 3 毫秒。

李想验收后说了一句:"这个功能做得很扎实。"

王志远笑了笑。他知道"扎实"这个词的分量——它意味着不只是"能用",而是"靠谱"。

七

上线后的第三天,出了一个小问题。

一个用户的订单拆成了三个子订单,其中一个子订单的物流信息没有同步到主订单页面。用户投诉说"我的订单显示未发货,但其实已经发了"。

客服把问题转到了王志远这里。

他查了一下,发现是物流信息同步的定时任务有一个 bug——当子订单数量超过两个时,第三个子订单的物流信息会被跳过。原因是一个循环的边界条件写错了。

// bug 代码
for (int i = 0; i < subOrders.size() - 1; i++) {
    syncLogistics(subOrders.get(i));
}

// 修复后
for (int i = 0; i < subOrders.size(); i++) {
    syncLogistics(subOrders.get(i));
}

size() - 1 应该是 size()。一个经典的 off-by-one 错误。

他修复了 bug,补了一个测试用例(三个子订单的场景),然后写了一份简短的故障报告:

## 故障报告

**现象**:子订单数量 > 2 时,最后一个子订单的物流信息未同步
**根本原因**:循环边界条件错误(off-by-one)
**影响**:约 50 个订单受影响
**修复**:修正循环条件,补充测试用例
**改进**:在测试用例中增加"多子订单"场景的覆盖

他把故障报告发到了群里,没有等别人来问。

苏薇看了之后回复:"发现快、修复快、报告清晰。不错。"

这是王志远第一次独立处理线上问题——从发现到修复到报告,全程没有找任何人帮忙。

他突然意识到,自己真的可以独立负责了。

八

那天晚上,他给赵北辰发了一条消息:

"赵哥,拆单功能上线了,运行稳定。今天出了一个小 bug,我自己修了。"

赵北辰回复了一个大拇指的表情,然后说:"看到了。故障报告写得不错。有一个建议——以后故障报告里加一条'如何防止类似问题再次发生',不只是修复当前的 bug,还要想想怎么从流程上避免。"

王志远想了想,在故障报告里加了一条:

预防措施:在 Code Review 检查清单中增加"循环边界条件检查"项。所有涉及集合遍历的代码,Review 时重点检查边界条件。

他把更新后的报告重新发了一遍。

赵北辰回复:"这就对了。修 bug 是治标,改流程是治本。"

九

那天晚上,王志远在笔记本上写下:

Day 195

第一次独立负责核心模块。第一次独立做方案评审。第一次独立处理线上问题。三个"第一次",一天之内。

苏薇说"可"的时候,我知道方案过关了。她的"可"比别人的"太棒了"更有分量——因为她从来不说客气话。

赵哥不在了,但他教我的东西都在。我发现自己开始用他的方式思考问题了——遇到事情先画图,先想影响范围,先问"最坏情况是什么"。

"我试试"不如"我来"。三个字的区别,是信心的区别。

他合上笔记本,看了一眼桌上的《程序员修炼之道》。书签夹在第七章——"石头汤与煮青蛙"。

书里说:做一个催化剂,而不是等待别人来推动变化。

他觉得自己正在从"被推动的人"变成"推动变化的人"。

这种感觉,很好。


:::{admonition} 小胖的笔记 :class: tip

本章知识卡片:独立负责模块

1. 技术方案评审流程

1. 写设计文档(架构、数据模型、接口、技术方案、风险)
2. 发出评审邀请(相关方:上下游、Tech Lead、产品)
3. 评审会(讲解 → 提问 → 记录问题)
4. 修改文档(补充评审中发现的问题)
5. 二次确认(邮件/群消息确认修改后的方案)
6. 开始编码

评审会的心态: - 被问倒 ≠ 方案不好,= 发现了盲点 - 记录所有问题,会后逐一解决 - 不要在会上争论细节,会后单独讨论

2. 上线检查清单

类别 检查项
代码 Code Review 通过、测试覆盖率达标、无高级告警
数据库 变更脚本 Review、测试环境验证、有回滚脚本
配置 新配置项已添加、有默认值和说明
监控 关键指标有监控、告警规则已配置
灰度 灰度方案确认、回滚方案确认
通知 上下游团队已通知、客服已通知

3. 故障报告模板

## 故障报告
- 现象:用户看到了什么?
- 根本原因:代码/配置/数据层面的原因
- 影响:影响了多少用户/订单?
- 修复:做了什么修复?
- 预防:如何防止类似问题再次发生?

4. 状态机设计

适用场景:订单、工单、审批等有明确状态流转的业务

设计要点: - 画出所有状态和转换关系 - 每条转换规则都要有单元测试 - 考虑并发场景(多个状态同时变化) - 使用状态机框架管理,避免 if-else 地狱

:::