给一家广告公司做的结算系统刚上线不久,客户亲手录进去一个真实项目,合同金额都已经填好。同一天我们要验证另一个完全无关的功能,顺手跑了演示数据脚本。这个脚本开头有一段清库:先把表清空,再灌一批演示数据。客户那个项目,就这样被一并清掉了。
去翻备份:备份每天凌晨一次,客户白天录的数据正好落在两次备份之间,三份备份里一份都没有。最后是靠清空前留下的界面截图,对着客户自己的总表模板,一格一格重建回去的。数据丢失不像 bug,改代码补不回来。
「开发工具」交出去之后就变了性质
这类脚本在开发阶段每天都跑,没人给它加确认,因为库里全是自己造的数据,删了再来就是。开头先清库,也是为了每次演示都从一张干净的表开始。
系统交到客户手里,这些脚本还留在我们手里,一个字没改,性质却全变了:它们现在能删的,是客户的劳动成果。那天的脚本照它的写法一步没错,错在写它时默认了一件事:库里只有演示数据。
可试用和正式使用之间没有分界线,客户哪天开始录真数据,不会有人通知我们。脚本自己不知道这一点,也不会问;跑它的人也没先查一眼库里有什么。
「最新的」「同名的」,都认不准是哪一条
有些功能只有在线上才验得出来,验完会留下测试记录,总得清掉。比清库更隐蔽的,就是这种看起来很克制的删法:只删自己刚产生的测试数据。问题在于,怎么认出哪些是「自己的」。
在一个直播互动游戏上做线上验证时,我们每验证一次,系统就会顺带开出一局、存下一份战报。清理时我们认的是「最新一份、并且在十分钟以内的,就是我们自己的」,也以为客户不在线。可我们确认客户在不在线,已经是十几分钟前的事了。
客户就在这个空档里开了一局。我们删掉的,是客户 26 秒前刚开出来的真实一局。好在那一局还能原样重做出来。事后要分清哪几局是客户的、哪几局是我们的,只能凭前后操作的节奏反推。
按名字认也一样靠不住:两个同名客户、两份同名合同,差别往往只在状态那一栏。这些认法的共同毛病,是凭的信息不够:只看名字不看状态,没记确切编号,拿「最近十分钟」框一段时间,就当里面全是自己的。时间范围尤其危险,它假设那段时间里没人在用。
我们现在的规矩
- 产生测试数据的当场就记下确切编号,删除只认这个编号。 「最新的」「几分钟内的」「同名的」,一律不算。
- 演示数据脚本只清自己登记过的记录。 库里多出一条名单外的就停手,列给人看,人明确下令才清。
- 删之前,先把要删的东西原样打印出来,人看过再动手。 两个工具报的数字对不上时,两个都别信,回到原始记录去看。
- 清库、灌数据的脚本只在测试环境跑。 真删前先自动存一份完整备份,存不成就停。
- 客户开始录数据后,备份从每日压到每 3 小时一次。 上线当天配的日备份是底线,它的 24 小时窗口兜不住白天的录入。
- 动数据前后都看一眼访问日志,分清谁改的。 但它不是「现在可以删」的许可:查在线和真删之间总有空档,删除还是只认编号。
这些规矩防的与其说是代码 bug,不如说是写进判据里的「以为」:以为库里只有演示数据,以为客户不在线,以为同名就是同一条。系统交出去之后,客户随时可能正在用。
删测试数据只认当场记下的编号,不认「以为」。

