# 三、joel测试:改进代码的12个步骤 你曾经听说过SEMA吗? [1]它是一个相当深奥的系统,用于测试软件团队优良程度。不,等 一下!不要去读SEMA!要理解这个东西就得花大约6年的时间。因此,我自己提出了一套 不很严格的宽松测试来评估一个软件团队的质量。该测试的闪光之处在于它只需花费大约三 分钟的时间。将节省下来的所有时间利用起来,你就可以进入医学院了。 Joel测试 1. 使用源控制机制吗? 2. 能一步完成连编吗? 3. 每天都做连编吗? 4. 有故障信息数据库吗? 5. 在编写新代码之前修复故障吗? 6. 有最新的进度表吗? 7. 有规格说明书吗? 8. 程序员拥有安静的工作环境吗? 9. 你用到了你资金能力内可买到的最好工具吗? 10. 有测试人员吗? 11. 新聘人员在试用期写代码吗? 12. 进行走廊可用性测试吗? Joel测试的巧妙之处在于,针对每个问题,都可以很容易得到“是”或者“不”的回答, 没必要弄清每天的代码行,或者每个测试点的平均故障数。对每个做出“是”的回答,给团 队加上一分。Joel测试的不足之处是,确实不应该用它来保证核动力工厂软件是安全的。 得12分是极好的,11分可以容忍,但10分或者更低就是严重的问题了。现实情况是,大 多数软件机构正运转在2或3分上,它们需要正式的帮助,因为像Microsoft这样的公司全 天候运转在12分上。 当然,这些内容不是决定成功或者失败的惟一因素。特别是,假设一个大型的软件团队正在 努力开发一个没人想要的产品,对了,人们就是不会要它。这就好比是一支由“枪手”组成 的队伍,他们做的事情与此毫不相干,却仍然设法生产能够改变世界的令人难以置信的软件。 但是,万事万物都有可比性,如果将这12件事情办妥了,那么就有了一个可以随时投入使 用的训练有素的团队。 ## 1.使用源控制机制吗 我使用过商业版本的源控制包与免费的CVS[2],并且,我要说CVS不错。但是,如果不使 用源控制,那就得十分强调尽力让程序员在一起工作。程序员没有办法知道其他人员做了什 么,所以不容易进行错误回滚。源控制系统的另外一个巧妙之处在于,可保证源代码在每个 程序员的硬盘上都是经过自动确认了的一一我从来没有听说使用源控制的项目丢失过许多 代码。 ## 2.能一步完成连编吗 对于这一点,我的意思是:从最新的源快照进行一次可分发的连编,需要多少个步骤? 一个 优秀的团队仅有一个能够做从头至尾的完全校验的有效脚本;可重建每个代码行;按所有不 同的版本、语言组合来建立EXE文件;创建安装包;生成最终介质一一CD-ROM规 划;下载Web站点,等等。 如果这样的过程需要多步才能完成,那么就很可能出错,并且越接近产品分发时刻,就越希 望修复“最后”故障、形成最终EXE文件等_*_作所经历的周期会更短一些。如果要用20 步才能完成代码的编译与安装程序的生成等任务,那么你因为感到烦躁而很可能犯低级错误。 正是因为这个原因,我供职的最后一家公司就从当初使用Wise到现在改用InstallShield 了 :我们要求安装过程能够通过使用NT调度表通宵自动地从脚本运行,而Wise不能在晚上 从调度表启动,因此我们将它扔掉了。(友善的Wise人向我保证,他们的最新版本一定支 持夜晚连编功能。) ## 3.每天都做连编吗 使用源控制时,程序员时常不经意地加入一些东西,导致连编中断。比如说,他们添加了一 个新的源文件,但是忘记了将该源文件添加到代码库中去。这在他们自己机器上编译是很好 的,于是,他们锁上机器回家去了,心情舒畅而惬意。不过,别人却不能工作,但也只好回 家去,心情郁闷而忧心忡忡。 中断连编过程是如此有害(同时也如此常见),以致它反而有助于保证每天的连编不至于出 现中断没有被觉察的情况。在大型软件团队中,确保中断得以立即修复的一条很好的途径是, 在每天的午餐时间实施每天都要进行的连编过程。每个人在午餐之前都尽可能多地进行加注 新内容的工作。当他们回来时,兴许连编己经做完了。要是这个办法可行,就好极了!大家 在核实最新的源文件版本以后继续工作。如果连编失败了,就得进行修复,不过,也可以从 连编过的没有发生中断的源文件版本重新再来。 我给Excel开发团队制订了一条规则,无论谁中断了连编,都要负责担当连编_*_作的临时 保姆以示“惩戒”,直到有别人中断连编过程为止。这是一条激励大家不要中断连编过程的 好机制,也是让大家轮流进入连编进程的好途径,从而使每个人弄清连编是如何进行的。 关于每日连编方面的更多内容,可阅读我写的《每日连编是朋友》[3]—文。 ## 4.有故障信息数据库吗 我并不在乎你说些什么。如果你正在开发代码(即使是只有一个人的团队),但是没有一个 组织严密,并列举了代码中所有己知故障的数据库,那么分发出去的代码的质量可能是很低 的。许多程序员认为能够做到在自己的头脑中放一份故障信息表。这是胡说!反正我一次记 不住两条或者三条以上的故障信息,也许就在第二天早上或者代码分发的一刹那,将它们忘 得干干净净。可见,绝对需要正式地保存一份故障信息记录。故障信息数据库可以很复杂, 也可以很简单。一个可用的故障信息数据库必须至少为每个故障包含如下数据: * 重现故障的完整步骤 * 预期功能 * 观察到的(故障)行为 一要分配给谁 一是否己修复 如果故障跟踪软件的复杂性是阻止你跟踪故障的惟一因素,那么建立一个包含上述关键信息 的五字段关系表,然后开始使用它。 关于故障跟踪方面的更多内容,可阅读《故障轻松跟踪》一文[4]。 ## 5.在编写新代码之前修复故障吗 Microsoft Word的第一个真正Windows版本曾被认为是一个“死亡之旅”项目。它花费的 时间不计其数,并且常常脱开正常轨道。整个开发团队行进在看不到尽头的工作泥沼之中, 项目经过了延迟、延迟与再延迟,压力大得难以置信。几年以后,当这个响当当的物件终于 分发下去时,微软将整个开发团队送到迦南去度假,从而坐下来做某种严肃而深刻的灵魂自 我反省。 他们意识到,项目经理们一直是如此固执地坚持按时间表行事,以致使程序员只顾赶进度而 编写出极其糟糕的代码,因为故障修复阶段并没有成为正式进度表的一部分。整个团队没有 在缩减故障数量方面做出任何努力,而是与此恰恰相反。 整个情景演变为:一个必须通过写代码来计算文本行高度的程序员只是简单地给出”return 12 ”这样的代码了事,然后就等故障报告出来,故障报告总是说他的函数不正确。到头来, 进度表只不过成了一张功能故障列表。在尸检行业,这称之为无限缺陷法(infinite defects methodology)。 为纠正出现的问题,微软公司普遍米取了一种称之为零缺陷法(zero defects methodology) 的措施。公司的许多程序员对此报以咯咯一笑,因为这听起来就像是一种单纯依_*_行政命 令就能减少故障数目的管理思想。其实,零缺陷意味着在任意给定时间点,最需要优先去做 的事情是在写任何新的代码之前消除故障。下面说说这样做的理由。 一般说来,在修复故障之前等待的时间越长,付出的代价(时间与金钱上)就越大。 比如,当编译器捕捉到一个拼写或者语法错误,然后去修正它基本上是小事一粧。 在首次试图运行代码时所看到的错误,可以毫不费事地立即进行修正,因为所有代码在头脑 中仍然十分清晰。 如果在几天前编写的代码中发现了问题,找到它确实需要花费一些工夫。不过,只要重新阅 读编写的代码,就可以回想起所有的事情,从而在合理的时间里把它修正过来。 但是,假如在几个月以前写的代码中发现了问题,就可能己经忘记了代码方面的许多事情, 要修复故障就困难多了。这个时候倒是可以去对别人的代码进行纠错,编写代码的人可能正 在阿鲁巴岛(阿鲁巴岛是拉丁美洲荷属安的列斯群岛中的大岛,译者注)度假。在这种情况 下,修理故障就跟从事科学工作一样:你得慢慢地、系统而小心翼翼地行事,并且不能确定 要花多长的时间才能纠正错误。 然而,要是在己经分发出去的代码中找到了缺陷,那么要修复它所要付出的代价将是难以置 信的。 这就是要立即修复故障的一个理由:因为这样做花费的时间较少。下一个理由与这样一个事 实有关:预测要花多长时间去编写新代码比预测要用多少时间去修复现有故障容易得多。 比如,假设叫你预测要花多长时间去编写一段进行列表分类排序的代码,你一定能够给出一 个相当好的估计。但是,如果叫你预测要花多少时间去修复代码在安装了 Internet Explorer 5.5版本以后无法工作的故障,你恐怕连猜也猜不出来,因为你不知道(从概念 上讲)故障出现的原因。很可能要用三天的时间去把故障跟踪出来,也可能只要两分钟就够 了。 这里要表达的意思是,如果进度表包含了许多有待修复的故障,那么该进度表就是不可_*_ 的。但是,如果你己经修复了所有己经知道的故障,并且剩下的就是编写新代码,那么进度 表就是极其准确的。 关于将故障数目维持在零的措施有另外一个重大意义,可以对竞争做出快得多的反应。一些 程序员一直将这看做是让产品做好分发的准备。然后,如果竞争对手加入一个“杀手锏”新 功能来抢夺顾客,你就可以只去实现此新功能,并即时分发产品,而用不着去修复一大堆累 积起来的故障。 ## 6.有最新的进度表吗 这个因素促使我们按进度表推进。如果代码对业务显得十足重要,那么必定有许多关于它为 什么对业务重要的理由可用以了解代码要在何时完成。程序员在制订进度表方面所显现出来 的执拗,给他们留下了坏名声。“在该做的时候自然就做了!”他们冲着业务人员大声喊叫 道。 遗憾的是,事情远还没有完。在分发代码之前,需要业务部门去很好做出的规划决策太多了, 这包括产品演示、贸易展示与广告等。做这件事的惟一途径就是拥有一个进度表,并保证它 始终反映最新的情况。 拥有进度表的另外一个至关重要之处在于,它首先迫使你做出将要实现什么功能的决定,然 后强迫你拣出最不重要的功能,并加以剪除而不是滑入功能沼泽地带(也就是功能范围蔓延 开来)[5]。 持有进度表并不意味着必定显得困难重重。不妨阅读一下第9章,其中给出了一种创建大进 度表的简单方式。 ## 7.有规格说明书吗 写规格说明书好比是理乱麻:人人都认为是好事情,可就是没人去做。 虽然我吃不准这是为什么,但觉得很可能是因为大多数程序员都讨厌写文档资料的缘故。于 是乎,当仅仅由程序员组成的团队在攻克一个问题时,他们偏向于用代码而不是以文档资料 来表示其解法。他们更宁愿匆匆忙忙地一开始就大写特写代码,而不是首先制订一个规格说 明书。 在设计阶段发现问题时,可以通过编辑几个文本行而容易地修复它们。一旦代码写完,纠正 错误所付出的代价会高得出奇,这包括情感(人们通常都厌恨丢弃代码的行为)与时间两方 面的原因。因此,实际消除问题是有阻力的。不是根据规格说明书开发出来的软件通常会因 设计欠佳而停滞不前,从而使进度失去控制。这个问题好像己经在Netscape浏览器那里出 现过,它开头的四个版本逐渐变得混乱不堪,致使管理层愚蠢地决定丢弃己写成的代码而从 头开始[6]。而后,他们再次在Mozilla上完全重复了这一错误而创建出一个让公司运作逐 渐失去控制的怪物,整整花了几年的时间才推进到a阶段。 按照我提出的娇惯理论,这个问题的一种解决之道是通过将程序员送去参加一个写作方面的 强化班[7]而教他们成为不那么凑合的作者。另外一种解决办法是聘用聪明能干的程序管理 人才,由他们负责编写规格说明书。使用这里给出的任何一种方式,都应该强调那条简单的 规则一一 ”没有规格说明书就没有代码!〃 读者可以阅读本书第5~8章,学习关于写规格说明书的所有内容。 ## 8.程序员拥有安静的工作环境吗 大量的文献表明,通过给能干的工作人员提供宽敞、宁静和独立的工作环境,可以获得很高 的生产效率。软件管理方面的经典书籍《人件》(Peopleware)全面论述了这类生产效益的 有关情况[1]。 现在来说明它是如何发挥作用的。大家知道,熟练员工一旦做到“顺手”(也称之为进入状 态)就工作得最好。这个时候,他们将全部精力集中在自己的工作上而置身于环境之外。他 们忘记了时间,因为精力特别集中而焕发出很高的生产率。这正是他们完成所有可做之事的 时候。作家、程序员、科学家乃至篮球队员等人士都可以说出什么叫进入状态。 问题在于,进入状态并不是件容易做到的事情。测量结果表明,人们平均起来似乎要经过 15分钟才开始进入效率最高的状态。有时候,如果你比较劳累或者己经在当天做了很多创 造性的工作,那么你就不能进入最佳状态;在剩下的工作时间里,所要做的事情就是把周围 整理一下、上一上网或者玩玩跳跳棋。 另外一件麻烦事情是被干扰而退出兴奋点却非常容易。噪音、电话、出去吃午饭、不得不驱 车5分钟去喝咖啡,以及被同伴打断一一被同伴打断尤为突出,这些事情都可以使人退出兴 奋区。如果虽然同伴问你一个问题只将工作中断了一分钟,但是这足以让你花半小时的时间 再重新进入状态,那么你的总体工作效率就很严重了。如果置身如咖啡网吧倾向于营造的那 种人多嘈杂的大房间环境之中,外加几个市场推销员在程序员旁边喋喋不休地聒噪,那么生 产效率将随着熟练员工一次又一次地被打断而打了水漂,你永远也进入不了状态。 对于程序员来说,这尤其很难。生产效率与能够立即改动脑子里短期记忆的许多细节有关。 任何类型的中断都能够使这些细节尽皆消失。在重新恢复工作时,任何细节(像正在使用的 局部变量名或者着手实现搜索算法的地方)都想不起来了,从而只得再次把它们找出来,这 会极大地降低工作速度,直到工作重新变得顺手为止。 它涉及的代数知识并不复杂。毫不客气地说(正如有证据似乎表明的那样),即便是打断程 序员一分钟,我们其实打掉了他15分钟所创造的效益。作为这方面的一个例子,让我们将 程序员Jeff与Mutt彼此紧挨着安排在某标准Dilbert肥牛场中一个开放的小卧室里。Mutt 记不住Unicode版本的strcpy函数的名字。他可以查询该函数,这要花费30秒钟的时间; 他也可以询问Jeff,这得用去15秒钟的时间。既然紧***Jeff坐着,他选择询问Jeff。不 过,Jeff因此显得心烦意乱而丢掉了 15分钟的产出(仅仅为了节省Mutt 15秒钟)。 现在让我们将他二两人移到有墙有门的独立办公室中去。这个时候,Mutt记不住那个函数 的名字,他可以查询该函数,仍然要花费30秒钟的时间;他也可以询问Jeff,现在得用去 45秒钟的时间并且意味着站起来走一趟(在现有程序员平均身体状况下,很少会那么做!)。 于是,Mutt决定自己去查询该函数的名字。如此一来,虽然现在Mutt损失30秒钟的产出, 但我们为Jeff节省了 15分钟。啊哈! ## 9.你用到了你资金能力内可买到的最好工具吗 用编译语言编写代码,仍然是在像花园一样多姿多彩的家用电脑上不能立即做成的最后几件 事情之一。如果编译过程要用几秒钟以上的时间才能完成,那么使用最新最好的计算机将可 以为你节省大量时间。即使编译过程只需要15秒钟,在编译器运行时,程序员也会感到无 聊,从而可能转过去阅读《洋葱》[2],这会使他着迷,于是几个小时的开发效益就没有了。 用单监视器系统调试GUI代码是很头疼的,尽管不是不可能。写GUI代码时,使用两个监视 器会使事情容易得多。 大多数程序员最终都会因为图标或者工具栏而_*_作位图,并且他们大多没有很好的位图编 辑器可用。虽然试图使用Microsoft Paint来处理位图不啻是个笑话,但这是大多数程序员 不得不去做的事情。 在我最新从事的一项工作中[3],系统管理员一直不断地给我发送自助午餐肉(信息)。他 抱怨说,我为此占用了服务器上多达220MB的硬盘空间。我指出,以当前的硬盘驱动器价格 论,这个空间的花销远远低于我使用的手纸的费用。我哪怕花10分钟来清除我的目录,也 将使生产效率造成惊人的浪费。 拔尖的开发团队是不让程序员遭受磨难的。它会尽可能不让程序员因为使用功能不强的工具 而遇到挫折,以免程序员心情烦躁而感到不愉快。烦躁不安的程序员不属于高产的程序员之 列。 说到底,程序员是容易通过给他们提供最棒最新的东西而得到满足的。这是一种远比通过支 付极富竞争力的薪水来促使他们为你工作,要廉价得多的途径! ## 10.有测试人员吗 如果团队没有专门的测试人员(至少为每两个或者三个程序员配备一个测试人员),那么意 味着要么分发充满故障的产品,要么通过让价值 30/小时的测试人员完成的工作而浪费钱财。在测试人员方面吝惜钱财谈不上节俭,这种做 法显得不可理喻,我只能是嗤之以鼻地说,较多的人不会认可它。第22章对该内容会有更 多的介绍。 ## 11.新聘人员在试用期间编写代码吗 你会聘用一个魔术师而不叫他露几手戏法吗?当然不会。你会让酒店老板承办婚礼宴席而不 品尝他们的菜肴吗?这很难说。(Marge阿姨除外,你要是不让她做她“著名的”碎肝饼, 她会嫉恨你一辈子。) 尽管如此,每天仍然有一些程序员是因为持有令人印象深刻的履历或者面试人员喜欢跟他们 聊天而被聘用的。或者他们只是被问了一些非常琐碎的问题(比如说“C「eateDialog〇与 DialogBox()之间有什么不同? ”),这些问题是可以通过查看文档资料得以作答的。用不 着在意他们是否记住了编程方面成千上万的细枝末节,应该在乎的是他们能否构造代码。甚 或还有更为糟糕的情况,那就是程序员被问了一些“打哈哈”的问题一一这些问题如果你知 道答案似乎显得很容易,可要是你不知道答案,要回答出来就显得极为不可能。 务请停止这样的做法。诚然,你可以在面试期间做想做的任何事情,但是一定要让应聘者编 写一些代码(关于这方面的更多建议,可阅读我的《面试游击战指南》一文,本书的第20 章收录了该文。) ## 12.进行走廊可用性测试吗 走廊可用性测试指的是,在走廊里随便抓一个从身边走过的人,要他试着使用你所编写的代 码。如果对5个人进行了这类测试,那么就可以了解隐藏在代码中的95%的可用性问题。 好的用户界面设计并不像你想像的那样难,并且,它对于顾客喜爱与购买你的产品至关重要。 我写的关于用户界面设计的书[4]集中叙述了这方面的内容,它是为程序员所写的一个初级 读本。 不过对于用户界面最为重要的事情是,如果将程序交给一部分人(事实上,5~6个人就够了) 看,那么你会迅速发现人们掌握着最大的问题。关于这方面的原因,可阅读Jakob Nielsen 的有关文章[5]。即使你的U I设计技能很缺乏,但是只要强迫自己进行走廊可用性测试(这 用不着付出什么代价),那么设计出来的UI将是非常非常好的。 ## 使用Joel测试的四种途径 1. 评价自己的软件机构,并说出是如何评价的,这样我可以与你交流一下了。 2. 如果你是程序设计团队的经理,那么使用该测试作为校验表,以保证团队确实在尽可能 地发挥作用。如果一开始就评定一个团队为12分,那么可以集中精力不使业务人员去打扰 程序员而使他们置身其外[6]。 3. 如果你在决定是否接受一项编程活件的话,那么询问你未来的雇主在该测试上的得分情 况如何。如果测试的分值太低,那么就要确保自己有权威去修正这种局面。否则,你会面临 失败而徒劳无益。 4. 如果你是一位正在努力评判某个程序设计团队的价值的投资人,或者你的软件公司正在 考虑与另外一家公司合并,那么这个测试可以提供一个快速而简易的尺度。 //后记:2004年6月14日 //自从Joel测试在2000年8月推出以来,我从世界各地的开发人员那里收到了成堆的汇报 各自团队如何评分事宜的 //电子邮件。尽管结果的分布显得相当均匀,我还是要说,绝大多数分值处在2与3之间的 一个位置。嗯!我也收到 //一些在无组织的“枪手”软件开发实践当中成长起来的开发人员的来信,他们拒绝从那些 看起来在Joel测试方面 //天生只能得低分的公司招揽新活。并且,我还收到一些团队经理给出的杰作,他们以Joel测试作为提高团队素质 //的进阶过程而推进自己的管理工作。 //与此同时,似乎许多软件开发组织己经远远地走出了 Joel测试的范畴,而进入复杂的官 僚政治动脉硬化苦斗之中 //。什么时候会出现这种情况是很容易说出的,因为人们在准备开会方面所花的时间比开发 软件更多。在Joel测试 //上得到12分的不错成绩,然后就被多如牛毛的政治活动纠缠得脱不开身而做不了什么事 情,这是很有可能发生的 //一种情况。 //没有必要告诉别人是我说了些什么,不过,自上世纪90年代初我在微软公司工作的那个 时期以来,所有证据都表 //明,该公司或多或少地搁浅乃至停滞均是因其过于庞大的规模、内部政治纷争与官僚系统 的不检点所致。还需要 //证据吗? //Tablet PC 一一这是一种只有微软公司的中层经理们才可能喜爱的东西一一似乎设计成了 让华盛顿Redmond的程 //序经理们可以开一整天的会,却不至于使其日常电子邮件处理事宜显得过于滞后。这不单 纯只是微软才存在的现象。 //如果突然间地发现自己在安装与配置巨无霸软件开发系统或“什么什么可视化企业体系设 计大师”之类的软件方 //面,花费的时间太多,或者说要开始开发产品时还在团队重新学习“极限编程(Extreme Programming)”与 //UML方面反反复复而让他们脑袋变大,那么即使在Joel测试方面真的做得不错,你还是 可能陷入困境。 [1]见Tom DeMarco与Timothy Lister合著的《人件:高产项目与团队》第2版(Peopleware: Productive Projects and Teams, Second),该书由 Dorset 出版社于 1999 年出版发行。 [2]见 [http://www.theonion.com](http://www.theonion.com) 。 [3]见第32章。 [4]Joel Spolsky 著的《程序员用户界面设计KUser Interface Design for Programmers) (Apress于2001年出版)。该书的一部分可以从 [http://www.joelonsoftware.com/uibook/chapters/fog0000000057.html](http://www.joelonsoftware.com/uibook/chapters/fog0000000057.html) 上免费使用。 [5]Jakob Nielsen写的“为什么只需测试5个用户”一文于2000年3月19日在.useit.com 上发表。详细内容见 www.useit.com/alertbox/20000319.html 。 [6] www.joelonsoftware.com/articles/fog0000000072.html 。