我们来看看设计和构建的根本不同。设计很难预测,而且需要有创造力的人,而那些人往往都很昂贵,而构建则比较容易预测。只要设计工作完成,我们就能开始计划构建。一旦有了构建计划,就能够开始构建,而这个过程是容易预测的。在土木工程中,构建阶段花费时间和金钱远远超过设计和计划。
所以众多的方法学看起来就像这样: 我们想要一种可预测的进度表来帮助组织、使用那些技术欠佳的人。为了做到这一点我们需要把设计和构建阶段分开。因此我们需要计算如何做设计和计划以保证构建的顺利进行。
而计划应该采用何种形式呢? 对於多数人来,就是诸如UML之类的设计记号法所要扮演的角色。如果我们的所有重要决定都使用UML,我们就能够建立一个建构计划并且把这些设计交给编码人员来开发,完成构建活动。
但是这里有一些至关重要的问题。你的设计能够保证把编码组织起来,完成一个完整的构建活动吗?即使这点你能做到,那么,你的构建过程在时间和金钱上的花销真的大到那种不得不采用这种方法的程度了吗?
这些怎能不引人深思呢。首先是把像UML那样的设计图移交给程序员来实现是一件极为困难的事情。问题的关键在于那种设计看上去不错,可你打算编程来实现它的时候就出现了问题。土木工程师使用的模型建立在多年实践的基础上,它们用土木工程的专用语言来描述。而且主要的问题在于,通常这种设计需要符合数学原理。而我们对UML之类的图表唯一能做的就是同级检查。虽然这是有帮助的,但还是往往会忽略一些错误,这些错误只有到编码和测试阶段才能被发现。即使是熟练的设计者,例如我觉得我就是一位,在把设计转为软件的时候,也会被其中的问题吓一大跳。
另外的一个问题是费用的不可比。当你建立一座桥的时候,设计的费用约占全部工作量的10%,其余的工作量都在建构阶段。在软件中编码的时间消耗则小得多。(McConnell建议在一个大的项目中,编码和单元测试的开销占整个项目开销的15%,这个比例和建桥的比例刚好是相反的。即使你把所有的测试也算在构建阶段中,设计仍然占了50%的工作量)。这就引起了一个至关重要的问题,因为通常我们都是把软件设计看做是工程学的一个分支的。
种种问题使得Jack Reeves提出,事实上源代码就是一份设计文档,而构建阶段实际上是编译器和连接器的使用。的确,你视为建构阶段的任何事都能而且也应该被自动化。
这就引出了一些重要的结论:
在软件中: 建构阶段是廉价而自由的。
在软件中所有的努力都是在设计, 这需要那些富有创造力而且聪明的人。
有创造力的过程可不是那么容易计划的,而且具有可预测性也是一个不可能达成的目标。
我们用传统的工程来隐喻设计软件应该非常小心。它们是不同的类型的活动,需要的过程也是不同的。
需求的不可预测性
在我经历的每一个有问题的项目中,我听到的总是同样的声音。开发人员跑过来对我说:“这个项目之所以有问题,是因为需求总是在变。”再也没有比这更令人惊讶的了。在商业软件开发领域,需求变化是很正常的,问题是我们该怎样对待它。
一条路是对把需求变更视为拙劣的需求工程所造成的恶果。需求工程要求你在开发软件之前对整个系统的需求有完整的了解,让客户确任需求,并严格按照需求设计程序,其中,不允许需求的变更。
这样就产生了一个问题,想要了解需求的一些信息是件困难的事,而要求开发组织提供需求的具体费用信息更是难于登天。如果你想要给你的车加上天窗,可是卖汽车的那家伙根本说不出花10块钱的天窗和要10000块钱的那种有什么区别。对这两种费用完全没有概念,试问,你能决定选用那种天窗吗。相信大多数人都不会作出决定的。
这种预算往往因为某些理由而难以做到,一个原因是软件开发是一项设计活动,难以计划和制定费用。另一个原因是基本的要素变化很大。还有一个原因是需求过于依赖于参与的个人,而个人是难于编制预算和量化的。
软件的无形价值的特性也加大了难度。除非投入使用,否则很难估算出软件的功能有什么价值。只有当你使用软件的早期版本时,你才能了解哪些功能是有价值,哪些是没有价值的。
具有讽刺意味的是,这使得人们希望需求是可以变化的。毕竟,软件被称为“软”件。需求一旦发生变化,软件也要能发生变化。这往往要求开发者费尽心机来说服客户固定需求。更糟的是,如果那个客户刚好涉猎过软件领域,说服他们可就更不是件容易的事了,因为他们知道那玩艺儿是很容易改变的。
即使你可以搞定你的客户,拿出一份准确、稳定的需求,可你还是注定失败。当今商业活动赖以生存的经济瞬息万变,要求软件的功能能够迅速改变。什么才是好的需求集呢,决不是只适用6个月的那种。即使客户能固定他们的需求,现实的商业世界也不会为了他们而停止。而在商业领域中,很多改变是完全不可预知的: 否则那个人不是在说谎,就是已经在股票市场赚了数十亿了。
软件开发中的其他阶段都必须依赖于需求。如果你不能够拿出一份稳定的需求,你就不能得到一份可预期的计划。
可预测是无法做到的吗?
大体上,这是做不到的。也有一些软件开发是可以被预测的。例如 美国航空航天总署的太空船软件团体组织就是这方面的一个典型例子。它需要大量的仪式,足够多的时间,庞大的团队和稳定的需求。所以能够制定出太空船那样的计划。然而我不认为这么多商用软件适合这种方法。为此你需要一个完全不同的过程。
一个极大的风险在于你总认为你可以遵循一个可预测的过程,但实际上,你不行。使用方法进行工作的人们并不能很好的识别边界条件: 方法从适合到不适合的交界之处。决大多数的方法学家希望他们的方法学能被每个人使用,因此他们不了解也不宣传他们的边界条件。这就误导了人么,在错误的环境中使用一种方法,例如,在一种不可预测的情形中使用一种可预测的方法学。
然而总有种强烈的诱惑驱动你去那样做。可预测性是一项极为宝贵的财富,非常令人动心。然而如果你相信你可以预见到什么,但是实际上你做不到。这就导致人们过早建立计划的情形,然后因为处理不当致使计划失控的情形。你可以看见计划和现实慢慢脱离的。很长的一段时间里,你仍认为计划仍然有效。但是当脱离越来越明显,计划最终失败。这该是多么的痛苦。
所以不论你是否处在这么一个可预测的环境中,你都不能使用可预测的方法。这是很痛苦的事情。意谓着为了控制项目,为了整体的客户关系而制作的大量模型,而这些根本不对。可预测性的好处确实很大,但要做到却很困难。象这麽多问题,其中最难的部份却是了解问题是否存在。
然而去掉可预测性并不意谓你回到无法控制的混乱局面。实际上你需要一个能控制不可预测性的流程。这就是合适性的本意。
控制一个不可预测的过程
那么我们该如何在一个不可预知的世界中控制我们自己? 最重要的,而且困难的是要如何正确地知道我们处在那个位置上。我们需要一种反馈机制,它可以每隔一段时间就告诉我们准确的位置。
反馈的关键是迭代开发。这不是一个新的想法。迭代开发以前有很多的名称: 增量模型,改良模型,阶段模型,螺旋模型...。迭代开发的关键在于把最终的系统划分为多个可工作的版本,每一个版本都实现了功能的一个子集。这些可工作系统都实现了全部功能的一小部分,但都完全符合系统最终的要求。他们都应该被完全整合并通过的小心的测试,做为最终版本交付。
一个经过测试、整合的系统无疑给那些计划注入了一针现实的强心针,再没有什么比这更好的了。文档能隐藏几乎所有的缺点。未经测试的代码同样能隐藏许多缺点。但是当人们真正坐在一个系统之前并用它来工作的时候,缺点就显现出来了:不论是bug还是曲解的需求。
迭代开发在可预测的过程中也样有效。但它是是适应性过程的核心思想,因为一个适应性过程需要处理功能需求上的变化。这使得迭代开发往往呈现出远期计划不固定,稳定的计划只是每次迭代的短期计划的风格。迭代开发在每一次的迭代中提供了一个坚实的基础以保证计划的制定。
另 一个主要问题是一次迭代需要多长的时间。这个问题的答案因人而异。XP建议一次迭代差不多需要在一到三个星期之间。SCRUM建议议一月的长度。Crystal则更远一些。整体的趋势是使每一次迭代都保持在你能够对付的时间范围之内。这种机制提供了频繁的反馈,因此你更好的知道你在哪里。
适应型客户
这种适应型的过程需要和客户建立一种全新的关系,而不是原先那样,尤其是开发部分由另一个公司负责的时候。当你雇请一个单独的公司做软件开发的时候,决大多数的客户会较喜欢一份固定价格的合同。告诉开发者他们想要的,要求竞标,接受竞标,然後负责是在发展组织上开发软件。
一份固定价格的合同要求稳定的需求,因此也就需要一个可预测型的过程。适应型和不稳定的需求暗示你不能采用固定价格的平常观念来处理问题。对一个适应型过程建立一个固定价格机制的尝试在经历一个痛苦的摸索后宣布失败。最糟糕的是这种做法深深伤害了客户,同时也伤害了软件公司。除非特别需要,用户不一定想要那些软件,前提是不用这些软件也不会损害生意。所以即使他们什么都没有付给开发公司,他们还是失去了很多。的确,他们失去的价值超过了软件的费用。 (如果那个软件没什么价值,我为什么要付费呢?)
所以在可预测型过程无法使用的条件下双方签署一份固定价格的合同是及其危险的。这意谓客户必须不同的工作。
在一个适应型过程中客户对软件开发过程会把握的更好。在每次迭代,双方都必须检查进度以决定是否改变软件开发的方向。这有利于和软件开发者建立一种更密切的关系,真正的生意伙伴。这种程度的契约关系并不是每个客户组织和每个软件开发者都必须达到的,但是它能够使一个适应型过程很好的工作。
客户的主要利益比软件开发的回应要重要多了。一个可以使用的, 虽然可能很小的系统可以尽量早的投入使用。然后客户会根据生意的变化来改变系统的性能,而且能够从现实中存在的系统中学习。
人是第一位的
适应型过程的执行可不是一件容易的事情。它特别需要一支高效的开发人员团队。这个团队的每一个成员都应该具有高素质,能够相互配合。这里有个有意思的合作优势:不仅仅是适应型过程需要一个强有力的团队,大多数的开发人员也原意加入到适应型过程中来。
同一的编程机器
传统方法的目标是建立起一个过程,把参与者分成多个可以替换的角色。在这样一个过程中,参与者在你眼中都是各种各样的资源以供使用。你有一个分析员,几个编码人员,几个测试人员,一个项目经理。至于每个人是不重要的,角色才是重要的。这样你在计划一个项目的时候考虑的不是你需要哪一个分析员,或是哪几个测试人员,你要考虑的只是你有多少的人可以用,你的计划所需要的资源。
但这样就会引出一个关键问题:项目的参与者真的只是一些可以替换的角色吗?敏捷方法的一个关键特点就是推翻了这项假设。
Alistair Cockburn就是一个强烈反对把人看做资源的这种做法的人。在他的论文《Characterizing People as Non-Linear, First-Order Components in Software Development中,提出一个观点,可预测型过程需要它的各个组成部分也必须是可以预测的。然而人从来就不属于可以预测的部分。他还进一步研究了软件项目,得出的结论是,人是软件开发中最重要的要素之一。
尽管Cockburn是如此尽力的宣传这种软件开发须以人为中心的思想,可是这种以人为先的思想却还只是软件领域那群思想家笔下的共同主题。造成这种现象的最常见的一个问题就是旧有的方法排斥这种以人为先的的思想。
这就产生恶性循环:因为你希望你的开发人员都能成为统一标准的编程机器,你就不会把他们视为一个个有个性的人。这样,士气和生产力就下降了。你的优秀的员工会离开你,找个更好的地方,而你那希望大家都成为同一编程机器的想法最终是失败了。
要转变观念需要很大的决心,而且需要许许多多的决策来支持推动。视人为资源的观念已经深入人心了,其根源甚至可以追溯到Frederick Taylor的科学的管理方法的影响(译者注:Frederick Taylor提出的管理思想是针对大工业时代的生产的)。在一个工厂中,Frederick Taylor的方法或许用效。但是对于有着非凡的创造力的计算机专家而言,这种方法就未必有用了。(实际上,现代的工厂也已经淘汰了Frederick Taylor的方法了)
文章来源于领测软件测试网 https://www.ltesting.net/