无痛软体时程

译:Paul May 梅普华
编辑:Jeff Wang 王家麒
March 29, 2000
属于Joel on Software, http://www.joelonsoftware.com

去年十月,美国东北部充斥着一个名为Acela产品的广告。这是一列由波士顿开到华盛顿的新开快速火车。到处都是电视广告,大看板和海报。你会认为这么多广告一定创造出 一些 对Amtrak新快运服务的需求

可能会吧。不过Amtrak根本没有机会知道。Acela一延再延,结果整个行销活动在Acela服务推出前就结束了。这让我想起某位产品在推出前一个月被媒体大加赞扬的行销经理,他对我说:「真是大出风头!只可惜你还 不到这玩意!」

那些睪丸素过剩的自大狂游戏公司总喜欢在自家网站上夸称,下个游戏等「好了」自然就会推出。至于时程?我们才不要那讨厌的东西!我们是超酷的游戏程式师!大部份公司可没这种福份。问问莲花公司吧。他们的Lotus 123 3.0版初推出时需要用80286电脑,这在当时可不怎么普遍。结果就把产品延后16个月推出,努力让程式能在8086的640K记忆体限制下执行。等他们完成时,微软在Excel的开发上已经领先了16个月了,更讽刺的是那时候8086已经完全过时了!

在我写这篇文章时,Netscape的5.0版web浏览器几乎已经_拖了两年_ 。部份原因是他们下了个自杀式的决定,把所有程式丢掉重头开始。同样的错误已经让安信达(Ashton- Tate)、莲花以及苹果的MacOS成为软体历史中的灰烬。Netscape浏览器的占有率在这段期间由80%左右掉到大约20%,而且完全无法对竞争者有任何反应,因为他们最重要的软体产品已经被拆成1000片散落在地上,什么事都做不了。其他因素都不够看,光这一个烂决定就成为Netscape炸烂自己的核弹了。(Jamie Zawinski的世界闻名之怒详述了整件事)。

所以说你一定得定时程。 几乎没几个程式员想做这件事。以我的经验来说,绝大部份人都完全不订时程,直接做了才说。至于那少数几个有做的,多是因为老板一定要,只好敷衍着做一做,而且除了那些同时相信「软体专案一定会延误」及「幽浮」的上级管理阶层外,没人真的 相信 排出来的时程。

那么为什么没人要订时程呢?主要原因有二。首先是执行起来很痛苦。其次是没人认为值得做。明明知道排出来不准确,为什么要费事去做呢?大家都为时程一定是错的,而且时间过得愈久错得愈离谱,所以何必白费工夫呢?

下面提供一个简单无痛的方法,可以订出确实无误的时程。

1)使用微软Excel。 不要用像微软Project这种专门的程式。微软Project的问题在于它假设你要花大量时间处理相关连性(dependency)。所谓相关连性是指有两件工作,第一件工作必须在第二件工作开始前完成。我发现就软体而言,相关连性实在是很明显,完全不需要花工夫正式追踪。

Project另一个问题是假设你需要能按一个小按钮就「重新均衡调整(rebalance)」时程。这表示程式会重新安排把工作指派给不同的人。这就软体来说完全行不通。程式员是不能互换的。Rita的程式错误交由John来修正的话得花上好几倍的时间才行。另外如果你把负责使用者介面的程式员拉去处理WinSock问题,她会卡在那里花整个星期熟悉WinSock程式设计。重点是Project是设计给建筑办公大楼用的,不是写软体用的。

2)简单就好。 我用的时程表标准格式简单到你一定背得起来。一开始只要七个栏位就好了:

Painless_Software_Schedules.gif

如果开发人员不只一个,你可以让每个人有自己一个表,也可以加个栏位标出负责各项工作的人员。

3)每个功能应该包含多项工作。 所谓功能就像是在程式中增加拼字检查。增加拼字检查包含好几项程式员必须做的工作。排时程最重要的部份就是排出这个工作表。接下来是个基本原则:

