新方法学

Chief Scientist,Thoughtworks 2004.3 从无、到繁重、再到敏捷

多数软件开发仍然是一个显得混乱的活动,典型的“边写边改”(code and fix)。设计过程充斥着短期的、即时的决定,而没有完整的规划。这种模式对于小系统开发其实很管用,但是当系统变得越来越大,越来越复杂的时候,要想加入新的功能越来越困难,同时,错误故障越来越多,越来越难排除,一个典型的标志就是当系统功能完成后有一个很长的测试阶段,有时甚至有遥遥无期的感觉,从而对项目的完成产生了眼中的影响。

而“正规方法”(methodology),对软件过程有着严格而详尽的规定,以期使软件开发更有可预见性并提高效率,这种思路借鉴了其他工程领域的实践-因此我们称之为工程方法。工程方法存在了很长的实践,但是没有取得令人瞩目的成功,甚至没有引起人们注意。对这种方法最常见的批评就是他们的官僚繁琐,要是按照它的要求来,那有太多的事情要做,从而延缓整个软件开发过程。

敏捷型和工程型方法有一些显著的区别,其中一个显而易见的不同反映在文档上,敏捷型不是很面向文档,对于一项任务,它们通常只要求尽可能少的文档,从很多方面来看,它们更像是“面向源码”。事实上,它们认为最根本的文档就是源码。更深层的两个特点是:

1.          敏捷方法是“适应性”而非“预见性”的。工程方法试图对一个软件开发项目在很长时间跨度内做出详细的计划,然后依据计划进行开发。这类方法在一般情况下工作良好,但是当环境、需求有变化的时候,就不太灵了。因此它们的本质上是拒绝变化的,而敏捷方法是欢迎变化的。

2.          敏捷方法是“面向人”的而非“面向过程”的。工程型方法的目标是定义一个过程,不管是谁用都工作,而敏捷方法则认为没有任何过程能够替代开发组的技能。过程起的作用就是对开发组的工作提供支持。 预设性和适应性 将设计和建造分离开来

传统的软件开发正规方法的基本思路是从其他工程领域借鉴来的,这类工程实践中,在实际建造之前,通常非常强调设计规划。这种方式其实已经假定了建造过程将按照图纸而来,当然,施工中也会碰到一些问题,但是这些都是次要的。图纸其实就是一个详细的建造计划,它说明了一个项目中必须完成的各个部分,以及如何把这些部分装配成整体,这样的计划可以进一步定出需要完成的各项任务,以及这些任务之间的依赖关系,这样,能够较为合理地制订出生产进度表和项目预算。这种模式实际上也规定了建造者如何施工,这也隐含着建造者不需要是高智能型的,尽管他们可能都有非常高超的手上功夫。

但是,软件中,设计是难以预见的,而且需要昂贵的创造性人员,建造则要易于预设。在土木工程中,建造不论在经费上,还是实践上的成本都比设计和计划大很多。

一个关键的问题是:你能否做出这样的设计,使得他能够使编码成为一项建造活动,如果能,这样干的成本是否比充分地小而使得这条路径一用?以下是几个问题:

1.          到底有多困难,能够使一个用类似UML做出的设计交给程序员,就能直接编码的状态?用UML这样的语言,在纸上很漂亮,但是实际编程的时候,可能会发现严重的缺陷;

2.          费用比较:建造一座桥梁,设计费用一般占到整个工程的10%左右,余下的90%左右为施工建造费用。而在软件开发中,编码实践一般要少得多。即使把所有的测试工作都算作建造的一部分,设计仍然要达到50%。那么和其他过程领域的设计相比,软件设计到底是什么性质?

Jack Reeves提出:源码也应该是设计文档,而建造应该是编译和链接。的确,任何你认为属于建造的工作,都应当是自动化的。

这些讨论导致了下面一些重要结论:

1.          在软件开发中,具体建造费用非常低,几乎可以忽略不计;

2.          软件开发中所有工作都是设计,因此需要富有创造性的才智之士;

3.          创造性的过程不太容易计划,因此,可预见性是一个不可能达到的目标;

4.          我们应该对用传统工程模式来进行软件开发的做法保持足够的警觉,因为他们是不同类型的活动,因此需要不同的过程。 需求的不可预见性

一种方法是把需求变更看成是因为需求工程没有做好而导致的结果,一般来说,需求工程是在着手建造软件之前,获取一幅已经完全理解的待建系统的画面,然后取得客户签字认可,并且还要建立一套流程来限制需求变更。

