软件项目秘辛:为什么软件项目会失败 - 第 1 章、第 4 章






1.53/5 (11投票s)
2005年12月30日
25分钟阅读

52148
《软件项目秘辛:为什么软件项目会失败》为软件行业的成功开辟了一条新道路。本书旨在帮助那些使用行业标准方法论,但项目仍然难以成功的经理、开发人员和客户。
|
|
目录
- 引言
- 为什么软件与众不同
- 项目管理假设
- 案例研究:计费系统项目
- 新的敏捷方法
- 敏捷项目预算
- 案例研究:计费系统再探
- 后记
第 1 章:引言
你的老板要求你监督一个新的计费系统的开发,你已经召集了一位能干的项目经理和一群精挑细选的开发人员。他们选择了最先进的技术和工具来构建系统。业务分析师与会计经理进行了长时间的交谈,并撰写了一套详细的需求。该项目拥有成功所需的一切——不是吗?
显然不是。六个月后,项目已经延期并超出预算。开发人员加班加点工作了数周,其中一人已经辞职,但尽管如此,软件似乎从未接近完成。问题的一部分是会计团队不断声称软件无法满足他们的需求,他们不断提出“必不可少”的变更请求,更不用说大量的错误报告。你的老板听到这些会非常生气。
那么,哪里出了问题?
无论是什么问题,它一定是大多数公司都会犯的错误。根据 Standish Group [2001] 的研究,2000 年只有 28% 的软件项目完全成功(参见图 1-1)。约 23% 的项目被取消,其余的项目则严重延期(平均延期 63%),超出预算(45%),缺少功能(33%),或者很多时候是所有这些问题兼而有之。
图 1-1. 2000 年软件项目的成功与失败。
在新西兰司法部,新的耗资 4200 万美元的案件管理系统在 2003 年推出时超预算 800 万美元,并延迟了一年多。该系统预计的 27 项收益中,只有 16 项得以实现。该系统不仅没有提高生产力,反而通过将数据输入量增加一倍,增加了管理法院案件所需的时间。实施后审查发现了 1400 多个未解决的问题。但“开发人员面临的唯一挑战是大型复杂系统常见的挑战”[Bell 2004]。
相比之下,工程和建筑行业的情况截然不同。根据《工程新闻记录》的报道,他们调查的项目客户中有 94% 对项目结果感到满意,这表明建筑项目的失败率远低于软件项目。这就是为什么 2004 年 5 月戴高乐机场(巴黎)新建的 2E 航站楼的管状屋顶倒塌成为世界各地头版新闻的原因:这太不寻常了。失败的软件项目太常见了,不值得如此关注。
我们可以通过考察商业和非商业软件开发来了解原因。商业软件是由公司为盈利而生产的。有些软件是为个人客户定制的,比如你的计费系统,但也有像 Microsoft Word 这样的通用“现成”产品。几乎所有这些都是在一个项目或一系列项目中创建的。非商业软件通常是开源的,这意味着任何人都可以阅读其源代码。用户可以了解其工作原理,并进行更改以修复错误和添加他们想要的功能。对于开源软件,来自世界各地的开发人员在一个没有固定功能列表、预算或截止日期的软件上共同工作。开源开发人员以与传统项目管理截然不同的方式协调他们的工作。
开源软件取得了巨大成功。“互联网运行在开源软件(BIND、Sendmail、Apache、Perl)上,”O'Reilly & Associates(最大的计算机图书出版商之一)首席执行官 Tim O'Reilly 说。开源软件的可靠性问题或错误通常比商业软件少得多。但它是否以我们衡量商业项目所用的相同标准来衡量成功?毕竟,如果时间无限,难道每个项目都会成功吗?
确实,无限的时间可以弥补低下的生产力。然而,开源开发人员的生产力是传奇般的。1991 年,Linus Torvalds 在不到一年的时间里,主要依靠自己,编写了一个完整、稳定的操作系统内核 (Linux)。不到一年后,八位核心贡献者聚集在一起组成了 Apache Group,他们将 Apache 1.0 打造成了一款如此引人注目的软件,以至于它成为了互联网上使用最广泛的网页服务器。
这些成功表明,软件开发可以在传统项目管理之外运作得非常好。考虑到项目管理技术在大多数其他领域都运作良好,这令人费解。我们已经看到,这在建筑和工程领域是正确的。软件开发一定有什么不同之处,导致项目管理失败。
下一章将通过识别软件及其开发过程的独特特征来开始分析。然后将这些特征与项目管理的最佳实践进行比较,以发现项目管理过程在软件开发中出现问题的地方。本书的第一部分以一个模拟案例研究结束,该案例研究展示了这些问题如何导致一个原本充满希望的项目失败。
这些章节详细描述了软件开发中的问题。这可能看起来令人沮丧,但不要放弃希望。识别问题的根源是找到解决方案的第一步。本书的第二部分重点介绍有助于软件项目成功完成的策略。它首先概述了三种流行且有前景的新软件开发方法。然后,它考虑了如何使这些方法与项目管理相协调。最后,重新处理了第一部分的案例研究,以展示如果项目管理方式不同,同一项目如何能够成功。
第 4 章:案例研究:计费系统项目
在上一章中,我们对项目管理进行了深入分析,以发现它在软件开发中出现问题的地方。本章涵盖了相同的问题,但从不同的角度。它引入了一个虚构的案例研究(与引言开头的场景相同),以说明十个隐藏假设是如何发挥作用的,以及它们如何导致项目失败的问题。在本章末尾,我们将考虑每个假设产生的影响。
案例研究不一定是典型项目,因为出于清晰和篇幅的原因,许多方面都已简化,但这绝非不寻常。案例研究中的每个问题都发生在作者参与的至少一个真实项目中。
这是第一部分的最后一章。在第二部分中,我们将尝试为这些问题找到解决方案,并以我们已经讨论过的想法为基础。第二部分将以另一个案例研究结束,该案例研究将重新处理此场景,以展示如果项目管理方式不同,它如何能够成功。
要求
Acme 公司——一家中型玩具制造商——由于其扩张计划的持续亏损,股价大幅下跌。每个部门都被要求削减 10% 的成本,以帮助提高盈利能力并安抚投资者。会计经理凯伦想出了一个主意,整合她的团队使用的各种财务应用程序,这样数据只需在新主应用程序中输入一次,然后新主应用程序会自动将其复制到其他应用程序中。通过消除重复输入相同数据,她的部门可以裁掉三个全职数据录入员。
凯伦去见了她的老板萨利姆,作为首席财务官,他有权批准或拒绝该项目。他喜欢这个主意,但敦促谨慎:“记住,我们正在努力省钱,所以我们必须控制项目的成本。公司政策规定,任何新投资都必须在三年内收回成本。考虑到公司目前的状况,我希望在此之前就能看到回报。看看你能做些什么。”萨利姆联系了 Acme 首选的就业机构 People Co.,聘请了一位经验丰富的业务分析师作为承包商,为期两周,以确定项目的范围和估算。布莱恩一周后加入,并立即与凯伦安排了一系列会议,以审查需求。两周结束时,他完成了一份厚厚的功能规范文档。他还对整个项目提出了 30 万美元的初步估算,其中包括他迄今为止工作的 7500 美元。
这个数字让凯伦和萨利姆都松了一口气,因为预计每年可节省约 15 万美元,因此投资将在两年内完全收回。项目获得了开始规划的许可。
规划
虽然 Acme 将其所有 IT 需求外包,但它仍然拥有一些能干且经验丰富的运营项目经理。萨利姆与运营经理交谈后发现,他的下属之一菲尔恰好在未来几个月有一些空闲时间,他当然可以负责这个新项目。
菲尔花了一周时间审查了布莱恩撰写的估算和范围,并在他的项目计划中整理了工期、资源和成本估算(表 4-1)。
表 4-1. 项目活动的工期、资源和成本估算
Activity | 资源 | 姓名 | 持续时间 | 成本 |
项目发起人 | 萨利姆 | N/A | N/A | |
关键业务负责人 | 凯伦 | N/A | N/A | |
要求 | 1 名业务分析师 | 布莱恩 | ½ 月 | $7,500 |
设计 | 1 名软件架构师 | 安吉拉 | 1 个月 | $20,800 |
然后,当你开始迭代 2(这是构建迭代的开始)时,你可能想要复制测试用例并将它们重新分类到迭代 2。这还允许对测试用例进行粒度跟踪,并允许你说某个测试用例在一个迭代中是准备好的,但在另一个迭代中不是。同样,如何做到这一点取决于你以及你希望如何报告。 “场景”部分提供了更多细节。 | 4 名开发人员 | Reiko, Tim, Hua, Mike | 2½ 月 | $138,600 |
系统测试 | 1 名测试员 | 伊恩 | ½ 月 | $6,100 |
用户测试 | 1 名最终用户 | 艾米丽 | ½ 月 | $4,300 |
返工 | 4 名开发人员 | (如上) | ½ 月 | $27,700 |
项目管理 | ½ 项目经理 | 菲尔 | 4 个月 | $34,700 |
总计 | $239,700 |
他将项目的其余部分划分为设计、构建和测试/调试阶段(图 4-1)。
图 4-1. 总体项目计划。
菲尔还考虑了最有可能影响项目的风险(表 4-2)。他遵循了将每个风险的概率和影响相乘的常见做法,以得出所需应急准备金的数字。疾病的影响可以忽略不计,因为 Acme 不支付承包商的病假工资,而且他认为一个最终用户很容易被另一个替代。在为未知风险增加 10% 的应急准备金后,菲尔最终认为整个项目有 25% 的充足应急准备金。
表 4-2. 风险登记册
计费系统项目风险 | 概率 | 影响 | 应急准备金 |
需求变更。 | 20% | 25% | 5% |
与现有系统集成的问题。 | 25% | 20% | 5% |
开发人员能力不如预期。 | 10% | 20% | 2% |
系统错误比预期多。 | 30% | 10% | 3% |
疾病会延迟项目。 | 10% | 0% | 0% |
将出现未知风险。 | 10% | ||
总计 | 25% |
项目成本和工期的最终估算分别为 299,600 美元和五个月,作为项目的正式发起人,萨利姆很高兴签署。
设计
People Co. 很快找到了一位经验丰富的软件架构师,Angela 成为了团队中的第一位承包商。她的任务是撰写一份技术规范文档,其中包括高级架构和详细设计工作。她很快决定 Microsoft .NET Web 服务是连接各种会计应用程序的最佳技术,并开始绘制 UML 图以展示解决方案的外观。
她觉得有点奇怪,她不被允许创建原型或编写任何测试代码,但菲尔在他们的第一次会议上对此非常明确。“抱歉,你编写软件太贵了。这个项目有严格的财务限制。有很多代码要写,我们希望以每小时 80 美元的价格完成,而不是 120 美元。”
Angela 知道这个安排不是一个好主意,但这个合同只有一个月,不值得为此大惊小怪。此外,当事情出问题时,这也不是她的问题。
然后,当你开始迭代 2(这是构建迭代的开始)时,你可能想要复制测试用例并将它们重新分类到迭代 2。这还允许对测试用例进行粒度跟踪,并允许你说某个测试用例在一个迭代中是准备好的,但在另一个迭代中不是。同样,如何做到这一点取决于你以及你希望如何报告。 “场景”部分提供了更多细节。
Angela 一旦确定了基本技术,Phil 就回到了 People Co. 寻找具有相应技能的开发人员。他不想要那些不可靠的新手,但他也不想要太昂贵的开发人员。People Co. 找到了四名声称熟悉 .NET 和 Web 服务的中级开发人员:Reiko、Tim、Hua 和 Mike。
周一早上,四位开发人员发现他们被分配到 Acme 大楼不同区域的空置办公室,其中一个办公室刚刚被 Angela 腾空。他们很快忙着安装开发软件并阅读 Phil 给他们的两份厚厚的规范文档。
“我们每两周开一次团队会议,”他对他们说,“但在此期间,如果你遇到任何问题,请随时过来找我谈谈。我的门永远敞开着。”
那天下午喝咖啡时,开发人员决定将工作分成四个大块:用户界面和业务逻辑、数据库、Web 服务接口和基础设施。Hua 曾参与过几个大型数据库项目,因此她自愿负责数据库访问功能。Reiko 接管了用户界面和业务逻辑,Tim 负责 Web 服务接口,Mike 负责基础设施。他们决定单独工作两个月,然后用最后两周将所有部分整合在一起。
编码
不久,Reiko 发现功能规范实际上并没有描述新应用程序屏幕的布局方式。她就此事询问了 Phil。
“布莱恩说这些需求将是你构建用户界面所需的一切,”他回答道,“你为什么不把一些合理的东西组合起来,然后更新功能规范来记录你所做的事情?”
Reiko 本来希望只写代码就能蒙混过关,但她欣然接受了。当她意识到错误消息也没有被指定时,她没有再去问 Phil,而是自己编造了它们,然后也把它们添加到功能规范中。
在大楼的另一边,蒂姆遇到了真正的困难。他之前参与过一个 Web 服务项目,所以他很乐意承担 Web 服务接口的责任。然而,一些会计应用程序对数据格式有特殊要求,而 .NET 工具创建的接口根本无法工作。
他发现,他不得不手工创建这些接口,而不是依靠工具来创建,而且他对此一无所知。然而,他知道关于这些技术的书籍很容易找到,所以他保持沉默,希望能够学到足够多的知识,及时完成所有工作。
当 Mike 开始进行程序的内部基础设施工作时,他意识到设计虽然优雅,但仍需要一些改进才能实现所有必要的功能。事实上,它确实需要进行一次大修。然而,当他向 Phil 提及这个问题时,Phil 的回应并不令人鼓舞。
“安吉拉作为一名软件架构师,受到了高度推荐,我不想让你对她的设计进行任何不必要的更改。我还希望你精确地记录你所做的更改。技术规范是这款软件的文档,我希望它始终是完整和准确的。”
因此,迈克并没有进行他认为必要的重新设计,而是对基础设施设计中缺失的所有功能进行了一系列快速而难看的修补。
在项目会议上,每位开发人员都报告了稳步进展,每两周完成 25%。菲尔说:“好吧,看来我们正按计划进行。”
集成
两个月后,团队重新聚集在一起整合代码。他们围着桌子,发现每个人的工作都差不多完成了。Reiko 代表大家说:“我的代码仍然有点粗糙。它应该能正常工作,但例如错误处理,还需要更多的工作。我很抱歉,但是更新所有文档使一切都花费了两倍的时间。”
然而,当他们试图将系统的四个独立部分编译在一起时,它失败了,并出现了一长串错误消息。他们整天都在努力解决这些问题,但似乎每修复一个,就会出现两个。到一天结束时,列表开始再次缩小,但 Hua 仍然相当恐慌。
“你们回家吧。我留在这里。我们反正不能同时处理这个。我们没有多少时间让它正常工作,我至少能做的就是让它编译通过。”
然而,工作进展缓慢,凌晨两点,华放弃了,还剩下六个严重的错误。更糟糕的是,她发现Reiko的业务逻辑和Tim的web服务之间存在根本性的不兼容。第二天早上他们一到,她就召集团队开会。气氛很紧张。
“伙计们,我们遇到了大问题。Reiko 编写的代码使用了事务,但 Tim 的 Web 服务不支持事务,”她说。“它必须使用事务,”Reiko 说,“这在功能规范中。对数据库的更新和通过 Web 服务的更新必须要么全部完美工作,要么全部一起中止。没有事务,当一个更新失败时,你如何中止另一个更新?”
“但是 Web 服务还不支持事务,”Tim 说,“那项技术又被推迟了,要到明年年初才能发布。”
“有没有变通办法?”迈克问道。
“我想有,”华说,“对于每个 Web 服务,我们可以添加另一个 Web 服务来撤销该更新。这样,如果我们需要中止事务,我们只需调用那个撤销 Web 服务。”
“但这意味著 Web 服务模块的大小会增加一倍,”Tim 说。
“我不可能在接下来的两周内完成所有这些。”
“Reiko 和我会帮助你,”Mike 说,“Hua 可以完成集成;她到目前为止在这方面做得很好。但是我们真的需要在交给测试人员之前完成所有工作。有没有办法我们能更快地完成事情?”
“放弃文档,”Tim 立刻说,“那是最主要的开销。每次我对代码做最微小的改动,都必须花很多时间更新所有图表。我知道有好的文档很好,但肯定比让系统正常工作优先级低?”“好的。也不要过度设计。我不介意它有点粗糙,但一切都必须在下周一之前到位,”Mike 说。
最后的两周简直是噩梦。华终于让程序编译通过了,但一运行就立即崩溃了。跟踪这些 bug 很难,因为每个开发人员的代码风格都非常不同。代码注释很少,很难理解其工作原理。
“哦,好吧,”她心想,“我们还有调试阶段。当我们都能再次处理自己的代码时,会容易得多。”事实证明,Web 服务撤销代码比他们预期的要棘手,到最后一个星期五还没有完全完成,所以开发人员决定周末加班。在周一早上的交接会议上,他们至少能够声称软件现在“功能完整”,尽管仍然有一些 bug。现在它由测试员伊恩和会计团队的最终用户艾米丽处理。
测试
第一份错误报告在交接会议结束后仅仅十分钟就提交了,之后便如潮水般涌来。在那周的其余时间里,错误列表不断增加,包含了 160 多个严重或关键错误。周五,菲尔召集会议讨论情况。
“我们计划在一周内部署系统,”他说,“我真的需要知道我们是否还能赶上那个日期。”
华摇了摇头。“我们这周修复了将近 60 个 bug,这是一个惊人的速度,但我们不可能在下周末之前完成剩下的工作。我们还需要一周,或者为了安全起见,可能需要两周。”
“好吧,有缺陷的代码是我在项目开始时发现的风险之一,这就是应急计划的作用。我乐意将发布日期推迟两周,”菲尔回答。
“我不乐意,”伊恩说,“有很多功能我还没法测试,因为程序在我还没到那个地方就崩溃了。我确信还有很多 bug 等着被发现。”
“那是因为一半的错误报告实际上是变更请求,”Reiko 回答道,“你看这个:‘无法将电子表格中的数据块粘贴到表格中。’这不在功能规范中。”
“这是我们目前正在做的事情,”艾米丽说,“我以为这款软件是为了节省我们的时间,而不是让我们的工作变慢。如果我们每次都必须复制一个数字,那么每张发票我们将花费两倍的时间。”
“好的,各位,”菲尔说,“我们将日期推迟三周,但我真的希望你们确保在那之前完成。我想把最后一周的应急时间留给部署中出现的任何问题。Reiko,我明白你的意思,但会计人员也必须对软件感到满意。我希望你与 Emily 合作,找出能让他们满意的最低限度的修改。Tim,你与开发人员合作,以便他们能够修复阻碍你测试的错误。我还希望在一周后召开另一次项目会议。”
在下次项目会议上,开发人员坐在桌子的一边,测试人员坐在另一边。双方互相怒视。Reiko 是第一个发言的。“Emily 没有退让任何一个她的变更请求。事实上,她还增加了更多。这样下去,软件永远也完不成。”
“我和凯伦以及我的团队其他成员谈过了,他们都同意我的看法,”艾米丽回答,“我们需要能用的软件。凯伦不会让我们切换到新系统,直到我们百分之百满意为止。”
“我们稍后再讨论这个。伊恩,你那边进展如何?”菲尔问道。
“抱歉,菲尔,进展不顺利。大家设法打开了大部分应用程序,但似乎每次他们修复一个 bug,就会破坏另外两个东西。严重和关键 bug 的数量现在是 230 个。”
“我仍然相信我们能赶上最后期限,”华说,“我想我们已经修复了大多数真正困难的 bug,所以剩下的应该会更快。”菲尔思考了一会儿。“我愿意把整个月的应急时间都给你,用来修复这些 bug,并进行会计人员要求的修改。但这已经是最后期限了。这个项目是为了省钱。我绝不会让它超出预算。”
死亡行军
在接下来的四周里,开发人员尽可能快地工作,但越来越明显的是,他们根本无法按时完成。错误列表不再增长,但也没有足够快地缩小,Reiko 和 Tim 完成的每个新功能都增加了总体的错误数量。在第五个月,Phil 最终允许项目超出其计划的应急时间。他认为,接受小部分损失总比放弃他们为之努力的一切要好。
迈克大约在同一时间离开了团队。随着项目陷入越来越多的困境,他变得越来越不开心,因此他安排了另一份合同,在与 Acme 的合同到期后立即开始。他很快被 Deepak 取代,Deepak 是一名刚毕业的大学生,在大学学习过 .NET。
然而,Deepak 发现这款软件很难上手。代码经过了太多仓促的改动,变得杂乱无章,文档也过时了,几乎毫无用处。他要么花几个小时盯着其他开发人员的肩膀,要么在自己的办公室里花几个小时,进展甚微,越来越沮丧。
后果
发布日期不断推迟,最终萨利姆和首席执行官凯茜都介入了。萨利姆请安吉拉回到 Acme,为艾米丽要求的所有“必要”更改提供可靠的估算。安吉拉建议再为这些更改留出一个月的时间。
在六个月的时候,项目已经超预算 30%,还需要至少 60% 的资金才能完成,其中包括一个月的清理剩余错误的工作(图 4-2)。凯茜毫不犹豫地取消了该项目。
图 4-2. 项目取消时的财务状况。
“这个项目状况很糟糕,不能保证它能成功完成。我再也不愿意投入任何资金了。”萨利姆因此项目失去了奖金,菲尔也错过了他一直期待的晋升。两人都因这次经历而受到了惩戒,但他们都没有真正理解项目出了什么问题。
摘要
那么,项目究竟出了什么问题?如果我们将案例研究与我们在第 3 章中确定的项目管理假设列表进行比较,我们可以看到项目中的大多数问题都发生,是因为项目计划依赖于这些假设,而这些假设结果是不正确的。
- 范围可以完全定义。
- 范围定义可以在项目开始前完成。
没有机会重新评估或调整项目范围。艾米丽指出需求中的缺陷是正确的,但她只有在所有功能都创建完成后才能这样做。此时,需求的变更意味着一些现有代码必须被丢弃和重写,这是浪费的,并增加了项目成本。
- 软件开发由截然不同的活动组成。
- 软件开发活动可以排序。
- 团队成员可以单独分配到活动中。
需求收集、设计、构建和测试活动之间缺乏重叠,这意味着执行这些任务的个人之间的沟通极其有限。规范文档是他们唯一可以依靠的,没有办法提问或提供反馈。开发人员无法与软件架构师讨论设计,测试人员也无法与业务分析师讨论需求。
如果开发人员一开始编写代码就进行测试,那么质量问题就会更早显现出来,并可以系统地解决。如果开发人员也负责软件的设计,那么一旦他们看到软件的成型情况,就可以根据需要进行完善。
- 项目团队的规模不影响开发过程。
团队规模很小,可以通过采用不那么正式的开发流程来更有效地工作。面对面交流是一种比通过文档传递信息效率更高的方式。
- 总有办法得出有意义的估算。
- 可以获得可接受的准确估算。
- 一位开发人员等同于另一位开发人员。
项目是在团队成员确定之前进行估算的,因此没有考虑个人技能差异——例如 Tim 对 Web 服务的有限知识。团队以前从未合作过,因此无法将估算与早期项目的结果进行核对。事后看来,25% 的应急准备金显然严重不足。
- 度量足以评估软件质量。
团队使用了两个指标来评估他们的进展。在构建阶段,他们估算了已完成功能的比例。在测试阶段,他们统计了已报告的错误数量。大量的错误清楚地表明软件质量低下,但这个指标误导了团队,使他们相信修复这些错误就足以修复软件。但是,他们越是疯狂地投入到软件中,软件就变得越混乱、越脆弱。他们的努力只是进一步降低了质量。