4)只有实际要写该程式的程式员才能排出该项的时程。 任何由管理阶层排好时程交由程式人员执行的系统一定都会失败。只有实际执行工作的程式员才能找出完成功能所需的步骤。也只有这个程式员才能估计每个步骤所需的时间。

5)把工作分得很细。 要让时程真正产生作用,这可是最重要的一环。分好的工作应该是以_小时_ 计而不是以天计。(当我看到以天甚至以周为单位的时程,我知道这根本是玩假的)。你可能会认为把工作细分的时程只不过是_精确_ 一点而已。错!错得离谱!当你订时程时先由大项工作开始,然后再细分出细项工作,就会发现结果 完全不一样 ,而不光是精确一点而已。这样的时程出来的是_完全不一样的数字_ 。为什么会这样呢?

当你必须订出细项工作时,就得强迫自己实际地找出确实要进行的步骤。要编写_foo_ 这个副程式。要建立某些对话框。要读取某某档案。这些步骤都很容易估计,因为你以前写过副程式建过对话框,也读过某某档案。

如果你随便划分出大项工作(实作出文法修正功能),表示你_根本没有真正思考过要做的事情。_ 而如果你并未真正思考过要做的事情,根本就不可能知道需要多久才能完成。

依据经验来看,每项工作耗时应在2到16小时之间。如果时程上有项工作需要40小时(一周),表示细分得还不够。

细分工作还有另一个理由,就是能逼你_设计_ 那些要命的功能。如果你排了3周去做「Internet整合」这样的粗略功能,你就完蛋了。如果你必须找出 要写哪些副程式 ,就会逼自己把该项功能弄清楚 。因为被迫提早进行这种程度的规划,所以就能消除软体专案中大量不稳定的成份。

6)记录最初和目前的估计。 当你把某件工作第一次排进时程时,先估计所需时数并填入Orig[inal] Est[imate]以及Curr[ent] Est[imate]栏位中。当计划进行时,你会发现某件工作所需的时间比估计的更长(或更短),就可以依需要更新Curr Est栏位。这是由错误学习并教育自己准确估算工时的最佳作法。大部份程式员并不知道如何估计工时。这是不要紧的。只要你持续学习并随时更新时程,时程就会确实作用。(你可能必须削减功能或延期,不过时程本身还是能运作无误,它会一直提醒你该砍功能或是必须延期了)。我发现大部份程式员只要一年工夫就能排出很好的时程。

当某项工作完成时,Curr Est栏的值会和Elapsed栏一样,而Remain栏会变成0。

7)每天更新耗时(elapsed)栏。 你不用真的看着马表写程式。只要在回家前或钻到桌下休息前(如果你是_那些_ 疯子之一的话),假装自己已经工作8小时(哈!)并列出所做的工作,再把8小时分配好填入工作对应的耗时栏中。Excel会自动计算剩余栏的内容。

同时还要依据现实状况更新各工作的Curr Est栏。每天更新时程应该只需要约两分钟 。所以才会说这是无痛的时程排法-快速又容易。

8)加上国定假日,休假等等项目。 如果整个时程耗时约一年,每个程式员可能会休10到15天的假。时程中应该加一项叫「休假」的功能,用作国定假日或其他会消耗人们时间的事情。这样就可以把剩余时间加总起来除以40(就是考虑一切之后的所需工作周数),计算出出货的日期。

9)把除错时间排入时程! 除错是最难估计的。回想一下你前一个专案。除错所占的时间很可能是把程式写出来的一到两倍。所以时程中一定要加这一项,而且这有可能是最大的一项。

实际的作法如下。让我们假设一位开发人员正在做某件工作。Orig Est是16小时,不过到目前为止已经用了20小时,而且恐怕还要再做10小时。所以开发人员在Curr Est和耗时栏分别输入30及20。

