这是一篇半娱乐性的吐槽文章,权当给广大技术人员解解闷:)。
哈哈哈,然后我要开始讲一个经常在发生的事实了。(程序员们可能会感到一些不适

)
99.999999999%做技术的都会被问到或者被吐槽到:"你的程序怎么又出bug了!"

▲图片来源于网络,版权归原作者所有
反正,我作为程序员的内心世界是:如同一万只草泥马飞奔而过,难以压抑内心的激动,每次都差点忍不住想说"你写篇几百字的作文还有错别字呢,我码个几万行的代码还不允许出错了?"
可能同样是做技术的你此时在不断点头,哈哈。
但是这么讲毕竟也缓解不了矛盾,我们还是得摆事实讲道理不是?
啥都不怕,就怕程序员有文化!
所以,Z哥想来带你好好分析一下这个事情,当你再遇到这个情况的时候,可以拿这些观点来反驳(不是做技术的也可以了解下程序员的难处,谁没个难处呢,多多包容)
什么是Bug
任何一个「问题」的产生,本身是没有好坏之分的,但是为什么会有的就不被care,甚至还会很喜欢,而有的会被吐槽呢?根本原因是因为产生了利益损失。
比如年前拼多多出问题送了很多无门槛券。
作为一个用户,自然很喜欢,夸你夸到飞起,怎么会吐槽你呢。但是作为利益损失方,必然破口大骂,害我倾家荡产!
所以,如果没有产生利益损失,我想其他人也不会来找你吐槽。
但是「问题」就等于「bug」吗?我认为并不是,「问题」不等于「 bug」。
因为程序员的职责是什么?拿造房子来比喻的话,我认为最核心的工作真的和"搬砖"(非贬义词)无异,就是根据设计师(产品经理)设计好的设计图砌砖(编码),建成和设计图纸上一模一样的建筑。
所以,如果一个东西造出来与设计不符,那么它可以说是bug或者缺陷(缺斤少两不完整)。否则,并不是bug,但可以被称之为「漏洞」(完全没考虑到的),表示不在预料之内的情况。
之前看到过一个形象的比喻:你家里的窗可以从外面打开,那叫漏洞。你家里的窗打不开,那叫bug。
但是要承认,bug是必然存在的。为什么?它是如何出现的呢?
Bug是如何出现的
正如前面所说,程序员做的是"造房子"的事情。这件事完整的步骤分为3步。
-
与产品经理讨论并确定功能(确定一个可以实现的设计图纸)
-
将每个单独的元件抽象出来(确定施工方案)
-
将相关的元件实现并进行组合,完成建设(带上材料开始施工)
第一步,"与产品经理讨论并确定功能"主要是沟通,靠"看"和"理解"。
但是沟通本身是一个有损耗的过程,特别是在职责非常明确的组织中,产品经理啪啦啪啦讲了很多,到实际做的时候你必然还是会去翻阅需求原型、需求文档之类的重新理解一下。这个时候就是一个非常危险的时期。
比如像下面这个的答案是什么?

▲图片来源于网络,版权归原作者所有
答案是17?不对。
我猜你可能没注意到这些地方。

▲图片来源于网络,版权归原作者所有
为了让你有深刻的印象,这个举例可能比较刻意和夸张一些,但是我想在你的身边,由于没注意到或者理解有误的现象肯定很常见。
沟通是相互的,这锅只让程序员背的话的确太委屈了点。
第二步,"将每个单独的元件抽象出来"这主要是一个人抽象能力的体现。
但是抽象是啥?抽象是"透过现象看到本质"的能力,这个能力理论上是可以无限增长的。随着你对相关信息的掌握越多,这个能力会越强,会无限趋近于100%,但永远不会真正达到100%,因为没人知道怎么才算100%。
所以,当你具备的信息没那么多的时候,是不是就抽象的不是那么合理?不合理会导致什么?虽然不会直接产生bug,但是会更容易产生bug。但是人不都是需要经历这么一个成长的过程么?
可以说,精通一项能力的背后都是踩着无数的bug过来的。要么在来这个组织之前已经踩过了,要么在这个组织里踩。因此,前者的薪资也比后者高。
所以,如果过分苛求没有bug,等于是在扼杀每个人成长的机会,并且在透支未来的可能性。人会变得非常保守、不敢尝试新事物。
但是外部环境在不断变化,新事物总会被动的需要去接纳(技术的更新越来越快,趋势不可逆),然而对新事物的接受能力又得不到锻炼,一旦遇到这种情况,在接触新事物的时候会产生更多的问题(欠下的债总要还的)。
第三步,"将相关的元件实现并进行组合,完成建设"这就是实际的coding过程,而coding是一个主观的,完全由人主观掌控的事情。
人毕竟不是机器,不可能不犯错,就如前面提到的写文章的时候出现错别字一样。
可能你会说,有测试人员啊,测试的工作不就是通过逆向思维来给程序员查缺补漏吗?
的确是的,但测试的介入只是降低错误率,只是让不出现bug的概率小数点后多几位
,指望发现100%的问题还是不太现实的。至少在当下的条件下是这样,为什么呢?因为代码的本质是各种逻辑的组合。
比如,一个完整的业务流程有10个环节,每个环节有3种可能性,这是一个什么复杂度的系统?3 ^ 10 = 59049个分支(理论上存在的可能性数量),想要100%覆盖这些场景,付出的成本几乎是不可接受的。
然而我们实际的系统中遇到的个别场景甚至还要复杂的多。
其实每个正在运行的系统都有bug,包括我们每天在使用一些热门系统(玩游戏的小伙伴们肯定熟悉"卡bug"这个词)。只是这些bug有没有被执行到,有没有被发现,被多少人发现而已。
那么,我们只能举手投降吗?那倒不至于,办法还是有的。
减少bug的惯性想法
首先最容易想到的一点是,增加测试人员。
这也是最容易看得到的"成本"一种方式,毕竟招一个人就得支出一份工资啊。所以,增加测试人员这个方案是最不容易被老板们采纳的方案。除非你可以说服这个人力成本的投入小于获得的价值。
另外,这个方案其实还增加了沟通成本,沟通的「隐性成本」其实非常大,但是往往容易被忽略。(关于沟通成本,感兴趣的可以看我之前写的《就简单聊聊沟通效率问题》)
其次会想到的就是程序员代码写的严谨一点,仔细一点啊。这也是一种缺啥补啥的惯性思维。
先撇开到底能不能达到严谨一点,仔细一点的目的。那怕达到了,他会产生什么结果呢?可能是下面3种。
-
更多的条件验证
-
更多的单元测试
-
更多的抽象提炼
可以确定的是,这些工作会增加2样硬性的东西,投入的时间和整体的复杂度。时间很好理解,我们就来聊聊复杂度。
一个常识是,越简单的东西越不容易产生bug。比如1+1=2,出现bug的可能性无非就是加号写成来减号,1写成了4之类。但是,1+1=2,并且1*1=1,并且1/1=1,。。。等等这些验证条件越多,那么由于验证条件自身的错误而产生问题的可能性反而更多。
所以,代码的复杂度和产生bug的概率是成正比的,并且具有「边际效用递减」的效果。这就意味着,做更多的验证带来的收益会越来越小。

因此,这个方案哪怕真能执行到位,也不是一个特别好的方案。
那有没有相对靠谱一些的办法呢?有,但需要我们换一个角度来看待这个问题。