现代软件工程讲义 7 开发 开发阶段的日常管理

[移山之道 14 章]

14.6  开发阶段的日常管理

14.6.1  闭门造车(leave me alone

荔荔:我今天真失败!在办公室里坐了10个小时,但是真正能花在开发工作上的可能只有3个小时,然后我的工作进展大概只有两个小时!

阿超:那你的时间都花到哪里去了?

荔荔:就是我们以前说的 “我没看见你在写软件,你到底在忙什么” 上面列出来的破事儿。每一件随机事情看起来都是挺重要的,我就放下手里的开发工作。但是好不容易做完了,刚想进入状态,又一件随机事情来了……

阿超:你要硬着心肠,说 “不”。

当场景、功能都计划好的时候,要给员工足够多的时间,让他们投入到工作中去,而不要经常打断他们。

要尽量减少非开发时间,不要动不动就开“全体会议”。团队成员们自我时间管理也很重要。由于MSF鼓励沟通,TFS也设置了不少提示(Alert)自动报告全体成员项目各方面的情况,因此团队的E-mail会特别多。在这种情况下,不要整天被E-mail牵着鼻子走。在Outlook上设置好邮件规则,按下面的规则把邮件自动分类到不同的邮件夹中:

1)从直接老板来的,发给你一个人的—马上处理。

2)从团队成员来的、和项目有关的事情,自动分配到一个叫“Team”的邮件夹中。

3)从TFS来的状态信息,如团队的check-in email,自动分配到一个叫“Check-In”的邮件夹中。

4)从公司其他同事来的与工作无关的消息(如笑话,大减价的消息等),自动分配到一个叫“Other”的邮件夹中。

最好每隔两三小时集中阅读和回复一下E-mail

荔荔:河对岸的河曲数码经常把所有人都拉去做“封闭开发”,这样是否就能避免干扰?

阿超:我们做开发软件,并不是让团队像被关在监狱里一样。要有大家自由交流的时间,团队成员们在无拘束的环境中,会更乐意提问和分享,这会比召开正式会议,强迫每个人分享好得多。在“封闭开发”的情形下,领导也更有可能每天、每小时来询问项目的进度,这种团队内部的干扰源,并不会因为团队搬到一个监狱里而消失。大家还记得MSF的“充分的授权和信任”?

果冻:我这里还有笔记。

小飞:另外,我经常去看测试人员又发现了什么Bug,有时就花时间研究和修复它们。

阿超:可以等第二天会诊之后再看看是否值得马上修复。

果冻:这样新建的Bug要等到第二天门诊之后才能给开发人员处理,是不是会影响进度?

阿超:不一定。

提示:

1)开发人员在开发阶段最重要的任务是把规定的功能完成!

2)在项目初期,可以不用集体会诊,开发/测试人员可以直接处理“缺陷”,不必等待。

3)在任何时候,测试人员都可以把“缺陷”交给开发人员,但是只有会诊的人员才能改变会诊决定。

14.6.2  每日构建

阿超:我好像有几天没有收到每日构建(Daily Build)的报告了。

小飞:已经有一阵子 Daily Build 没成功了。

阿超:哦?我们上课的时候不是说过“每日构建”的重要性么?

小飞:我同意在我们有时间的情况下,要做每日构建,但是当工作忙的时候,我们的确实没有时间去管构建的问题。

阿超:这么说还是应了那句话——在理论上,理论和实践是一回事,而在实践上,理论和实践是两回事。

阿超指着窗外,河对面的工地。

阿超:他们在建楼房吧。

小飞:对,据说是软件学院的新大楼。

阿超:那,他们的脚手架自从搭好了之后,就没有垮下来过吧。

小飞:那当然不会,俺爹是干这一行的,所有的工人和材料都得运上运下,脚手架要搭得特别结实。

阿超:那你爹他们有没有因为工期紧,就凑合着搭个架子,就往上盖楼?或者脚手架倒了也不管?

小飞:那哪成!要倒下了,就要出人命了,哪还能盖楼?!

阿超:对呀,我们的软件构建,就和脚手架一样,每天都要立着,倒下来就麻烦了。

小飞:不过,我们搞开发的都有点不屑搞构建,没有写程序来劲。

阿超:不会建脚手架的小工,你爹会要么?

小飞:不会。

阿超:不会做构建的程序员,就像不会搭脚手架的小工,运球不熟练的球员。这样的程序员,我们也不要。

小飞:我明白了。

