从敲下第一个字符开始,八阿哥(Bug)就是磨人的小妖精,形影不离,简直比真爱还要真爱。
随着项目的扩大,功能的增加,Bug出得越来越快,越来越多,Buglist变的越来越长。
慢慢地,项目的节奏明显变慢,Feature越来越难增加,Bugfix的时间越来越长,团队逐渐变得死气沉沉,原本温顺的程序猿变得暴躁,进而演变成团队成员流动性提高,流失率提高。
总结我个人的工作经验,以及参照业内的一些文章,这种变化的轨迹也非常典型。
1、一个新Feature会与已有的Feature产生联系,也会依赖于已有的组件。而这些旧Feature或组件,因为有Bug还没处理好,接口不稳定,行为不可控。一个依赖于不稳定的系统的系统,必然是不稳定的。
2、一个依赖于不稳定的组件而组成的系统,要让其相对稳定地工作,必然需要在其内部添加修正,也就是workaround。其内部逻辑,需要实现原本不应当自己来承担的逻辑。
3、前两步还会继续滚起来,继而演变成workaround的workaround的workaround。
这时候问题来了:原有的带Bug的组件,是否应该调整或修复呢?
这是一个两难的境地:
1、调整,那么workaround就会失效。workaround的workaround的workaround也会失效。
2、不调整,那么按照以往的步骤,一个新Feature的实现,需要对其所依赖的所有组件进行修正,节奏只会越来越慢。
当开发节奏变的缓慢,这是一个非常不好的征兆,因为一旦开发节奏变的缓慢,除非进行根本性的改变,否则只会越来越慢。这不是一种时间可以解决的问题。打个比方,一辆自行车,就算是全世界最好的自行车运动员来骑,比速度也比不过一辆汽车,比行程更是完全不能比。
而面临这个两难境地,决策通常有两种:
1、放慢、甚至停下步伐,回顾、整理以前的实现和需求,进而制定改进计划和方案。但这样会面临市场和用户的压力。
2、招聘更多的工程师来进行修复工作。前几天看到一个新闻,Facebook的iOS工程师有429个人。
这里着重讨论一下第二种方案,也就是大多数公司会采用的方案。
这种方案有效,需要建立在几个前提上:
1、Bug修复的速度,赶得上Bug出现的速度。
2、Bug修复的收益,大于成本。
这里先插入一段,一个有工作经验的工程师,从第一天进入公司开始,到他能贡献代码,需要经历多少步骤。
1、每个产品都有BaseCode,熟悉这个BaseCode的结构和逻辑,需要时间,少则1个月,多则半年,视具体项目大小而定。这段期间,看文档,和老司机聊天是主要工作。看代码的作用,可以说几乎为0。
2、经过了熟悉阶段后,可以进入到边角性的修复工作。一般从修复和主要功能无关的UI开始。
3、再过了一段时间,等工程师对产品的后台逻辑有了更深入的了解之后,就可以开始从事一些相对核心的主干功能的修复。
好比手术一样,一个主刀医师切你一条血管,只需要几秒钟。但他要知道切那条,怎么切,需要几年。
简单来说,一个有行业经验的新员工,从第一天加入公司,到他可以修复相对重要的Bug,中途至少,需要几个月的时间。
熟悉代码库的逻辑,有几个东西起着重要作用。
一、需求文档,但这个非常可能落后于进度;
二、实现的结构的描述文档,这个在国内的大环境下,就是呵呵呵呵,几乎没有;
三、老员工的口述,但由于进度逼迫,他们一般会用来处理非常紧急且致命的Bug,同时,由于他们是对整个项目最熟悉的人,最赶的任务,最迫切的任务,都会交给他们。
回顾一下上个问题,通过招聘更多的工程师,能解决Bug积累的问题的前提,有几个:
1、Bug修复的速度,赶得上Bug出现的速度。
2、Bug修复的收益,大于成本。
我们再来看看这两点能否被满足。
老成员一直保持高强度的输出状态,由于一直赶进度赶任务,没时间重构,没时间补文档,也没时间和团队的成员同步设计概况和进度。而新成员,因为对代码库的结构和功能预期不熟悉,所以无法有效地分担相对重要的开发和修复工作。更可怕的是,在不熟悉代码结构和功能的情况下,任何的修复,都可能引入更多的Bug。所以第一点,不能被轻易满足。
要熟悉一个乱糟糟的代码库,对比起一个结构清晰的代码库,更需要时间,项目越大,功能越多,这个时间就越长。而软件开发的成本,最大的开销,是人力成本。目前一个有3年工作经验的工程师的价格,按照目前市场的价格,至少至少1万元起。对公司而言,算上社保公积金等等,公司的开销至少1万5以上。假如一个这样的工程师,进入团队,熟悉一个代码库,需要3个月。3个月之后,他走不走,是否能了解清楚代码库,另说。也就是说,这个人要发挥作用,公司至少至少要花接近5万元。而这个项目本身值多少钱呢?影响客户有多少呢?
招更多的人来填坑,各位要不要拿出计算器计算一下成本收益呢?
是不是所有的Bug都需要被修复呢?这个问题的深层意思是,“Bug修复的数目,是不是越多越好”。
我的答案是“否”。大部分的Bug产生的原因,可以归入以下几类:1、需求描述不清,理解、实现有二义性;2、代码的变化,没赶上需求的变化;3、需求之间产生内在冲突,实现了A,就不能实现B。而需求的描述,很大部分又是以“看得见”的方式来描述的,说简单点,就是界面上、用户操作顺序上去描述的。而这又是很容易被修改的部分。“加个简单的按钮,这里默认值不对”,这种大多数可以归入1或2。这种Bug是产生得最多的,也是最容易修改的,只是需要时间去找到实现的细节。
需求间的冲突,这种是最难搞的。说实话,我觉得这种不能算入Bug,因为实现了A,就不能实现B,实现了B,就不能满足A,无论代码怎么写,都是错。这类Bug往往又是很多Bug的深层原因。
如果一味地追求Bug的修复数目,那么很容易得到一种情况,简单的表面的Bug抢着干,也频繁地出,深层的Bug没人赶动。如果把KPI考核引进来,把Bug的修复数目(而不是影响程度)作为一个比重不低的标准,问题会变得更加复杂。
需求间的冲突,在项目合并和对接的时候,会更容易暴露。
我最讨厌无底洞般的Bugfix的地方,在于根源性的Bug没人敢动,因为牵连甚广,而大多数的小修小补,并不会解决影响体验、或者是直接决定用户买不买账的的根源性问题。也就是说,虽然大家都很努力,但是并没有什么用,到头来只耗费了时间,能否感动自己还是一个未知数。
就拿Evernote为例,曾有几次我动过购买高级账号的念头,因为它的浏览器插件、Mac下的客户端,真的解决了我很多问题。但最终,阻碍我购买的,原因就一个:它的编辑器有Bug。这个Bug有多影响体验呢?举个简单的例子,我选定一些字,设置了格式,undo在redo,结果居然不一样?就更别说莫名其妙的锁进和空行问题了。Evernote放着这个编辑器不管,转而去开发协作,甚至加入了团队IM功能。只要分析一下,开发团队协作,无论怎么搞,归根到底还是要回到编辑功能上去。一个笔记软件的编辑器不稳定,你围绕着这个不稳定的编辑器,无论你周边做的多么成功,附带功能多么完美,用户并不买账。
而软件一但走到这个地步,说句不好听的话,很有可能回天乏力。
软件和建筑很类似,都有结构,有规模,都需要精妙的设计和准确的实现。区别在于,一个建筑工人不大可能轻易毁掉一动大楼的根基,而工程师,要毁掉一个软件的结构,只需要删掉一行。
软件项目是一个系统工程,尤其是在当下这个什么都联网的年代。因为一个软件的设计,需要考虑自身的需求,在互联网时代,更需要考虑他人的需求。一个软件的价值,在于它对数据的操控能力。这种操控能力,建立在需求、实现的条理性和精确性之上。而要得到这种条理性和精确性,需要用系统的眼光去看待问题。而系统,是不可能通过散沙般的组织方式得到的。
互联网的世界,是赢者通吃,弱者渣渣都没得剩。因为一切都联网了,联网需要标准和统一。
我一直提倡,不要盲头跑,如果出发的方向错了,跑得越快,错得越远。