等到达里程碑(milestone)时,这所有的「落后」加总起来可能会有相当数量。理论上为了因应这些延误,我们必须削减功能才能准时上市。幸运的是可以削减的第一项功能就是名为缓冲(buffer)的功能,而这个项目一开始就排了很多工时。

原则上,开发人员会在写程式时除错。程式员在应该除错时绝对不该写新程式。基于两项原因,随时都应该让错误数目尽可能的少:

1)在写出程式的同一天除错会比较容易。如果一个月后当你忘记程式运作细节时再来除错,就会变得非常困难而且要花很长的时间。

2)修正错误就像科学活动。不可能估计何时能有发现并解决问题。如果随时都只有一两个主要的问题,表示未来无法估计的项目不多,所以很容易估算产品推出的时间。反过来说,如果主要的问题有几百几千个,根本就不可能预测什么时候才能把问题全部修好。

如果开发人员总会在写程式时就把问题修好,为什么还要加上除错项目呢?有道理,不过即使在写程式时尽量修好所有的问题,在到达里程牌时,测试人员(内部或外部)总还是会找到真正 困难 的错误,难免要有许多除错的动作。

10)把整合时间排入时程中。 如果你的程式员不只一位,难免会有两人不一致的事情需要协调。他们会各自建立功能近似的对话框,这当然需要协调。必须有人细查所有功能表、键盘快速键、工具列工具等等,并且整理及组织所有大家不得不加的新功能表项目。另外只要有两个人把程式登入就会出现编译错误。这也得有人修正,而且应该列入时程。

11)在时程中加上缓冲时间。 事物总是容易用完。你可能要考虑两种重要的缓冲。第一种:预防工作耗时超过预期的缓冲。第二种:针对未预期但必要的工作的缓冲(这通常是因为管理阶层决定某功能超级重要,绝对不能等到下一版)。

你可能会很惊讶地发现、休假、国定假日、除错、整合还有缓冲时间加起来超过实际做事的时间。如果被吓到表示你程式写得还不够久,不是吗?你要忽略这些项目的话后果自行负责。

12)绝对不要让经理叫程式员缩减估计时间。 很多菜鸟软体经理认为能用精细「紧密(短得不切实际)」的时程,「激励」程式人员做得更快。我认为这种激励根本是脑袋坏掉。当我进度落后时,我会觉得内疚消沉毫不积极。当我进度 超前 时,会非常快乐而且充满生产力。时程可不是玩心理游戏的地方。

如果你的经理要求你缩短估计时间,这里告诉你要怎么做。在时程表上加一个叫Rick的估计 (当然是假设你叫Rick)的新栏位。把你的估计填进去。随便经理怎样要求,直接把她定的时间填入Curr Est 栏位后就不要管了。等专案经束时再看看谁的估计比较接近实际状况。我发现光是_威胁_ 说要这样做,效果就很惊人了,特别是当你的经理了解到,他们刚参加了一个看你能做得多_慢_ 的竞赛时更是有效!

为什么不适任的经理们总会试图要程式员缩短估计时间呢?

当专案开始时技术经理会去见经营人员,然后会得出一个他们_认为_ 三个月(实际上要9个月)做得到的功能列表。如果你认为写程式不需要先想清楚所需步骤,然后估算出来某工作需时_n_ ,实际上很可能会耗时超过3 n 。在订定真正的时程时,把所有工作加总起来,就会了解专案耗时远比想像中多得多。欢迎光临真实世界。

不适任的经理的处理方法是想办法让员工做得更快。这一点其实不太实际。你或许能雇用更多员工,不过他们需要时间适应,可能前几个月都只有一半的效率(还会拖慢必须引导他们的其他员工)。而且无论如何,在这个业界得要6个月才找得到好的程式员。

你可能可以让员工在一年内全力以赴, 暂时 提高10%的初版程式(译注:指未整理除错的程式)产量。算不上是什么大跃进,而且这样有点太短视了。

