“To err is human”
在过去相当长一段时间内,我都在一个负责项目维护的团队内工作。团队的特殊之处在于,我们从来不开发新功能,而是负责解决每天上报的线上问题。这些 bug 无奇不有,从无法打开页面到数据奇怪丢失,麻木早已经替代焦虑成为了我们面对 bug 时的主要情绪。
但我时不时的抱怨依然是:为什么 bug总是在发生。
缺陷早已在丰田生产系统(Toyota Production System)中被标注为浪费之一。没有人希望看到 bug,我们不想,客户更加不想。但我们似乎都不愿承认的一个事实是:
bug是代码的副产品而已。
如果我们选择接受编码不过是人思维活动的一种形式,与思考无异,那我们也就必须接纳,人性的缺陷在代码中自然也不会缺席,恰如硬币的正反两面。
反过来说,如果你对 bug采取的是零容忍的态度,甚至不惜把此写入 KPI 中,它也未必会带来正面效应,因为自此开始,没有人会愿意重构,没有人会愿意引入新的技术方案,道理非常简单:改动越多风险越大——这是某年发生在我所属团队的一次亲身经历。
所以我们面临的并非 bug 去或者留的选项,而是多与少的问题。
摆正质量
在 MoSCoW 方法论的框架下,我们通常可以将功能的优先级划分为四类: Must Have, Should Have, Could Have 以及 Won’tHave,如果把质量也作为功能的一个维度落入这四个区间之一的话,它一定不会在 Must Have 这个范围内。因为人们既不会因为没有 bug而选择长时间地使用一款应用,也不会因为存在 bug而成为转投它竞争对手的唯一理由。我们必须承认这样一个事实:质量永远也不是商业的核心竞争力,这也暗示着:
- 有些功能缺陷是可以被容忍的
- 质量被分配得到的资源永远是有限的。
前者并非我们的一厢情愿,在互联网产品的高性价比和快速迭代的商业逻辑下,用户对产品质量的预期已经被规训到一个非常「理想」的状态。
而后者更为关键:我们应该如何最大化利用有限的资源去提升质量?如果你所在的部门也有机会组建一支类似于本文开头的团队,那不妨考虑一下这个建议:用资源换取更多的人员加入这支团队怎么样?
原谅我用一个粗俗的比喻来解释为什么这么做行不通:
我们换来的只是打扫的速度,对制造垃圾的人产生不了任何影响,效果甚至会适得其反:考虑到总有人为他们收拾残局,我们的善后工作做得越好,他们越是会肆无忌惮。
但这是当下大部分公司的现状:如果线上问题激增,是不是QA 工作不到位?我们似乎倾向把编码和测试的界限划分得一清二楚,从人员到职责到工序都是如此。而质量问题从编码中来,却想从测试中寻找解决之道,这与刻舟求剑无异。
铺垫了如此之多,我想表达的观点依然是老生常谈:质量内建,以及最近几年我们常常提倡的测试左移。至于什么是质量内建和测试左移,并不在这篇文章的范围内,你在网上可以找到大量的专业文章来介绍他们。
质量的成本
现在我们必须回答一个核心问题:谁该对质量负责?最官方的答案是每个角色,我们可以列举出产品经理没有全面地对功能做验收,QA没有把控好质量关等等。但假定此刻我们必须指定一人将他五花大绑起来祭天,为的是有人需要为上一个让人焦头烂额的bug 负责,程序员绝对是不二之选。
但程序员死也不会瞑目的。
如果你是团队经理,你发现上个月线上问题数量增加了一倍,于是你冲到你的工程师团队工位前,怒不可遏地冲他们吼道:我希望这个月的线上问题不超过个位数!你觉得他们能做到吗?
我想说的是:
质量不是「希望」的结果,它是付出的收获。关键在于你愿意用什么去交换。
提升质量的诀窍一点也不神秘。口口相传的各类业内实践便是最好的灵丹妙药,比如重构、代码评审、结对编程、流水线集成等等。我们不妨就以单元测试为例,看看我们需要付出多大的成本
首先,时间便是一笔可观的支出。以我所在的项目为例,我们为前端React 组件编写单元测试的时间,几乎与开发功能的时间相同。注意这还是在没有追求覆盖所有的边界用例,以及没有追求 100%的测试覆盖率的情况下。另外,当我们编写的代码导致之前编写的关联测试无法通过流水线时,去查找失败的原因以及修正这些错误也是隐形时间。
其次,在我看来最难以逾越的障碍在于对工程文化的重塑。对下要强调保证程序员去写、关注、修复的纪律;对上要争取理解和空间来辅助这些实践,单拎出来任何一件事推动起来都不简单。工程实践天然具有一种反商业活动的特性,它很难被量化、难以一针见效。没有人敢拍着胸脯说在xx 天之内或者当测试覆盖率至少达到 xx 水平之后, bug 数量会降至 xx。我们都不否认它会变得更好。讽刺的是实践带来的「负面」效应是立竿见影的:工程团队的交付速度变慢了。
测试的部分好处还来自未来,比如它能增强我们重构代码和变更架构时的信心,防止旧功能无意被新功能破坏。但我依然无法保证你的收益会何时何地有几倍于付出的到来。
于是现状变成了一方面可见的迭代速度变慢,另一方面成本的付出看不到收益,质量就自然值得被牺牲。
在提升质量的过程中,我们解决的不是个体问题而是工业问题。细想这是很难的:一个团队中成员的能力不同背景不同,但我们却要设法让它们的产出质量处于某个水平之上。
还债
听上去我们只能义无反顾去相信(take a leap of faith)某些实践能够帮助我们提升质量,且付出的收益是不确定的。但换一个角度想,我们只是在做一些本该做好的事情而已,用户的宽容让质量变得可有可无。
我不否认有时候快比好更重要,只不过当有一天质量变成我们无法再忽视的问题时,别不知所措地想不起来质量是在哪里搞丢的。