这个方法的问题是,要准确获取所有需求是困难的,特别是开发商不能提供某些需求的费用信息的时候。

做软件开发费用的估算是不容易的,这有多种原因,部分原因是因为软件开发是一种设计活动,因此难以精确计划,部分原因是因为系统的“基本材料”变化非常之快,部分原因是开发活动极大地依赖于项目参与人员,而个体是难以预测和量化的。软件的“不可触摸”性也是一个原因,在系统建成之前,有时很难判断一项功能的具体价值,也就是说,只有当你在实实在在使用系统的时候,你才知道哪些功能是有用的,哪些没有用。而且,即使你把所有的需求都固定下来的,在当今的经济形势下,决定并且推动软件系统功能性的商业因素在飞快变化。

软件开发的一切都取决于系统需求,如果需求不能固定,那么就不能制定出一个可预见的计划。 预见性是不可能的吗?

一般来说,不可能。

如果你不能遵循一个可预见性方法,而你强装能,这是很危险的。通常,一个正规方法的创造者不是很善于(乐于)给出其方法的边界条件,当这些边界条件不能满足的时候,这个方法是适用的。

适用预见性方法具有强烈的诱惑性,因为预见性毕竟是一个非常需要的特征,可是,当你不能达到预见性的时候而你相信你能够,这将导致这样一种局面:你可以很早制订出计划,但是不能恰当地处理计划崩溃的情况。你看见现实和计划慢慢地偏离,而你可以在很长的时间中,装作认为计划仍然是有效的。但是当偏离积累到足够的时候,你的计划就崩溃了,这通常是很痛苦的。 不可预见过程的控制—迭代

迭代式开发的要点就是经常不断的产生出最终系统的工作版本,这些版本逐步地实现系统所需要的功能,他虽然功能不全,但是已实现的功能必须忠实于最终系统的要求,他们必须是经过全面整合和测试的产品。理由是:没有什么比一个整合了的,测试过的系统更能够作为一个项目扎扎实实的成果。文档可以隐藏所有的缺陷,未经测试的程序可能隐藏许多缺陷。但当用户实实在在地坐在系统前面来使用它的时候,所有问题就会暴露出来。可能是源代码缺陷错误,也可能是对需求理解有误。

需求变更使得长期计划是不稳定的,一个稳定的计划只能是短期的,这通常是一个“迭代周期”。迭代开发能让每个周期为下面的开发计划提供一个坚实的基础。

迭代式开发的一个重要问题是一个迭代周期需要多长。XP建议是1-3周,Crystal更常一些。不过,一般的趋势是让每一个周期尽可能短。 适应性的客户

把一个固定的价格模式弄到适应性过程将是一个痛苦的过程,最糟糕的是客户将和软件开发者受到同样的伤害,毕竟客户不会想要一个不需要的软件,他们失去的要比开发商大很多。通常一个敏捷方式是固定时间和价格,而让范围能够可控制地变化。在适应性过程中,客户实际上能够对软件开发过程进行深入细微的控制,在每一个迭代过程中,他们都能检查开发进度,也能变更软件开发方向,这导致了和软件开发者更密切的关系。

这样的方法能够更真实地反映出项目的实际状态,可预见性过程的问题是:项目的质量是根据和计划的一致性来衡量的,当实际情况和计划脱节的时候,人们很难提出来。一般的结果是在项目后期出现进度上的大滑坡。在敏捷项目中,每一个周期都对计划进行评审。如果有什么糟糕的事情的话,它也会早点发现。

预见性项目是否成功由它是否很好地按计划执行来衡量的,一个项目如果在规定的时间和预算内完成,就是成功的。对于敏捷型环境来说,这种衡量没有意义,对于敏捷型项目的实践者来说,最重要的商业价值是客户得到的软件的价值是否大于他们的投入。 把人放在第一位

实施一个适应性过程并不容易,特别是它要求一组高效的开发人员。高效既体现在高素质的个体,也体现在有能让团队协调一直的工作方式。另外,并非只有适应性过程需要强的团队,多数优秀的开发人员也愿意采用适应性过程。 可兼容性程序插件

敏捷方法不认为参与软件开发的人员是可替代的部件。因为部件是可预期的,而人并非可预期的部件。并且“人是软件开发中最重要的因素”。 程序员是负责人的专业人员