你可能可以恳求员工不计辛劳超努力地工作,提高20%的初版程式产量。砰!可惜除错时间_倍增_ 了。真是了不起的自爆蠢方法。

不过你绝对绝对不可能由_n_ 变成3 n ,如果你自认有这种本事,请写信告知贵公司的股票代码好让我放空。

13)时程就像积木。 如果你有一堆积木,积木太多塞不进箱子里。这时候你只有两个选择:找个大点的箱子或拿掉一些积木。如果你认为能在6个月内完成出货,可是时程上排的却是12​​个月,同样的也只能延后出货时间或是删掉部份功能。积木是不能压缩的,如果你自认为可以,那只不过是在骗自己,徒然让自己失去一个真正能 展望未来 的好机会。

另外要知道,如此维护时程还有其他好处,就是能逼你自己 删除功能。为什么说这是好处呢?假设你有两个功能:其中一个非常有用而且能让产品变得超棒(比如Netscape 2.0里的table),另一个很容易而且程式员很想写(如BLINK标签),不过却啥用处也不具备市场价值。

如果你不订出时程,程式员会先做简单/有趣的功能。然后等时间用完时你完全没得选择,只能延后时程来完成有用/重要的功能。

如果你在开始作业前就排出时程,就会了解必须削减某些项目,自然会把容易/有趣的功能砍掉而做有用/重要的功能。这样子强迫自己削减某些功能,就能完成更强更好的产品,不但功能更好而且又更早推出。

我想起Excel 5的制作。我们最初的功能列表非常庞大,远远_超出_ 我们的时程。我们都在想:天啊!这些_全都是_ 超级重要的功能!没有巨集编辑精灵我们怎么活得下去呢?

结果是我们没得选择,所以只好配合时程把功能删到不能再删。每个人对于削减功能都很不爽。为了安抚自己的感觉,我们只好告诉自已说这不是在_删除_ 功能,只不过因为这些功能没那么重要,所以_延后_ 到Excel 6而已。

当Excel 5几近完成时,我和同事Eric Michelman开始写Excel 6的规格。我们坐下来审视由Excel 5删除移过来的「Excel 6」功能列表,当我们发现这些被删除的功能烂极了时真的是被吓到了。里面竟然_没有一项_ 值得做。我认为即使是接下来的三个版本,也完全没有必要制作这些功能。配合时程削减功能是我们所做过最好的事。如果我们没有这样做,Excel 5可能会耗双倍时间而且包含50%无用的垃圾功能。(我绝不怀疑这就是Netscape 5/Mozilla现在的状况:他们没有时程也没有明确的功能列表,没有人愿意削减功能,所以永远无法推出。等他们能推出时,里面会有很多IRC用户端等根本不该做的无用功能。

附录:你该知道的Excel二三事

用Excel管理软体时程如此好用,原因之一就是对大部份Excel程式员而言,Excel的唯一用途就是维护软体时程表!(只有少数程式员会用沙盘推演(what- if scenario)规划的方式做事的…这些程式员!

共用列表 利用档案选单的共用列表命令可以让大家同时开启并编辑档案。由于整个团体应该会持续更新时程,这个功能帮助很大。

自动筛选 这是个筛选时程的好方法,举例来说,你可以只检视所有指派给你的功能。再加上自动排序功能,就能依优先度顺序检视所有指派给你的功能,这实际上就是你的工作清单。够酷吧!

枢纽分析表 这是个检视摘要及多重汇总表格的好方法。举例来说,你可以做一张图显示各优先度下各个开发人员的剩余时数。枢纽分析表就实在是个大创新。你一定要学会怎么用枢纽分析表,因为它能让Excel增强一百万倍。

Excel分析工具箱中的WORKDAY函数 是个在无痛时程中计算日历天数的好方法。

有关本文的Q &A:Juggling Tasks in Excel

这些网页的内容为表达个人意见。
All contents Copyright 1999-2002 by Joel Spolsky。All Rights Reserved。