下午,阿超在喝水的时候碰到小飞来报告说Daily Build正在运行中。发现的几个错误都改正了。估计晚上就可以产生一个新的构建了。

阿超:了不起,这么快就做好了。

小飞:超总,我想提一个和我职业发展有关的问题。我们接受的可都是科班的软件工程教育,我们当时的院领导说我们毕业后都是要朝CTO发展的,至少是软件金领,我当然知道这是遥远的将来的事,但是我总觉得我至少可以做一个软件白领吧,这些构建之类的事情,嘿嘿,是不是要由所谓的软件蓝领来做?

阿超:问题提得好……

他望着这位将来的CTO、软件金领,突然想抄起身边的塑料水桶,把水都从他的白领里灌进去。他喝了一大口水,退到窗边,勉强把这个念头压了下去。阿超看着窗外的操场

阿超:听说你篮球打得不错?

小飞:还行,常和二柱几个玩。

阿超:你提到大学的课程,让我想起大学的篮球课。我们当时考试的科目之一是定点投篮。老师叫每个要考试的同学站在罚球线上,别的同学负责捡球,考生就站着不动,一个一个地瞄准了投,如果进了一个球,老师就开始算分。平时玩球的同学都是十个进七八个,连运动细胞不多的同学都是十个球中五个以上,皆大欢喜,好像大鲨鱼奥尼尔罚球也不过50%上下,大家都有NBA球星的感觉。另一个考试科目是两人配合上篮,当然这是在球场空荡荡的时候进行的,大家接//投一气呵成,颇有马龙和斯多克顿的风范,觉得篮球“技止此耳”!考试后,我们意犹未尽,和在一边玩球的同学打球赛,尽管我们“定点投篮”和“二人配合”的分数都很高,但是我们都输得很惨……

小飞:为啥?

阿超:因为我们运球、传球都不熟。这都是我们平时不屑练习的东西,即使勉强到了篮下,投篮都是在踉跄之中完成,当然没有考试时候的准星。

小飞:超总,您把我绕远了,您的意思是?

阿超:我觉得大学的软件工程课,本来要教全面的技术,但是考试往往只考定点投篮和无防守情况下的配合。所以有些大学的高材生到了实际工作中,很多“蓝领”的基本功,比如实战中的运球、传球都不灵,他们津津乐道的定点投篮十中八九的功夫也没有发挥的机会了。我还没有见过从天而降的白领或金领。所谓的大拿们都是从蓝领摸爬滚打出来的。换句话说,我眼里没有白领或蓝领,只有“汗领”——就是大家都得出汗干活。

小飞:你是说构建就像运球、传球……好,我明白了。超总,下班后我们球场见!

14.6.3  构建大师

头碰头会上,大家发现,最近连续几个构建都不成功,测试组都拿不到新的版本,没法进行测试。

阿超手里拿了小飞整理的“导致构建失败的失误列表”分送到每人手里,表上列举了错误的类型和导致错误的签入,以及牵涉的成员。

大栓:看来拿不到新的构建版本的原因有这些——

1)构建在开发人员本地机器上就不成功。

2)构建在本地成功,在服务器上失败。

3)构建在本地及服务器上成功,但是基本功能不能使用,导致无法进行测试。

阿超:试着对症下药,很多事情我们在培训时都讲过了——

1)强调基本开发流程(注意编译要产生deBug | release两个版本)。

2)签入时,必须从TFS同步下载所有最新的版本再编译,而且个人的签入要做成一个Shelveset,成为原子操作,而不能把一次修改中的所有文件分成几次签入。

3)这时,我们以前做的单元测试和构建验证测试(BVT)就要发挥作用了,每一个开发人员在签入前都要运行所有的单元测试和构建验证测试,确保没有问题后,才能签入。

我们要让团队中做事不仔细的人慢下来,这样能减少他们的危害。将欲取之,必先予之。阿超进而建议——

对于下一个导致构建失败的成员,授予“构建大师”(Build Master)称号,构建大师做下面的事:

1)负责管理构建服务器。

2)调试构建,负责找错,并分析出错的原因。

3)负责把“构建大师”称号和责任交给下一个导致构建失败的成员。

4)“构建大师”同时向团队的“腐败基金”存入50元,以供大家将来“腐败”之用(此项可选)

14.6.4  宽严皆误

上次头碰头会议后,各个小组都进一步强化了单元测试和BVT

下午,果冻发了一封E-mail,标题是“我受不了啦!”内容如下——

我的签入流程:

1)代码写好,本地测试通过,代码复审通过。可以签入了。

