现代软件工程讲义 8 软件的血型

[这是 现代软件工程讲义 的一篇]

一个软件团队经历了计划/设计/开发等阶段, 达成代码完成 (Code Complete) 这一目标,似乎后面的事情就水到渠成了.  其实不然, 软件生命周期的最后阶段往往是最考验团队的,不但考验团队项目管理水平,应变能力,也考验团队的血型。 原计划的软件发布时间快到了,但是软件还是有这样那样的bug,怎么办?

优秀的软件团队会发布有已知缺陷的软件么?

我觉得和人类血型类似,软件团队的“软件血型”也可以分4种:

    A型:他们知道优秀的软件公司会发布有已知缺陷的软件;

    B型:他们不相信这一点;

    O型:他们不知道这一点,因此嘴巴惊讶成O型;

    AB型:他们对于自己开发的软件是A型,对于别人开发的软件是B型。

 

B型的人会发现搞软件开发是很痛苦的事。要说明的一点是,所有软件公司都希望能够把缺陷都改正了才发布软件,但是第一什么叫“缺陷”?如果只是一些无关大局的问题,用户可以绕过去的,我们非得马上解决么?第二什么叫“改正”?如果改正的方案中又有“缺陷”怎么办? 做商用软件的人都在为此苦恼,只有优秀的软件公司能找到一个平衡点,及时发布能够解决用户问题的软件,并且能及时修改软件中的问题——注意,这两个“及时”并不一定是同一个时间。做“大作业”的软件(比如为了演示、交作业)可以不用管这两个及时,交了卷,就万事大吉了。

说到“质量”,我们不提“全面质量管理”,因为“全面”之后,会出现“大道废,有仁义”的现象,大家都讲“全面质量管理”,往往意味着我们的质量管理没有抓到点子上。而且有些庸人往往会以“高质量”为由,阻碍正常的工作进程。而那些口口声声要求“高质量”的人士,往往是出于下列情况:

    a) 缺乏对用户、行业、软件开发的洞察力,对于“高质量”并没有具体的定义。

    b) 没有具体的招数让软件达到所谓的“高质量”。

    c) 害怕真实世界的反馈,因此不发布软件,能拖一天是一天。

 

可以看看这两个例子, 推断出这些团队的血型:

    STG 游戏的跳票 (为了完美,推迟了 7 天,但是7天之后也没有发布…)

    英语学习软件  (说了 “明早发布”,但是明早一直没到)

有些同学会马上举出世界有名的公司推出完美软件的例子, 例如苹果, 永远的毁灭公爵等等…. 请问: iPhone 的第一个版本是完美的么?  它连 复制/粘贴 的功能都没有

 

那么,从软件的Code Complete 到最后发布, 我们要经历哪些步骤,有哪些招数让我们能以比较大的共识,比较小的痛苦走完这血腥的流程,需要什么样血型,血性的团队才能按时推出优秀软件?

 

首先看看一些常用的名词:

Alpha: 指集成了主要功能的第一个试用版本。有些小功能并没有实现。事实上很多软件的Alpha版本只是在内部使用。给外部用户使用的版本会起一个比较美妙的名字,Technical Preview, 等等。

Beta: 功能基本完备,稳定性较Alpha版本高,用户可以在实际工作中小范围使用,可以有Beta1、Beta2、Beta3……

ZBB(Zero Bug Build): 某天的版本要把在48 小时前记录的bug 都解决掉。

RC(Release Candidate): 发布候选版本,RC1、RC2……直到RTM为止,版本间隔时间较短。

RTM(Release To Manufacturer): 最终发布版本。如果某一个RC版本没有很大的问题,那么这一RC就会成为最终的版本, 通常情况下,软件公司会把最终的版本和相关的文件及其他资料交给另一个团队(Manufacturer)去包装、刻软盘、光盘。在AppStore/MarketPlace 的年代 , 我们有相应的 RTM (Release To Market)。

RTW(Release To Web): 和RTM类似,对于网络应用来说,我们无须依赖“Manufacturer/Market”来制造软件的光盘或者管理软件的发布渠道,但是我们要依赖“Web”来发布我们的最终版本。如果软件产品是一个网站服务,那软件系统一般会交给网站运营团队(Operation Team)去管理,这样的发布也可以叫做RTO(Release To Operation), 运营团队和研发团队一起决定什么时候系统上线(Go Live)。

 