泰勒注意的一个关键理念是认为干活的人并非是那些知道如何把这件活干好的人。历史证明,这种情况在软件开发中不存在。如果你想聘任并且留住优秀人才,你得认识他们是有能力的专业人员。因此,他们最优资格决定如何干好他们的技术工作。泰勒主义让计划部门来决定如何干好一件工作的做法只有当计划者比实际操作者更能知道如何做的时候才有效。如果你拥有优秀、自觉自励的员工,那么这点并不成立。 面向人的过程的管理

实施敏捷型过程的一个关键之处就是让大家接受一个过程而非强加一个过程。通常软件开发过程是由管理人员决定的,因此这样的过程常常受到抵制,特别是管理人员脱离具体、实际的开发活动很长时间了。而接受过程需要一种“自愿”,这样大家就能以积极的态度参与进来了。一个有趣的结果就是:只有开发人员自己才能选择并且遵循一个自适应过程。

另外一点是开发人员必须有权做技术方面的所有决定。在前期计划中,只有开发人员才能估计干一件工作所需的时间。 测试的困难性

如果有一个过程,规定工作应该如何来做的人,不是具体来干的人,那么你需要一些方法来测度干工作的人是否工作有效,在“科学管理”中,有种强烈的力量驱使着发展出客观方法来测度人们的产出。但是,测度软件非常困难。如果没有一套有效的测度方法,任何外部的控制都会是非常困难的。

不存在一套有效的测度方法而要在管理中引入测度将会导致管理本身出问题。“当进行测度时,你必须要获取影响这种测度的所有重要因素,任何缺失都将不可避免地使得具体干工作的人改变他们的工作方式以获得最好的测度业绩,甚至那样会明显降低他们真正的工作有效性”。结论是:你必须在两种方法中进行选择:基于测度的管理或者委托式的管理(干工作的人决定如何干)。基于测度的管理是非常适合简单、重复性、知识要求低并且易于测度输出的,这和软件开发恰恰相反。

敏捷开发者认为软件开发的特征会使得基于测度的管理导致非常高度的测度“失效”。实际上使用委托式管理方式有效的多。这正式敏捷论者所持观点所在。 业务专家的引领作用

技术人员不能包打天下,他们需要应用系统的需求引导。这导致了适应性过程的另一个重要方面,他们需要和应用领域的业务专家非常紧密的联系。

如果开发人员和业务人员只有偶尔的沟通,那么敏捷过程是不可能存在的。他们需要不断获取业务方面的知识,这种沟通不是由管理层来处理的,而是每个开发人员需要做的事情。因为开发人员在他们的行业里面是有能力的专业人员,因此他们能够域其他行业的专业人员同等地工作。

这是由于适应性过程的特点来决定的,因为敏捷开发的前提是在整个开发过程中,事情变化很快,你需要经常不断的联系沟通以使每个人都能及时知道这些变化。 自适应过程

随着时间的推移,开发团队会发现什么方式对他们的工作最好,然后改变过程以适应之。

自适应的第一步就是经常对过程进行总结检讨,一般来说,每次迭代结束以后,你可以问以下问题:

1.          有哪些做的好的部分;

2.          有哪些教训;

3.          有哪些可以改进的部分;

4.          有哪些没有搞清楚的部分;

自适应性导致的结果是你绝不能期待着只用一个过程,相反,每个项目组不仅能选择他们的过程,而且还能随着项目的进行而调整所用的过程。公开发表的过程和其他项目的经验都可以拿来作为参考和样本,但是开发人员需要根据手头项目的具体情况而对其加以调整,这也是开发人员的专业职责。 敏捷型方法 XP

XP(Extreme Programming—极限编程)。

XP的四条基本原则是:交流、反馈、简洁、勇气。并且在此基础上建立了10多条XP项目所应遵循的时间准则。

XP的一个特点是:对测试的极端重视;要求每个程序员写一段代码都得写响应的测试代码,并且这些测试片断不断积累并整合到系统中,这样系统会产生一个高度可靠的建造平台,为进一步开发提供良好的基础。

XP建立了一个渐近型的开发过程,依赖于每次迭代对源代码的重整(refactoring),所有的设计都是围绕当前的这次迭代,而不管将来的需求;这种设计过程的结果是“纪律性”和“适应性”的高度统一,使得XP在适应性方法中成为发展的最好的一种方法。 Cockburn的水晶系列方法