2同步TFS上最近更新,编译deBug | release,解决版本冲突(半小时)。

3)安装最新版本,运行本地单元测试,BVT(一个小时)。

4)提交到TFS上,发现有版本合并冲突,因为在第(23)步的时候,有人签入了和我的代码有关的新修改。

5)如果我简单地合并版本,并且签入,很有可能会导致TFS 上编译失败。但是如果我为了保证质量,在合并后,本地编译并运行各种测试,这相当于重复了第(23)步。当我再次提交签入(重复第(4)步)时,有可能碰到新的版本冲突。这样循环往复以至无穷……

二柱发了E-mail,第一句话就是:

在理论上,理论和实践是一回事,而在实践上,理论和实践是两回事。

然后也抱怨了类似的问题,似乎大部分时间都花在了没有价值的“同步/编译/验证/再同步……”的循环中。

荔荔:似乎应该在签出一个文件的时候,加上一个“防止别人签出”的锁,这样就没有冲突了。

果冻:但是如果你锁住了file1,要签出file2;与此同时,我锁住了file2,要签出file1,这样我们都进入了死锁……

小飞:我刚刚同步TFS,然后编译就不成功了。我在一台全新的机器上重新试了一次,也不行。这至少证明不是我引起的问题。现在我已经没法工作,只好到“顶球”喝两杯去了。谁把错误修好了,就给我发短信,我就回来上班。

阿超:除了构建大师,所有开发人员都可以到“顶球”去玩。

构建大师:我已经连续三天错过了午饭时间,谁能帮我从顶球带两个烧饼回来?另外,能不能不要在午饭前安排构建?要不然铁打的胃也受不了。

经过一个多小时的忙碌,构建终于好了,但是构建大师问阿超,现在构建成功了,明天呢?

阿超:让我想想……

阿超晚上把情况和同事们的意见报告了愚公,阿超在E-mail最后写道:

团队有两条路可以实行:

1)很严的规则和流程控制,这样会保证很高的签入成功率,如果一个人根据流程来做,几乎肯定能成功。这样构建质量高,但是团队的进展会受到限制。极端情况下,整个团队的进展被序列化为一系列个人串行签入操作。

2)宽松的规则和流程,每个人随时可以签出签入,签入时的成本很低,但是签入成功率不高,构建质量低,极端情况下,所有人都可以签入、同步,但是没有人能正常工作。

哪一种是最好的呢?

第二天一早,阿超就看到了愚公的回复:

不审势即宽严皆误,从来治蜀要深思。

阿超心想,那什么是我们这个团队目前的“势”呢?他根据每一个步骤,宽、严各是什么做法和当前团队的情况(势),列出了一个“宽”或“严”表,如表14-7所示。

阿超认为,当团队成员的行为只是影响到个人的时候,就尽量放松,让个人根据自己情况处理;当其行为影响到整个团队的时候,就尽量严格,因为整个团队都有可能会受影响。同时,我们要提高可预见性——明确构建大师的职责,公开显示固定的构建时间。

14-7  宽严表

步骤

签出

自由签出

签出时候,将文件上锁

很多人都会同时编辑同一文件

本地单元测试

不要求

要求

每个模块都要求写单元测试

本地check-in test(签入测试)

不要求

要求

BVT还没有完成

签入时间

任何时候

每天固定时间开放

目前签入情况很混乱

签入冲突处理

合并后即可签入

合并后,再重新编译,测试,再提交

重新测试会花费比较多的时间

签入必须经过代码复审

随意

必须

开放人员有一半是新员工,必须通过代码复审建立良好的规范

签入时必须运行代码分析工具

不要求

要求

代码分析工具尚未配置好

签入时单元测试必须同时签入

不要求

要求

每个模块都要求写单元测试

 

步骤

签入必须是多个相关文件同时签入

不要求,可以签入单个文件

要求

保证每一个签入都不会导致构建失败

签入必须和一个工作项关联

不要求

要求

所有的工作必须有工作项跟踪

设定专用网络服务,自动处理提交的ShelveSet、构建、BVT、然后签入代码

不要求

设置

需要很多人力来设计并维护

综上所述,移山团队目前的开发流程如表14-8所示。

14-8  具体流程

时间

总体

管理/程序

 

开发

构建大师

测试

8am~10am

开发人员可以同步代码,这时只有非常要紧的签入才能经过批准,签入TFS

9am

头碰头会议,Bug会诊,分配Bug

同步代码,构建,根据自己的任务Bug情况决定今天的工作

 

测试新版本,新建Bug

10am~12am