image

 

会诊小组(Triage  Team)

软件团队的各个角色代表 (pm/dev/test/UX 等) 组成会诊小组。处理每一个影响产品发布的问题。 打个比喻, 就像医院的门诊或急诊室 (Triage Room), 如果一下蜂拥进来好多病人,  但是医院里人手和设备有限, 值班的医生护士要根据病人的情况安排。  另一个类似但比较紧急的场景是,  在战地医院里,  两次战斗的间隙, 医护人员冲上硝烟尚未散尽的战场搜救伤员,  有些做简单包扎即可, 有些要抬担架, 有些伤情太重的, 只好放下不管了。 大家的血型和勇气在这一次次的triage 会议中得到了展现。 下面的招数都是在会诊小组的领导下进行的。

对于每一个bug, 会诊小组要做出下面的决定:

  • - 修复
  • - 设计本来如此 (as designed)
  • - 不修复 (won‘t fix)
  • - 推迟 (postpone)    //如果我们的软件是真正解决用户问题的, 是有价值的,那它一定会有下一个版本。

 

招数: 设计变更(Design Chang Request)

经过Alpha / Beta阶段,移山团队收到了不少用户的反馈,有些是意料之中的,有些是意料之外的。大家都看到,原来的设计也有不少要改进的地方。有了用户反馈,大家也能够取得比较一致的意见。另外,大家也有了很多新想法。一时间,众说纷纭,很多人都嚷嚷着——DCR,DCR!

重写或者是重构

小飞:我们的某某模块真是太烂了,我觉得必须重写,而且现在又有了新的技术叫 “我佩服”(WPF) [或插入任一最近时髦的技术],它能做很酷的效果,为什么不呢?

二柱:我们先要看看,原来烂到什么程度,现在是否能完成功能?你所说的问题有多严重?是功能不能实现?或者界面有问题?或者不能扩展(例如:不能支持更多用户)?

大栓:另外,是重构,还是重写?

重构——在尽量保持原有界面的基础上优化部分代码。

重写——重新实现原有功能,同时,要分清是全部重复原有功能,还是偷偷加上许多新的功能(Feature Sneak)?

小飞:咱们找领导去,超总,看看我新写的功能。

阿超:你不是在修理这个模块的 bug 么?怎么开始写新的功能了?

小飞:对,但是你是不是觉得我加的这个新功能很酷,嗯……现在是有点慢,但是如果数据库再做一些对应的修改,比如增加一个缓冲之类的,那就更好了。

阿超:用户提到了这个功能么?这和我们项目的远景有什么关系?数据库修改后,原来的用户数据要如何迁移到新的Schema下面?

小飞:嗯,但是用户如果看到了,就会喜欢的。

阿超:很多程序员有这样的冲动,在做修改的同时,想到自己还能做更多的事,有一个“东西”一直想做,但是提出几次都没人重视,那现在有机会,就 “加进去” 算了。或者还有很多灵机一动的想法。打一个比喻——本来是要修厨房顶上一个有时漏水的水管,结果修理工来了,修好了水管,同时灵机一动,加了一个带淋浴的豪华卫生间。

小飞:但这毕竟是新的想法,我以为你会喜欢的。

阿超:记住我们在项目的当前阶段是一个阻尼振荡的过程,要收敛和稳定。等到下个版本开始的时候再进行发散的思考吧。如果你觉得目前的设计有问题,我们要用DCR 来管理。

对所有提出来的问题都列表(标题注明 Beta Feedback),阿超给大家列出了DCR的要点:

(1)如何提出DCR?

        a. 在提交一个DCR的时候,选用任务作为工作件类型,并在标题中标明:DCR。

        b. 在DCR的描述文字中,说明:

                i. 问题在哪里,问题的影响;

                ii. 如果不做修改,会有什么后果?

                iii. 几种修改的方案,各种方案的优缺点,以及成本。

(2)如何决定DCR的执行次序?

            a. 会诊所有DCR。

            b. 按照影响、成本排序,得到一个自上而下的名单,根据现有资源,按照名单执行。

另外, 适合在Beta分支实现的修改并不一定适用于主分支(Main Branch), 我们要做好源代码管理。

 

招数: ZBB

团队要有把bug 都搞定的执行力。ZBB = Zero Bug Build,即这一版本的构建把所有已知的Bug都解决掉了。

