# 九、轻松制订软件进度表 去年十月,美国东北部充斥着一个名为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’s世界闻名之怒详述了整件事). 所以说你一定得定时程.几乎没几个程序员想做这件事.以我的经验来说,绝大 部份人都完全不订时程,直接做了才说.至于那少数几个有做的,多是因为老板 一定要,只好敷衍着做一做,而且除了那些同时相信〃软件项目一定会延误〃及” 幽浮”的上级管理阶层外,没人真的相信排出来的时程. 那么为什么没人要订时程呢?主要原因有二.首先是执行起来很痛苦.其次是没人 认为值得做.明明知道排出来不准确,为什么要费事去做呢?大家都为时程一定 是错的,而且时间过得愈久错得愈离谱,所以何必白费工夫呢? 下面提供一个简单无痛的方法,可以订出确实无误的时程. 1)使用微软Excel.不要用像微软Project这种专门的程序.微软Project的问题 在于它假设你要花大量时间处理相关连性(dependency).所谓相关连性是指有 两件工作,第一件工作必须在第二件工作开始前完成.我发现就软件而言,相 关连性实在是很明显,完全不需要花工夫正式追踪. Project另一个问题是假设你需要能按一个小按钮就〃重新均衡调整 (rebalance)”时程.这表示程序会重新安排把工作指派给不同的人.这就软件来 说完全行不通.程序员是不能互换的.Rita的程序错误交由John来修正的话得花 上好几倍的时间才行.另外如果你把负责用户接口的程序员拉去处理WinSock问 题,她会卡在那里花整个星期熟悉WinSock程序设计.重点是Project是设计给建筑办公大楼用的,不是写软件用的. 2)简单就好.我用的时程表标准格式简单到你一定背得起来.一开始只要七个字 段就好了: 如果开发人员不只一个,你可以让每个人有自己一个表,也可以加个字段标出 负责各项工作的人员. 3)每个功能应该包含多项工作.所谓功能就像是在程序中增加拼字检查.增加拼 字检查包含好几项程序员必须做的工作.排时程最重要的部份就是排出这个工 作表.接下来是个基本原则: 4)只有实际要写该程序的程序员才能排出该项的时程.任何由管理阶层排好时 程交由程序人员执行的系统一定都会失败.只有实际执行工作的程序员才能找 出完成功能所需的步骤.也只有这个程序员才能估计每个步骤所需的时间. 5)把工作分得很细.要让时程真正产生作用,这可是最重要的一环.分好的工作 应该是以小时计而不是以天计.(当我看到以天甚至以周为单位的时程,我知道 这根本是玩假的).你可能会认为把工作细分的时程只不过是精确一点而已.错! 错得离谱!当你订时程时先由大项工作开始,然后再细分出细项工作,就会发现 结果完全不一样,而不光是精确一点而已.这样的时程出来的是完全不一样的 数字.为什么会这样呢? 当你必须订出细项工作时,就得强迫自己实际地找出确实要进行的步骤.要编 写foo这个子程序.要建立某些对话框.要读取某某档案.这些步骤都很容易估 计,因为你以前写过子程序建过对话框,也读过某某档案. 如果你随便划分出大项工作(实作出文法修正功能),表示你根本没有真正思考过 要做的事情.而如果你并未真正思考过要做的事情,根本就不可能知道需要多 久才能完成. 依据经验来看,每项工作耗时应在2到16小时之间.如果时程上有项工作需要40 小时(一周),表示细分得还不够. 细分工作还有另一个理由,就是能逼你设计那些要命的功能.如果你排了3周去做 “Internet整合〃这样的粗略功能,你就完蛋了.如果你必须找出要写哪些子程 序,就会逼自己把该项功能弄清楚.因为被迫提早进行这种程度的规划,所以 就能消除软件项目中大量不稳定的成份. 6)记录最初和目前的估计.当你把某件工作第一次排进时程时,先估计所需时 数并填入〇「ig[inal] Est[imate]以及Cu「「[ent] Est[imate]字段中.当计划进行时,你会发现某件工作所需的时间比估计的更长(或更短),就可以依需要更新 Cu「「Est字段.这是由错误学习并教育自己准确估算工时的最佳作法.大部份程 序员并不知道如何估计工时.这是不要紧的.只要你持续学习并随时更新时程, 时程就会确实作用.(你可能必须削减功能或延期,不过时程本身还是能运作无误, 它会一直提醒你该砍功能或是必须延期了).我发现大部份程序员只要一年工夫 就能排出很好的时程. 当某项工作完成时,Cu「「Est栏的值会和Elapsed栏一样,而Remain栏会变成0. 7)每天更新耗时(elapsed)栏.你不用真的看着马表写程序.只要在回家前或钻 到桌下休息前(如果你是那些疯子之一的话),假装自己已经工作8小时(哈!)并 列出所做的工作,再把8小时分配好填入工作对应的耗时栏中.Excel会自动计算 剩余栏的内容. 同时还要依据现实状况更新各工作的Cu「「Est栏.每天更新时程应该只需要约两 分钟.所以才会说这是无痛的时程排法–快速又容易. 8)加上国定假日,休假等等项目.如果整个时程耗时约一年,每个程序员可能会 休10到15天的假.时程中应该加一项叫〃休假〃的功能,用作国定假日或其他会 消耗人们时间的事情.这样就可以把剩余时间加总起来除以40 (就是考虑一切之 后的所需工作周数),计算出出货的日期. 9)把除错时间排入时程!除错是最难估计的.回想一下你前一个专案.除错所占的 时间很可能是把程序写出来的一到两倍.所以时程中一定要加这一项,而且这 有可能是最大的一项. 实际的作法如下.让我们假设一位开发人员正在做某件工作.〇「ig Est是16小时, 不过到目前为止已经用了 20小时,而且恐怕还要再做10小时.所以开发人员在 Cu「「Est和耗时栏分别输入30及20. 等到达里程碑(milestone)时,这所有的〃落后〃加总起来可能会有相当数量.理 论上为了因应这些延误,我们必须削减功能才能准时上市.幸运的是可以削减 的第一项功能就是名为缓冲(buffer)的功能,而这个项目一开始就排了很多任 务时. 原则上,开发人员会在写程序时除错.程序员在应该除错时绝对不该写新程序. 基于两项原因,随时都应该让错误数目尽可能的少: 1)在写出程序的同一天除错会比较容易.如果一个月后当你忘记程序运作细节 时再来除错,就会变得非常困难而且要花很长的时间. 2)修正错误就像科学活动.不可能估计何时能有发现并解决问题.如果随时都只有 一两个主要的问题,表示未来无法估计的项目不多,所以很容易估算产品推出的时间.反过来说,如果主要的问题有几百几千个,根本就不可能预测什么时候 才能把问题全部修好. 图: [http://chinesetradjoelonsoftware.com/Images/Painless_Software_Schedules.gif](http://chinesetradjoelonsoftware.com/Images/Painless_Software_Schedules.gif) 如果开发人员总会在写程序时就把问题修好,为什么还要加上除错项目呢?有 道理,不过即使在写程序时尽量修好所有的问题,在到达里程牌时,测试人员 (内部或外部)总还是会找到真正困难的错误,难免要有许多除错的动作. 10)把整合时间排入时程中.如果你的程序员不只一位,难免会有两人不一致的 事情需要协调.他们会各自建立功能近似的对话框,这当然需要协调.必须有人 细查所有菜单,键盘快捷方式,工具栏工具等等,并且整理及组织所有大家不得不 加的新菜单项.另外只要有两个人把程序登入就会出现编译错误.这也得有人修 正,而且应该列入时程. 11)在时程中加上缓冲时间.事物总是容易用完.你可能要考虑两种重要的缓冲. 第一种:预防工作耗时超过预期的缓冲.第二种:针对未预期但必要的工作的缓 冲(这通常是因为管理阶层决定某功能超级重要,绝对不能等到下一版). 你可能会很惊讶地发现,休假,国定假日,除错,整合还有缓冲时间加起来超过实际 做事的时间.如果被吓到表示你程序写得还不够久,不是吗?你要忽略这些项目 的话后果自行负责. 12)绝对不要让经理叫程序员缩减估计时间.很多菜鸟软件经理认为能用精细” 紧密(短得不怍实际)”的时程,”激励〃程序人员做得更快.我认为这种激励根本 是脑袋坏掉.当我进度落后时,我会觉得内疚消沈毫不积极.当我进度超前时, 会非常快乐而且充满生产力.时程可不是玩心理游戏的地方. 如果你的经理要求你缩短估计时间,这里告诉你要怎么做.在时程表上加一个 叫Rick的估计(当然是假设你叫Rick)的新字段.把你的估计填进去.随便经理怎 样要求,直接把她定的时间填入Cu「「Est字段后就不要管了.等项目经束时再看 看谁的估计比较接近实际状况.我发现光是威胁说要这样做,效果就很惊人了, 特别是当你的经理了解到,他们刚参加了一个看你能做得多慢的竞赛时更是有 效! 为什么不适任的经理们总会试图要程序员缩短估计时间呢? 当项目开始时技术经理会去见经营人员,然后会得出一个他们认为三个月(实际 上要9个月)做得到的功能列表.如果你认为写程序不需要先想清楚所需步骤, 然后估算出来某工作需时n,实际上很可能会耗时超过3n.在订定真正的时程时, 把所有工作加总起来,就会了解项目耗时远比想象中多得多.欢迎光临真实世界. 不适任的经理的处理方法是想办法让员工做得更快.这一点其实不太实际.你或 许能雇用更多员工,不过他们需要时间适应,可能前几个月都只有一半的效率 (还会拖慢必须引导他们的其他人员工).而且无论如何,在这个业界得要6个月 才找得到好的程序员. 你可能可以让员工在一年内全力以赴,暂时提高10%的初版程序(译注:指未整理 除错的程序)产量.算不上是什么大跃进,而且这样有点太短视了. 你可能可以恳求员工不计辛劳超努力地工作,提高20%的初版程序产量.砰!可惜 除错时间倍增了.真是了不起的自爆蠢方法. 不过你绝对绝对不可能由n变成3n,如果你自认有这种本事,请写信告知贵公司 的股票代码好让我放空. 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函数是个在无痛时程中计算日历天数的好方法.