我们的产品有八门语言的网站。免费额度在每一门的首页上都会写一次。
其中一门写错了。 写成了一个大得多的数字,而真实额度只有那个数的六成。
它在线上活了不知道多久。
所有的检查都是绿的
这件事最值得记的不是错误本身,是它躲过了我们全部的检查:
- 类型检查:绿
- 全部测试:绿
- 我们有一条专门查价格的守卫:也是绿的
那条守卫为什么没抓到?因为它只扫「$X.XX」这种形状的金额。而写错的是一个分钟数,不带货币符号。
最后是人在逐屏走查的时候,用眼睛看出来的。
补守卫的时候,差点补错
第一反应是加一条:「不许出现那个错的数字」。
这条是错的。 想一下就明白:下次如果写成另一个错的数字,这条守卫照样绿。
它防的是这一次的错,不是这一类的错。
正确的判据
改成了这样:
讲免费额度的那几处,渲染出来之后把里面所有的数字抽出来, 必须落在「允许出现的数字」这个集合里。
集合里就三个值:企业额度、个人额度、企业额度换算成小时之后的数。
任何别的数字出现在那几句话里,都红。
两者的区别
| 黑名单 | 白名单 | |
|---|---|---|
| 问的是 | 有没有出现那个错的 | 是不是都在允许的里面 |
| 漏掉的 | 所有你没想到的错法 | —— |
| 维护 | 每发现一种新错法就加一条 | 允许的值变了才改 |
黑名单永远追在错误后面跑。 你只能把已经犯过的错加进去,而下一个错还没被想到。
白名单是把口子先收窄。 不在名单里的一律拦下,包括你还没想到的那些。
为什么大家总是先写黑名单
因为黑名单看起来更容易:你刚犯了一个错,把它禁掉,事情就解决了。
而白名单要求你先回答一个更难的问题:到底什么是对的?
这个问题难,但它只需要回答一次。而黑名单的问题,每犯一次错就要回答一次。
别处的对应
这条在别的地方一样成立:
- 审稿:「不要出现错别字」是黑名单;「这几个专有名词只能写成这几种形式」是白名单
- 数据核对:「不要有异常值」是黑名单;「这一列只能是这几个值之一」是白名单
- 对外口径:「不要说错价格」是黑名单;「价格只能引用某一处的原文」是白名单
最后一个是我们后来定的规矩:对外材料里的价格,只能从线上原文抓,不许凭记忆写、也不许读本地文件。
理由很实在:本地文件会过期,而它过期的时候不会告诉你。