Zero Bug Bounce:通常在一个Zero Bug Build之后,Bug数目会以惊人的速度反弹,故称Bounce。系统要经历几次bounce,像阻尼震荡一样,Bug的数目在反弹了几次之后,最后固定在(或者无限逼近于)0。

要注意必须要保证Bug的数量到0,以防止一些问题拖而未决, 有些bug 长期拖而未决,  其实它们掩盖了深层次的设计问题, 要早把这些问题暴露出来, 而且划定一个时间期限, 一定要解决。

下图是一个60人的团队的“预想ZBB 进军图”。每个小组的Bug数量累加起来,就是团队的Bug总量。下图中的黑线表明修复的Bug总量。

clip_image002

项目ZBB = 此次构建中所有两天 (48 小时)以前报告的缺陷都已经处理。

移山公司的例子:

第一个ZBB达到了,同时产生了一个ZBB 的构建,由于这个构建质量很好,因此测试团队铆足了劲把各个部分都测试了一遍。同时也测试了复杂的场景,进行了效能和压力测试。结果报告出来不少新问题。因此ZBB 之后的 Bounce 就跳得特别高。第二次ZBB 后,由于各个模块质量的提高,这一次的反弹就低很多,随着每次ZBB 过程中质量的加强,Bug 的数目会越来越少。同时也有几个功能被砍掉,这些功能的Bug 也就不计入总数。下面ZBB 的趋势图显示了Bug 经过几次反弹,逐渐到0的情况。

clip_image002[4]

图15-9 bug ZBB趋势图,横坐标是构建的版本号

 

招数: 砍掉功能

有一个模块看来不能实现预期的设计需求,时间快到了,怎么办?

砍!

芸芸:可是我们花了很多心血才把设计做到目前的地步,好像再努一把力,就可以成功了。现在撤退,我真是不忍心呀,这不是浪费以前的投入么?

果冻:对呀,我们可能只需要额外的三天,不,只要额外的三个通宵就可以了。再说我们可以以后接着修复任何新问题。

阿超:这些话好像有理,但是细一想,都没道理。芸芸,你听说过  “沉没成本(Sunk Cost)”  这个词没有?没有的话,应该上网查一查,好好学学。果冻,从你做事的历史来看,如果类似的功能需要N个单位时间才能最终完成,那么我们没有理由相信新功能会花少于N个单位时间。我们再回顾一下以前看过的功能/资源/时间的平衡图, 我们要不断保持这些因素的平衡:

 

image

 

招数: 修复bug 的门槛逐渐提高

在beta 期间,  修复bug 的门槛要逐渐提高,  昨天修复了同样类型的bug, 今天如果还找到了类似的问题, 团队未必要修复。 在RC 阶段, 只有影响巨大的bug 才能修复。 其它优先级较低的的bug 就只好在一边等着。 如果有严重的bug 要修复, 那么这些不严重的bug 也许有机会跟着一起修复。

在alpha 阶段, 如果开发人员拿到一个bug, 那他/她 就可以马上去修复, 只是在签入之后告诉大家做了什么样的修改。

在beta 阶段, 在新代码签入之前, 就要告诉会诊小组这个修改潜在的风险是什么, 如何应对,等等。

在RC 阶段,  开发人员拿到 bug 进行修复工作之前,  就要和会诊小组沟通,  看看这个bug 是否值得花时间。

 

 

 

 

招数: 逐步冻结

随着程序功能的完善,我们要让程序的各个方面有次序地“冻结”,这样才能把稳定的软件交付给用户。一般来说,程序的人机交互界面最先开始“冻结”,不能再随意修改,因为很多项目的文字信息要被本地化成多种语言,当人机界面所用的文字和排版(layout) 固定后,我们才能把这些文字交给负责本地化的部门。随着时间的推移,一些功能也可以“冻结”,这些功能都经过全面测试,所有的Bug 都解决了,功能进入稳定状态。在下一个版本前不要再碰和此功能相关的代码。如果有新的功能要写怎么办?  那就把源代码分支 (fork), 在新代码分支里开发下一个版本的功能。

 

[注: 大部分内容来自 移山之道]

 

posted @ 2013-01-03 12:41  SoftwareTeacher  阅读(2866)  评论(5编辑  收藏  举报