代码签入时间,经过正常代码复审及其他流程后,代码(连同单元测试)才能签入

程序经理组织必要的会议

单元测试
代码复审
同步/解决代码冲突
签入代码

准备构建服务器

 

12am~1pm

午饭时间

 

 

 

 

1pm~3pm

构建/安装/基本测试/宣布版本质量(见后)

 

待命,随时准备攻克问题

全程监督执行,负责把导致构建失败的缺陷(找人)修复并签入

运行基本测试

3pm~6pm

开发/测试人员继续工作

 

 

运行BVT后,宣布此次构建质量(失败/可测/可用)

聪明的测试人员此时就开始测试并报告缺陷

6pm

晚饭及机动时间

 

 

 

 


阿超:我特地把紧张的构建及待命阶段安排在午饭之后,这样大家至少可以安心吃饭了。

 

 

14.6.5  小强地狱(Bug Hell

在这一次的头碰头会议上,平时不主动发言的阿亨也说话了。

阿亨:开发的同志们,你们手里有那么多小强,为什么都揣着掖着,不舍得修复,让测试人员有事情做?测试人员反映因为现有的小强没有被修复,有越来越多的小功能点不能进行测试,我们都要没事做了。

大栓:我们的开发任务很重,必须先把新功能全部实现后,再修复旧的小强。

阿亨:这是不对的,我们有些小强在你们手头很久了,看似举手之劳,为什么不尽快修复,让我们测试组能继续完成测试?

二柱:我们都是按优先级来进行的,开发新功能的优先级远大于修复小强。

阿亨:但是有些开发人员手里头有二三十个小强,难道数量不是一个考虑因素?

阿超:我同意,随着项目的深入,每个人同时要开发新的功能,修复以前的缺陷。由于没有明确的优先次序,一般人都愿意把时间花在开发新功能上。但是我们的确需要平衡进度和质量。有这样的一种方法:

小强地狱(Bug Hell

如果开发人员的小强(Bug)数量超过一规定值,则此君被送入“小强地狱”,在地狱中,他能做的唯一一件事就是修复小强,直到小强数量低于此阈值。

这一阈值由团队根据实际情况来确定,要注意:开发人员同时“入狱”的人数应在全体成员的5%~30%之间,若比例太高,则要考虑阈值或小强数量的计算方式是否合理(是否只包括某一严重程度以上的Bug)。

在项目过程中,阈值不宜频繁调整,最好事先宣布阈值。

大栓:但是我们已经违反了“最好事先宣布阈值”这一规定。

阿超:如果我们现在要让20% 的同志入狱,需要马上运行一个TFS 查询看看这一个阈值是多少?是15?好,那我们现在宣布给大家三天时间,第三天后,小强数量达到或超过15 的开发人员请入狱,然后每天早上9点头碰头会议时统计并宣布入狱/出狱名单。

大牛: 其实先把所有的功能写完也不错,至少我可以告诉客户“功能写完了”,让他们高兴高兴。

大栓:大牛,这不就是咱们以前项目的情况么?你一直问“功能都写完了,为什么还不能用”? 我们一直说“还有一些小问题”,然后小问题总是不能解决,因为要真正解决这些“小问题”的话,我们还得重写一些功能。

阿超:对,很多问题,甚至是大问题,都隐藏在目前的小强后面,如果一味赶所谓的“进度”,到时候有些小强就变成了大怪物,因为我们已经在错误的基础上搭建了很多新的逻辑和功能,这时再来处理一些历久弥新的小强,就有投鼠忌器的麻烦。

阿亨:那怎么办?

阿超:我们要分析小强,看看这是一个小问题,解决了就万事大吉呢?还是冰山的一角,解决后也许会发现更多、更棘手的问题。或者看似不经意的一个小强会让很多人加班重新实现功能—这就成了设计变更需求DCR

14.6.6  DCR Tell mode v.s. Ask mode设计变更

在项目早期,如果大家觉得要做一个设计变更,可以用告知模式(Tell-mode)的形式,就是说,修改方必须通告所有关系人:“我在这里修改了某某界面。”但是修改方不必取得其他关系人(或者模块)的事先同意,就是说可以先行设计并编码。当然,如果其他关系人不同意,修改还是不能签入。

当项目进行到稳定阶段,Tell-mode 要改为请求模式(Ask-mode),这时,修改方必须先问“我是否可以在这里修改某某界面?”(当然还要有更详尽和充分的理由)得到肯定的答复后,才能进行修改。这时的默认回答是“不”。

14.6.7  每周进度报告——还有多少事没做完

头碰头会议。

大栓:我有一点不太放心……

大牛:哦,为啥?我们大家都干得很欢。完成任务应该没问题吧。

大栓:我们每天都在签入新的代码,每人都很忙,但是我总觉得不太对劲。会不会越做事情越多呢?

阿超:这时我们可以看看各种报表,首要推荐的是“Remaining Work”。

请看图14-2

这个报表告诉我们究竟还剩下多少事情要做。我们要分析这么多签入到底是否解决(Resolve)了相应的问题,如果是,那么我们的任务数量应该逐渐下降,但是从图14-2上我们看到深灰色的任务和缺陷还在缓慢增长。而浅灰色的“已完成任务”,却一动不动,这就要引起我们的注意了。

可以在报表设置控制板中,进一步选择你要报告的内容,如:Iteration,选择里程碑;Area,选择项目的不同部分,也可以修改报告的起始和终止日期等。

 

clip_image002

 

[注: VS2010 还提供了 burndown chart 等,  参加中科大同学的博客, 例如

http://www.cnblogs.com/OMG-Team/archive/2011/09/30/2196150.html]

什么叫代码完成(Code Complete[1])?

就是我们认为所有应该写的代码都写了,所有应该实现的功能都实现了。

那就是可以发布了?

不,代码都写了。但是代码中可能有很多小强,各个模块之间的合作还有很多问题。Beta用户看到产品后,说不定要提不少修改意见。但是,我们毕竟是把“我们认为所有应该写的代码都写了,功能都实现了”。这是一个了不起的事件。一个团队经过几个月的努力,从无到有,从简到繁,把几个月前的远景变成了可以运行的软件,也许我们还有许多问题,但这无疑是很值得庆祝的!

TFS上,就是所有的代码任务(Task)都完成了。也许我们现在还有许多缺陷(Bug),还有一些与测试相关的任务。这些事情要留到以后稳定阶段才能全部解决。

14.8  讨论

问:   每次里程碑结束后,我们向客户汇报的时候,客户总是会惊讶地说,某某功能不是我们当初商量的那样啊,而PM却也同样一脸诧异地说,不对啊,当时咱们就是这么说好的啊,有文档为证。客户不干了,威胁不加/不改xx功能就如何如何,这时PM该怎么办?

大牛:我们在合同里要写明到底我们要交付的是什么,这就要看PM的分析和说明能力了。有时要对客户说“不”。同时,我们在需求说明中也要从用户的角度去描述问题和解决方案,这样用户才能了解他们最终会得到什么。

问:   项目开发中后期,Dev lead用工具一统计,乖乖,足足xx万行代码,xx千个存储过程,可是每到给客户演示时,却不时出现程序的各个功能相互不配合,不能自圆其说的尴尬场景,Dev lead很郁闷,想想自己可是没少加班啊,代码量也够多,可是问题究竟出在什么方面呢?

阿超:一个原因是每个人都沉浸在“我要写出最强大的某某类或某某模块”,不停地优化一些没有人用的功能,但是真正能够为其他模块使用的功能却未能实现。他们忘了他们写的代码是给别人用的,而且是为了解决用户问题的。所以这个时候我们要想想“用场景驱动”的方法,保证典型的用户场景能够实现。如果从“场景”出发,各个模块的互相集成就能得到充分的测试,按照场景演示起来就更有保障了。

问:   在项目开始之前, 有很多队员还没有接触过编程语言(例如C#),导致PM在分配任务时很难用时间来衡量,就拿写一个Web Service这一模块来说,一个熟练的程序员可能只需要两个小时,而对于C#的初学者来说,就得先花两天来理解Web Service的实现机制和原理。在有限时间的催促下,导致一些紧急的任务不断向高手集中,而初学者的任务越来越少。这时应该怎么办?

阿超:对于这些队员,可以考虑在他们自己的任务估计值之上再乘以4。另外,如果你是写一个商业项目,请不要让连开发语言都没有接触过的队员进行开发工作。并不是非得 “写” 程序才是对项目有贡献,有时不写也有很好的贡献。如果他们有热情,就从测试开始学习吧。请参看前面提到的“大马哈鱼洄游模型”。



[1] 有一本很著名的书叫《Code Complete》,中文翻译为《代码大全》。事实上,此书不是各类代码的汇编“大全”。Code Complete(简称CC)是“代码完成”的意思。

posted @ 2011-10-30 13:49  SoftwareTeacher  阅读(2499)  评论(1编辑  收藏  举报