上线前,最容易骗人的是测试样本。
你准备了 10 条订单,3 个用户,2 个边界条件。跑了一遍,新逻辑没报错,结果看起来也对。于是你松了一口气,点了发布。
第二天早上,群里开始响。
有人说退款订单不对,有人说老用户被算成新客,有人说去年遗留的一批补录数据突然把图拉歪了。
你看着屏幕,心里那句脏话还没说完,已经开始背锅。
干净样本测不出脏世界
很多数据问题不是代码完全没测,而是测得太干净。
真实历史数据很脏。它有重复、有缺失、有迟到、有补录、有业务临时规则,有当年某个活动留下来的奇怪字段。
测试样本往往没有这些东西。
所以测试通过,只能说明你的逻辑能处理一个理想世界。它不能说明你的逻辑能处理公司过去几年留下来的旧世界。
Stripe 最近写了一篇技术文章,讲他们用 Apache Spark 做微服务测试,其中一个重要思路是利用历史请求数据重放,比较新旧系统行为。
这件事放到普通数据工作里,也很有启发。

你不一定要做一套完整平台。
但上线前多拿一段真实历史数据跑一遍,很多问题会提前浮出来。
先别追求完美系统,先做 1 次回放
对普通数据从业者来说,历史回放可以很小。
比如你改了一个活动复盘指标。
不要只拿今天 20 条样本测。拿过去 30 天活动数据跑一下,看看新旧口径差异分布。差异大的日期挑出来,问问原因。
比如你改了一个 ETL 同步逻辑。
不要只看任务是否成功。拿一批旧分区重跑,比较行数、关键字段空值率、去重后数量、异常状态分布。
比如你改了一个用户分层模型。
不要只看几个用户画像是否合理。拿历史用户跑一遍,看分层迁移是否出现明显跳变,尤其看高价值用户和边界用户。
回放不是为了证明你没错。
回放是为了在上线前找到你可能错在哪里。
回放时重点看 4 类差异
第一类是数量差异。
行数、订单数、用户数、交易数有没有突然变化。数量变化不一定是错,但必须解释。
第二类是结构差异。
新旧结果里,各状态、各渠道、各分层的占比有没有明显变化。总量一样,不代表结构没变。
第三类是边界差异。
退款、取消、补录、跨天、重复、异常用户、极端金额,这些样本最容易暴露问题。别只看平均值,平均值很会安慰人。
第四类是业务差异。
这个最麻烦。技术结果看起来没问题,但业务含义变了。比如一个“有效订单”口径,多排除了某类补贴订单,财务和运营的理解就可能完全不同。
你要把这些差异写下来。
不是为了显得流程完整,而是为了让上线后的问题有地方追。
差异表比口头保证更有用
很多上线评审最没用的一句话是:“我测过了。”
这句话太薄。
更有用的是一张差异表:
- 旧逻辑结果是多少;
- 新逻辑结果是多少;
- 差异比例是多少;
- 差异主要集中在哪几类样本;
- 哪些差异是预期内;
- 哪些差异需要上线后继续观察。
你把这张表发出来,别人就知道你不是在赌。
哪怕最后仍然出问题,你也能更快定位,而不是从零开始翻日志、找 SQL、问口径。
数据工作里有很多锅,不是因为人不负责,而是因为上线前没有把“旧世界”请回来再看一眼。
多重放 1 次历史数据,可能真的少背 3 次锅。
这不是夸张。
这是很多夜里改数据的人,慢慢学会的朴素经验。
最小版本怎么做
如果你现在没有平台、没有自动化测试、也没有很多时间,可以先做一个很小的版本。
选 3 天历史数据。
一天正常,一天业务波动大,一天出现过异常。把新旧逻辑都跑一遍,导出一张对比表。不要只看总数,至少看 5 个字段:总量、核心金额、关键状态、空值率、异常样本数。
然后把差异分成 3 类:
- 预期差异:这次改动本来就会导致变化;
- 可解释差异:变化不是目标,但原因明确;
- 未解释差异:现在还不知道为什么变了。

上线前最该盯的,不是前两类,而是第三类。
如果第三类还很多,就别急着说“测完了”。这时候上线,不叫勇敢,叫把未知数交给明天的自己。
很多数据从业者真正需要的,不是一套很高级的测试体系,而是先养成这个习惯:上线前让旧数据替你说一遍真话。
旧数据不会照顾你的面子。
这正是它有用的地方。
我叫石头,在数据行业里摸爬滚打了十几年,越来越相信上线前多看一次旧数据,比上线后解释十次都有用。这里写的,就是这些教训——我觉得值得说出来的那部分。