2015年5月19日下午Martin Fowler在深圳做了一次讲座,我有幸参加了。Martin Fowler分享了Agile精髓和一个Agile流畅度模型,他演讲的内容在他的博客中都有,链接如下:
http://martinfowler.com/articles/newMethodology.html
http://martinfowler.com/articles/agileFluency.html
我本打算整理一下我的笔记,然后写篇短文分享出来,结果在参考上面的链接的时候,发现里面的内容比他演讲的内容更加详尽,所以我就尝试把他上面的文章翻译了一下,由于文章内容较多,我挑重点翻译的,在翻译方面还处于菜鸟阶段,所以很费力,耗费一天的时间才翻译了第一篇(一套新方法)。下周会尝试翻译另外一篇(Agile流畅度模型)。翻译中难免疏误,欢迎指正。
从无方法,到计划驱动方法,再到敏捷
大部分的开发过程一片混沌,可以简单的概述为“开发,然后解bug”。没有太多计划,对于整个系统没有一个核心的设计,而是根据短期的需求不断的打补丁,当系统不大的时候这种方法还行得通,但是当系统变得越来越复杂,添加新功能就会变得越来越困难,bug就会越来越多,而且还很难修复。这样的系统在完成一个功能之后都必须要进行一个很长时间的测试周期,由于此时的bug很难调试而且很难修复,所以这个测试周期通常无法预测,软件开发计划也很难进行。
最开始,人们视图解决这个问题的方法是制定一系列的流程,来确保软件开发可预测更高效。于是他们会制定非常详细的流程,并且特别强调“制定计划“的环节,下面我将把这种方法称之为工程方法(也被广泛的称之为计划驱动方法)。
工程方法被使用了很长一段时间,但没有成功;人们对它最多的批评是“太官僚化”,按照这个方法,会有太多的步骤,整个流程走下来太耗费时间,拖慢开发进度。
敏捷方法与工程方法是相对的,很多人喜欢敏捷是因为它不像工程方法那么“官僚”,它是太多流程和无流程之间的折中,它提供刚好够用的流程。
敏捷方法和工程方法的区别在于他们的侧重点不同,比如,相比较而言,敏捷方法不是文档导向型,而是代码导向型的,或者说,在敏捷方法中,代码本身就是文档。
但是我认为这不是二者的核心区别,忽视文档只不过是表象,它们有更深层次的区别:
敏捷方法强调自适应性而非可预见性。工程方法倾向于花较长的时间,来给软件开发过程制定一个大而全的计划,然后严格按照计划执行,在无变化的环境下这个方法挺好,它天性排斥变化。而敏捷方法,则拥抱变化;它会适应变化并随变化生长,甚至进化。
敏捷方法强调以人为本而非以流程为本。工程方法的目标是制定一个通用的流程,不管套用在谁身上,都能适用。敏捷方法则坚定的认为,没有任何流程可以取代开发团队的技术和能力,而流程,仅仅是为团队服务的工具。
下面我将详细阐述他们的区别。
可预见性与自适应性
1. 设计与实现的分离
我们会不自觉的受机械工程方法和土木工程方法的影响,它们强调在建造之前要做详尽的计划。工程师们会画出很详尽的图纸,在上面标记出需要什么样的材料,并能表示出如何把这些材料组合出最终的东西,这些图纸会转交给别的团队,通常是另外一个公司,让他们去建造。这个方法的前提是,建造过程能够按照图纸进行下去,实际建造的时候虽然总会遇到一些问题,但通常都是些小问题。
因为图纸能够详细表明建造的过程,那么就能根据这些图纸制定一个计划,比如一共有多少子任务,每个任务的依赖关系等等,都可以制定出来,甚至连工人应该怎么工作都有详细的说明,于是就能评估时间表和预算了。在这种方式下,工人无需多少知识技能,只要手脚麻利就可以了。
所以设计与实现这两者的差异就很明显了,设计通常比较困难,而且很难预测,需要昂贵的富有创造力的人才能制定;而实现过程则比较容易预测。只要设计图出来了,我们就可以计划整个流程;只要能够计划整个流程,我们就能很好的预测。在土木工程中,建造过程的成本远大于设计和计划阶段的成本。
于是,人们很容易想到在软件工程方法中也引入类似的方法:我们也把设计实现分离,让高水平的人做出软件设计,然后让低水平的人去写代码,这样的话,软件开发过程就能预测了,也能详尽的计划了。听起来不错,但我们首先要找到能详尽的表示软件设计的方法。
在软件设计中有一个术语:“UML”,如果我们能把所有的决策都用UML来表示,我们就可以制定一个实现计划了,然后把设计交给码农们去实现就好了。
但是这里隐含一个关键问题:你能给出一个可以预测实现过程并且可以直接转化代码的设计吗?即便能,那么做出这个设计的成本足够少吗?能少到值得去做吗?
由此我们想到一些问题。首先,做出一个能够交给码农去执行的设计的难度会有多大。问题是,类似于UML这样的设计,往往在纸上看起来挺好看,在实际编码的时候总是遇到问题。土木工程的设计图是建立在多年的实践基础上的,而且更关键的是,它这种设计是可以通过数学分析和计算来掌控的。UML这样的图表能够帮助我们做代码review,但它常常带来设计上隐性错误,这些错误只有在编码或者测试的时候才被发现,即便是非常高水平的设计师,比如说我,也经常在付诸代码的过程中发现新问题。
另一个问题是相比较下的成本。如果你建造一座桥,设计成本不过占10%,剩下的都是实现成本。在软件中,通常只有15%的编码和单元测试时间,即便你把所有的测试时间算做实现时间,那么剩下的设计时间依然不少于50%(译者注:解bug时间应该算作是对设计的完善,也属于设计时间)。这就引发了一个重要的问题:软件设计与土木工程上的设计到底有何本质不同?
对于这个问题,Jack Reeves认为:源代码本身就是设计文档,实现阶段实际上是编译和链接阶段。的确,任何你被认为是实现的东西都已经能够并且应该自动化。
由此我们得出一些重要结论:
在软件开发中,实现过程的成本已经接近于零。
软件的所有工作都是设计,所以需要富有创造力和才华的人
创造性的过程是很难被计划的,所以预测它是无法完成的任务。
我们必须对传统工程学方法保持警惕,不同的活动需要不同的方法。
2. 需求的不确定性
经常有开发者抱怨说“项目的需求总是在变化”。其实这背后是有原因的。
我们通常把需求的变化归结为需求分析人员的工作不到位。并且以为,需求分析师应该详细的列出需求条款,然后让客户在上面签字画押,后面再制定一些限制需求变化的流程。
这里隐藏一个问题,完全理解需求条款是很难的。更让客户为难的是,软件开发方通常不会在需求条款里提供成本信息。
因为预估成本是非常困难的。首先,软件开发本身是一个设计活动,很难去计划和评估成本;其次,软件开发对于参与进来的个体具有非常强的依赖,而个体是有差异,也很难去预测和量化。
另一方面,软件是看不见摸不着的。你很难弄清除一个软件功能到底能给你带来多少价值,除非你真实的使用它;只有当你见到早期版本的时候,你才能看到哪些功能有价值哪些没有价值。
于是就有了这个讽刺的结论,人们希望需求可以变化。毕竟,软件应该是“软”的。所以,需求不仅是可变的,而且应该是可变的。和软件的客户一下子敲定需求是很难的,特别是那些对软件开发了解一点,但不是很多的人,更难;因为他们“知道”软件是易变的。
今天的商业力量在改变软件新功能的价值,客户在6个月前定义的需求已经不是那么有价值的需求,即使客户曾经确认了需求并且敲定,商业世界也不会因此而停止,客户的价值还是会有损失;于是,如果别家的软件可以根据需求变化,那么你将不具有竞争力。
软件开发中的一切都依赖于需求,如果你无法保证需求变化,你也就无法制定一个可以预测的计划。
3. 预测是可能的吗?
简短的回答是,不可能。有一些软件开发是可以预测的。比如像NASA(美国国家航空航天局)这样的机构,他们的软件开发是可以预测的。因为他们有很多的时间,很大的团队,和稳定的需求,他们的项目都是太空飞行器。然而,我认为大多数的商业软件都不属于这一类,你需要另外一种方法。
一个较大的风险是对于一个无法预测的工作使用一个预测性的流程。这对人很有吸引力,大家都期望事情是可以预测的,然而,在无法预测的时候选择相信事情是可以预测的,将会使人们早早的制定详尽的计划,但却不能正确处理计划“摔跟头”的情形,你只能眼睁睁的看着计划和现实越来越远,你可以假装计划仍然有效,但是,最终你将看到计划“摔跟头”的情形,而且会“摔”的很疼。
所以,当你处在一个无法预测的环境中时,就不要使用预测性的方法。现实总是残酷的。也就是说,控制项目的模型,为客户关系所建立的模型,都不再有效。预测性的方法很好,放弃它很难,这有点像“最困难的事情就是承认困难存在”。
然而,放弃预测,并非意味着回到之前完全失控的混沌状态,你需要一套可以控制不可预见性的方法,这正是我要说的自适应性方法。
4. 控制不可预测的方法-迭代
那么,我们如何在未知的世界中控制自己呢?最重要的,也最难的是,弄清楚我们在哪儿,我们需要一个诚实的反馈机制,来每隔一小段时间精确的告诉我们当下所处的位置。
建立这种反馈机制的核心是迭代开发。这不是个新思路。迭代开发已经有段历史了,它有许多其他的名字:增量开发,演进开发,阶段开发,螺旋式开发...等等很多名字。迭代开发的关键是经常产生一个可用版本,这个可用版本的功能是最终版本的子集,每个迭代新增的功能都很小,但每个版本都向最终版本更近一步,它们会像发布最终版本一样,都要经过集成并通过完整测试。
这么做是因为没有什么能比一个经过集成测试后的系统更真实,更让人放心。文档常常存在缺陷,未经测试到代码中也常常隐藏着缺陷,但是当人们坐下来,真实的使用系统的时候,才会发现缺陷,可能是bug,也可能是需求的错误。
迭代式开发也适应于可预测的工作中。但是,对自适应性流程来说,迭代是必不可少的,因为自适应流程需要处理好需求的变化。于是计划就变成这样子的:长期的计划可能会变,但基础不经常变,而每次迭代都是完成一个短期计划,每个短期计划都是执行大计划中比较稳定的部分。迭代式开发的每个迭代,都给下个迭代的短期计划打下坚实的基础。
有人会问,一个迭代应该要多久呢。不同的人可能有不同的答案。极限编程建议迭代是一到两周,SCRMUM则建议一个月,而现在的趋势是,尽量把迭代时间缩短到你能承受的程度,这会带来更快的反馈,你也因此更加频繁的知道自己在哪儿。
5. 自适应的客户
这种自适应的方法需要一种不同的客户关系,以往的客户期望固定价格的合同,告诉软件开发公司他们需要什么,询问报价,接受报价,然后开发任务就交给软件开发公司了。
而在自适应方法中,客户能更精细的调控软件开发过程。每个迭代中,他们可以检查进度,也可以改变软件开发的方向。这就使得客户和软件开发者的关系更亲密,更像合作伙伴。这种参与,不是因为客户,也不是因为软件开发者,而是因为只有这样,自适应方法才能得到良好发挥。
这么做能给客户带来巨大的优势。首先,他们的需求能得到快速反馈。一个可用的尽管很小的系统,可以较快的上线,尽早的给客户带来价值,然后客户可以根据商业的变化改变它的功能需求,而且也可以在这个过程中自然的学习到该系统的用法。大部分人应该已经注意到,人们通常一开始不知道自己对软件的需求是什么,当他用到软件的时候才意识到哪些功能是真正能给他带来价值的。敏捷方法鼓励人们在每个迭代发布的版本中发现自己的需求,这种随需求变化而构建的软件具有较强的竞争力。
所有方法都有一个评定项目成功与否的方式。可预测的项目,通常由它与原计划的契合度来评定,如果按时按量完成就是成功。但这种方法对于敏捷来说没有任何意义,敏捷主义者追求的是商业价值——客户是否获得比成本更高的价值。一个好的可预测项目根据计划进行,而一个好的敏捷项目则会打造一个比最初所计划的更好的计划。
以人为本
执行自适应方法不容易。它需要一个非常有效的开发团队,而且每个成员要有效,成员间的协作也要有效。有一个有趣的现象:不仅仅自适应性的流程需要一个强有力的团队,大部分的优秀开发者也喜欢自适应的流程。
即插即用的编程单元
传统方法的目标之一是,开发出一个流程,使得参与流程中的人们是可以被替换的。在这种流程中,你可以把人看作是资源,不同技能的人是不同类型的资源。比如分析师,码农,测试人员,以及经理,每个个体都不是特别重要,重要的是角色。于是,如果你计划一个项目,哪个分析师或者哪个测试参与进来都无关紧要,你只需要知道有多少资源,你就能知道你的计划会不会受到影响。
但是这里有一个关键问题,软件开发中的个体是可以被替换的吗?敏捷方法给出的答案是否定的。
或许反对把人当作资源的声音最高的人当属Alistair Cockburn,在他的一篇论文里指出,“人是高度可变的,非线性的,有时高效有时低效,这些都是很直接的并且不容忽视的因素...人是软件开发中最重要的因素。”
其实许多软件开发的思想家,都持有软件开发应以人为先的观点。但是要推行以人为先是一个很大的决定,需要很大的决心去推动。因为把人当作资源的观念已经在商业思维中根深蒂固,它起源于Frederick Taylor's的《科学管理方法》一书。在工厂生产中,Taylor的方法可以奏效,但是对于高度创新性和专业的工作,比如软件开发,就不怎么奏效了。(实际上,现在的制造方法已经开始放弃Taylor的方法了。)
码农是负责任的专业人士
Taylor观点认为,实际干活的人无法评估自己最大能干多少活。在工厂中这可能是有道理的,原因之一可能是工厂的工人不是那么聪明和富有创造力的人,也可能是因为管理层和工人之间有种紧张的气氛,因为管理层挣得的钱多而工人挣得少。
最近的历史越来越表明,软件开发中没有这样的事。越来越多的聪明能干的人被吸引到软件开发中来,因为它听起来高大上而且能挣大钱。(我就是因此而从电气工程转行过来的。)尽管在00年代早期出现过下滑,但在软件开发行业中仍然涌现出了大量的天才和创新。
当你想要雇佣和保留好的人才时,你需要甄别出他们是否是有能力的专家。就本身而论,他们自己才是指导自己工作的最佳人选。Taylor的观念是把计划部门分离出来,来专门做计划,告诉工人如何工作,这种方式只有在计划者比工人更懂得如何工作的情况下才可行。如果你有一个批聪明主动的人工作,就不要采用这种方法了。
管理以人为本的流程
这里的关键因素之一是,接受流程而非强加一个流程。通常软件流程是被管理层强加上去的,于是开发人员会反抗,特别是当管理层人员已经很长时间没有参与开发活动的情况下,更是如此。接受一个流程需要用心投入,需要整个团队的主动参与。
由此得出一个有意思的结论,只有开发者自己可以选择采用哪个自适应流程。
另外一个结论是,开发者必须能够做技术决策。
于是技术型的领导面临一个很大的转变,他需要分享他的责任给开发者,并且在领导项目的时候与开发者处在一个相等的位置,注意我说的是*相等*,管理人员仍然扮演着他应有的角色,但需要考虑到开发者的专业意见。
现在科技行业发展很快,过不了几年现有的技术就会过时,近50年的科技行业的发展是其他行业无法匹敌的。甚至技术人员也开始意识到,进入管理层就以为着自己的技术水平将会枯萎;已经进入管理层的*前开发者*需要认识到,他们的技术水平将会快速消失,他们需要信任并依赖当前的开发者。
评估的困难
在Taylor的方法中,做计划设计的人和实际干活的人是不同的人,于是领导们需要一种方法来评估干活的人的有效性。《科学管理方法》一书中特别强调说,要开发出一种客观的评估劳动成果的方法。
但是,评估软件是一件非常困难的事情,即便我们竭尽全力,也很难对软件中哪怕很简单的东西进行评估,比如产量。如果没有办法对这些东西很好的评估,任何外部的控制都是徒劳的。
对于无法评估的东西使用评估性方法来管理会导致问题。Robert Austin对此曾进行过精彩的论述。他指出,当评估绩效的时候,你必须获得所有需要评估的重要因素,任何一个因素的缺失都将导致这样一个结果:干活的人会改变他们的产出物以获得最佳的评估结果,即使他们的做法明显损害了产出物的质量,他们也会这么做。这种管理失效的情况是基于评估的管理方法的阿克琉斯之踵。
Austin的结论是,你必须在基于评估的管理方法和授权式管理方法(这种方法下,干活的人自行决定如何干活)中做出选择。基于评估的管理最适应于重复的简单性工作,对知识要求很低而且容易评估产出——这与软件开发的特点刚好相反。
总而言之,传统的方法都基于这样一个设想,基于评估的管理方法是最高效的管理方法。敏捷社区发现,软件开发很特别,如果对它采用基于评估的方法管理,将会导致管理失效;在实践中,采用授权式管理更加高效,而这正是敏捷人的核心方法之一。
业务领袖的角色
然而,技术人员无法单独搞定整个开发过程,他们需要业务需求的指导。这就引出了敏捷方法另外一个重点:开发者需要与业务专家紧密配合。
这种紧密程度超出了大多数类型的项目。敏捷团队如果只是与业务专家进行偶尔的交流,那它就不能称之为敏捷团队,他们需要不间断的交流;并且这种交流的通道不能仅仅限于管理层,每个开发者也应该能随时获取。既然开发者能胜任自己的专业工作,那么他们也需要能够与其他领域的专业人士进行协作。
当然,这很大程度上是因为,敏捷开发方法的本质。既然敏捷开发的大前提是事物在快速变化,那么你就需要经常联系开发者,告诉他们什么发生了变化。
对于开发者来说,没什么能比,眼睁睁的看着自己的工作白白的浪费掉,更痛苦的了。所以,保证业务专家的专业水平,让开发人员信服,以及保证他与开发者之间沟通的畅通性,就变得非常重要。
方法本身的自适应
至此,我们讨论了软件开发项目为了适应客户需求的变化必须不断调整。然而,还有另外一个角度来看待自适应性:那就是自适应方法本身随时间演变。一个项目,在开始时采用的自适应方法,与一年后采用的自适应方法,在具体准则和细节上,不会完全一样。随着时间的推进,团队将会发现怎么做会更好,然后会改进自适应方法本身。
要做到方法本身的自适应性需要对方法进行定期的回顾,通常可以在每个迭代中进行。在每个迭代结束时,开一个小会,团队扪心自问以下问题:
我们哪里做得不错?
我们学到了什么?
我们哪里可以做得更好?
我们有何困惑?
这些问题可以帮助你们在下个迭代中改进工作方法,这样,工作方法本身随着项目的开展,也会变得越来越好用。