相信不同的项目需要不同的方法,他认为决定一个方法和两个因素有关:项目参与人数和出错后果。如果用这两个坐标轴来分别表示两个变量的话,那么在这张图上,每一种方法都有响应的坐标位置。

水晶考虑人们一般很难严格遵循一个纪律约束性很强的过程,因此,探索了用最少纪律约束仍能够成功的方法,从而在产出效率和易于运作上达成一种平衡。

水晶强调每次迭代后的总结回顾,鼓励过程本身的自我完善,理由是迭代开发是用来尽早发现问题并且解决的。这样更强调了开发人员要随时观察他们所用的过程,并且随着项目的进行而调整。 开发式源码

开发式源码项目组的一个特别之处,就是程序开发人员在地域上分布很广。

多数开放式源代码有一个或者多个源码维护者,只有维护者才能将新的或者修改过的源码并入代码库,其他人可以修改源码,但是需要把他们所做的修改提交给维护者,由维护者对这些改动进行审核并且决定是否并入源码库。通常来说,这些改动是以“补丁”文件的形势,这样处理起来更加容易一些。维护者需要协调这些改动并保持设计的一致性。

开放源码的一个突出特点就是拍错过程的高度并行性,因为很多人能够同时彩舆拍错,如果他们发现了错误,他们可以把改正的源码的“补丁”发给文件维护者,这些拍错角色对于非维护者来说合适,对那些设计能力不是很强的人来说,也是一项挺好的工作。 Highsmith的适应性软件开发方法(ASD-adaptive software development)

ASD都得核心是三个非线性的、重迭的开发阶段:猜测、合作和学习。

在一个适应性环境中,因为结果是不可预期的,Highsmith把计划看成一个反论(paradox)。在传统的计划中,偏离计划是错误,应予以纠正,在一个适应性环境中,偏离计划则是引导我们向正确的目标迈进。

在可预见性环境中,通常不大鼓励学习,设计师都已经设计好了,你跟着走就是了。但是在不可预见环境中,学习对所有各方,包括开发人员和客户,都是一个挑战,他们需要学习以检验他们的假设,需要学习以便于每次开发周期的结果去适应下一个周期。

在不可预见环境中的管理,重点不在于告诉大家做什么,而是鼓励大家交流沟通,从而使他们能够自己提出创造性的解决方案。 CSRUM

SCRUM强调这样一个事实:明确定义了可重复的方法过程只限于在明确定义了的可重复环境中,为明确定义了可重复的人员所用,去解决明确定义了的可重复的问题。

CSRUM把一个项目分为若干个为期30天的迭代阶段,称之为一“冲”(Sprint)。开“冲”以前,你必须明确这一冲要实现的功能,然后交给开发组完成,但是在冲阶段中,需求必须是固定的。

管理人员并非在冲的时候就不管了,每天,他需要召集一个短会,称之为一个Scrum,大家讨论第二天干什么,特别是大家对管理层提出那些阻碍项目进行的因素,并且希望管理层能够予以解决。当然,他们也需要报告目前完成了什么,这样管理层就能每天了解项目的进展情况。 功能驱动开发方法(FDD-Feature driven development)

在FDD中,一个迭代周期一般是两周。FDD有以下5项任务:

1.          建立总体模型;

2.          提出功用清单;

3.          针对功能逐项制定计划;

4.          针对功能逐项进行设计;

5.          针对功能逐项进行实现;

前三项在项目开始时完成,后两项在每一个迭代周期中都要做。

FDD中,编程人员分为两类,首席程序员和类程序员。首席程序员是最富有经验的开发人员,负责开发实现系统的各项功能。对每一项功能,首席程序员要制定出需要哪些类来实现这些功能,并召集类程序员组成一个针对这项功能的开发组。首席程序员是协调者、设计者和指导者;类程序员主要作源码编写。 你是否应该走向敏捷?

如下的因素建议你采用适应性过程:

1.          不确定或者经常变更的需求;

2.          负责任的、自觉自励的开发人员;

3.          理解并且愿意参与其中的客户;

而以下因素则建议你采用可预见性的过程:

1.          100人以上的项目组;

2.          固定价格,或更明确的说,固定任务范围的合同。


文章来自: 本站原创
引用通告: 查看所有引用 | 我要引用此文章
Tags:
评论: 0 | 引用: 0 | 查看次数: 4991
发表评论
你没有权限发表评论!