看清本质:程序员为什么会写Bug?

最近在思考研发团队质量的问题,我觉得这是个很有意思的问题,直觉上来看,bug 是程序员挖的坑,但从团队的角度来看,却不尽然,接下来我们做一个深入的剖析。

个人问题

程序员的个人能力和经验会有所差异,从人才梯队角度来讲,这是很正常的。当执行的任务难度超出个人能力或经验范围的时候,出 bug 的概率就会增加。

有意思的是,对程序员自己,这个出 bug 和修复 bug 的过程可以带来增加个人经验的正向收益。当然也不全是。说到这,我想给 bug 分两个类:高级 bug 和低级 bug。

当你发现程序员之间在兴奋地讨论如何修复某个 bug 的时候,这个 bug 往往是高级 bug。这种 bug 已经超出程序员目前的经验范围,但最终被发现和解决。

这就好比游戏中组团打 boss,一次次团灭后,最后 boss 终于倒下时候感受到的兴奋感。但对于那些低级 bug,程序员往往难以启齿,那是一些非常低级的错误,完全在经验范围内,但却还是出现的bug。

当一个程序员反复出现这样低级的 bug,那或多或少都有些写代码的坏习惯,比如忽视时区问题的习惯、没有处理 NPE 的习惯、不写 UT 的习惯等等。如果坏习惯问题不及时纠正,不仅会使自己的工作量长期增加,而且还会降低个人在团队中的竞争力!麻烦的是很多程序员都无法自己意识到坏习惯问题的严重性。

解决这类问题,最好需要建立完善的 readiness 机制,进阶式的技术培训机制,标准化的代码审核机制,通过流程和制度可以尽可能扼杀低级bug。

但对于高级 bug,需要有丰富经验的资深程序员,分享他们的经验,我觉得最好的方式是写成文章或者录成视频,这比组织一场现场分享要更高效,从公司角度,如果说花重金聘请的专家是一种投资,那把他们的经验在公司内部传承下来,这样才能带来长期的投资收益。

沟通问题

除了个人问题,对于强业务驱动的项目,沟通问题也是一种引发 bug 的主要因素。在组织结构复杂的大公司内部,这种情况特别明显。

首先,分工复杂多变,经常会出现找错对接人或者重复对接的情况,比如某模块,今天是A负责,过几天变成 B 负责,A 和 B 之间又缺少充分的交接过程,这会导致 A 和 B 对特定问题出现不一致的理解,最可怕的是多个人同时负责某个模块,对接的时候,他们各自会下意识地认为其他人会处理,然后就没了结果;其次,信息不对称,自上而下或是自下而上传达不及时、不到位,打个比方,需求方要一个苹果,层层 copy 不走样后,到程序员这里就成了番茄,最后出来的是一个绿色的产自新西兰的酸度为 5 的小番茄,而需求方实际要的是红色的甜度为 5 的新疆阿克苏大苹果!

沟通上的壁垒,其实是流程和制度上的不足。客观地说,程序员的沟通能力并不是他们的特长,当他们参与到这样的工作中时,他们要花更多的时间去学习沟通和适应环境,少部分经过这样历练的程序员可以脱引而出成为骨干或者 leader,而绝大多数带着挫败感艰难生存,这也确实难为了他们。

所以,完善的流程和制度是至关重要的。公司或者团队管理者需要尽可能想办法消除沟通壁垒,让程序员发挥他们最擅长的能力,从而减少因沟通不畅而产生的不必要的 bug。

量与质的动态平衡

我曾经观察过这样的数据,团队总工作时长和总 bug 数是成正相关的。这个结论也是显而易见的,一定期限内工作量的增加,势必会对质量产生一定影响。

当然,影响的程度和前面讲的两个问题有很大关系。但我想说的是,业务驱动的项目中,程序员用来使自己修炼技术功底的时间越来越少,这或许也让上述两个问题不断恶化,导致产生的 bug 数很难呈现下降趋势。可以理解的是,为赢得更多市场和用户,整个行业都处在一个紧迫的状态,明面上虽然不说,但实际上对程序员的要求也宽容到类似流水线上的一环。

但是,在这样的环境下,自驱力差的程序员,要么甘于现状,用“做得多自然错的多”之类的借口麻痹自己,要么错误地认为“苦劳”终可换取个人价值,但往往不断受挫、不断更换环境。

我们如何从有限的时间内,挤出足够的时间,来修炼自己的技术功底,这是程序员需要自己反思的。理解这点很重要,因为量的存在是这个行业造就的必然挑战,我们需要在这样的挑战下,与质找到一个平衡点,这个点并不是固定的,我们是需要在一段时间内,通过量来驱动质的不断提升。

总之,关注 bug 数量本身并没有太大意义,因为 bug 是必然会发生的,不管是团队还是程序员自己,应该更加关注从bug中能学到什么,然后改进自己,去迎接更困难的挑战。这个过程也就是解决前面提到的两个问题的动力。

逐渐消失的 Geek 精神

最后,我想抛出一个大胆且抽象的观点:具备 Geek 精神的团队,产生bug 的概率会相对较低。

我们来看一个简单的例子:

// Method A
String rsl = "";
for (int i = 0; i < 100; i++) {
    rsl = rsl + "this is message:" + i + "\n";
}
System.out.println(rsl);
// Method B
StringBuilder builder = new StringBuilder();
for (int i = 0; i < 100; i++) {
    builder.append("this is message:")
            .append(i)
            .append('\n');
}
System.out.println(builder.toString());

两种方法都有同样的输出,单看 coding 速度,前者可能快于后者,但是内行人一看,后者看起来更有水平。

事实上,真正体现水平的程序,需要充分考虑到可读性、健壮性、可扩展性、复用性、安全性、执行速度等等问题,这往往需要花费更多的时间去思考。

但正如之前所说,大环境对于互联网程序员的期望,更趋向于流水线上的一环,再加上对“结果导向”理论的字面理解,重视产出,忽略过程,导致现在很少出现那些乐于追求极致,饱含激情,具有 geek 精神的程序员。

Geek 本意富含贬义,但用在程序员身上,却被赋予“追求极致”的特有意义。“追求极致”是一种态度,一种程序员特有的价值观,是驱动程序员快速成长的意识,也是研发团队特有文化的表现。

对于一个需要长期可持续发展的技术团队,这样的团队文化的存在,就好比化学反应中的催化剂,可以优化产出,也可以让不可能的反应成为可能。所以,如果说团队能力决定产出质量,那质量的差异,本质上也许就是团队文化的差异。




☞“面向对象就是一个错误!”

☞程序员的浪漫,你值得拥有!
☞平均 15144 元、软件工程师占比最高,2021 年 2 月程序员工资最新出炉!
☞PHP、Python 竟上榜最慢的现代编程语言
点分享点收藏点点赞点在看

你可能感兴趣的:(编程语言,人工智能,java,项目管理,olap)