新方法论
在过去几年中,一种新的软件方法论风格——敏捷方法——蓬勃发展起来。 它们被认为是官僚主义的解药或黑客的许可证,在整个软件领域引起了人们的兴趣。 在本文中,我将探讨敏捷方法的原因,重点不在于它们的重量,而在于它们的适应性和以人为本的导向。
2005年12月13日
近年来,软件过程思维最明显的变化可能是“敏捷”一词的出现。 我们谈论敏捷软件方法、如何将敏捷性引入开发团队,或者如何抵御决心改变既定实践的敏捷主义者的迫在眉睫的风暴。
这场新运动源于 20 世纪 90 年代处理软件过程的各方面的努力,他们发现软件过程存在不足,并寻求一种新的软件过程方法。 大多数想法并不新鲜,事实上,许多人认为很多成功的软件很长一段时间以来都是以这种方式构建的。 然而,有一种观点认为,这些想法受到了压制,没有得到足够认真的对待,尤其是那些对软件过程感兴趣的人。
这篇文章最初是这场运动的一部分。 我最初是在 2000 年 7 月发表的。 像我的大多数文章一样,我写这篇文章是为了试图理解这个主题。 那时,我有幸在 1996 年与 Kent Beck、Ron Jeffries、Don Wells 以及最重要的是克莱斯勒 C3 团队的其他成员一起工作,之后我已经使用极限编程好几年了。 从那时起,我与其他对软件过程有类似想法但不一定想走极限编程相同道路的人进行了交谈并阅读了书籍。 因此,在这篇文章中,我想探讨这些方法之间的异同。
我当时的结论是,现在我仍然相信,有一些基本原则将这些方法论统一起来,而这些原则与已建立的方法论的假设形成了鲜明的对比。
这篇文章一直是我网站上最受欢迎的文章之一,这意味着我觉得有必要对其进行更新。 在其原始形式中,这篇文章既探讨了这些原则上的差异,也对我当时所理解的敏捷方法进行了调查。 自从我无法跟上调查部分以来,敏捷方法发生了太多事情,尽管我确实提供了一些链接以供您继续探索。 原则上的差异仍然存在,我保留了这方面的讨论。
从无到有,从庞大到敏捷
大多数软件开发都是一项混乱的活动,通常以“编码和修复”来描述。 软件的编写没有太多的底层计划,系统的设计是由许多短期决策拼凑而成的。 当系统很小时,这实际上很有效,但随着系统的增长,向系统添加新功能变得越来越困难。 此外,错误变得越来越普遍,也越来越难以修复。 此类系统的一个典型标志是在系统“功能完成”后有一个漫长的测试阶段。 如此长的测试阶段会对进度造成严重破坏,因为测试和调试是不可能安排的。
最初试图改变这种情况的运动引入了方法论的概念。 这些方法论对软件开发施加了严格的流程,旨在使软件开发更可预测和更高效。 他们通过开发一个详细的过程来做到这一点,该过程非常强调受其他工程学科启发的计划——这就是为什么它们通常被称为计划驱动方法论的原因。
计划驱动的方法论已经存在很长时间了。 它们并没有以非常成功而著称。 它们更不以受欢迎而闻名。 对这些方法论最常见的批评是它们是官僚主义的。 遵循该方法需要做的事情太多了,以至于整个开发速度都慢了下来。
敏捷方法论是作为对这些方法论的反应而发展起来的。 对许多人来说,这些敏捷方法论的吸引力在于它们对计划驱动方法论的官僚主义的反应。 这些新方法试图在没有流程和流程过多之间找到一个有用的折衷方案,提供足够的流程以获得合理的回报。
所有这一切的结果是,敏捷方法与计划驱动方法相比在重点上发生了一些重大变化。 最直接的区别是它们不那么以文档为导向,通常强调为给定任务减少文档量。 在许多方面,它们都相当以代码为导向:遵循一条路线,即文档的关键部分是源代码。
然而,我认为这不是敏捷方法的关键所在。 缺乏文档是两个更深层次差异的症状
- 敏捷方法是适应性的,而不是预测性的。 计划驱动的方法倾向于尝试详细计划软件过程的很大一部分,这在事情发生变化之前都很有效。 所以他们的本性是抗拒改变。 然而,敏捷方法欢迎变化。 他们试图成为适应变化并在变化中茁壮成长的过程,甚至改变自身。
- 敏捷方法是以人为本的,而不是以流程为导向的。 计划驱动方法的目标是定义一个无论谁使用都能很好地工作的流程。 敏捷方法断言,没有任何流程能够弥补开发团队的技能,因此流程的作用是支持开发团队的工作。
在以下部分中,我将更详细地探讨这些差异,以便您了解自适应和以人为本的流程是什么样的、它的优缺点,以及您是否应该使用它:作为开发人员或软件客户。
预测性与适应性
设计与构建分离
方法论的通常灵感来自土木或机械工程等工程学科。 此类学科非常强调在构建之前进行规划。 此类工程师将处理一系列图纸,这些图纸精确地指示需要构建什么以及如何将这些东西组合在一起。 许多设计决策,例如如何处理桥梁上的负载,都是在绘制图纸时做出的。 然后将图纸移交给另一个小组(通常是另一家公司)进行建造。 假设施工过程将遵循图纸。 实际上,建设者会遇到一些问题,但这些问题通常很小。
由于图纸指定了零件以及如何将它们组合在一起,因此它们充当了详细施工计划的基础。 此类计划可以确定需要完成的任务以及这些任务之间存在哪些依赖关系。 这允许为施工制定合理的可预测的时间表和预算。 它还详细说明了进行施工的人员应该如何进行工作。 这使得施工在智力上不那么熟练,尽管他们通常在手工方面非常熟练。
所以我们在这里看到了两种截然不同的活动。 设计难以预测,需要昂贵且有创造力的人才,而施工则更容易预测。 一旦我们有了设计,我们就可以计划施工。 一旦我们有了施工计划,我们就可以以一种更可预测的方式来处理施工。 在土木工程中,施工的成本和时间都比设计和规划要大得多。
因此,软件工程方法论的方法如下:我们需要一个可预测的时间表,可以使用技能较低的人员。 为此,我们必须将设计与施工分开。 因此,我们需要弄清楚如何进行软件设计,以便一旦计划完成后,施工就可以直接进行。
那么这个计划采取什么形式呢? 对许多人来说,这是设计符号的作用,例如 UML。 如果我们可以使用 UML 做出所有重大决定,我们就可以制定一个施工计划,然后将这些设计交给编码员作为施工活动。
但这里有一个关键问题。 您能否获得能够将编码转变为可预测的构建活动的设计? 如果是这样,这样做的成本是否足够低,以至于这种方法值得一试?
所有这些都让人想到了一些问题。 首先是如何将类似 UML 的设计转变为可以移交给程序员的状态有多困难。 类似 UML 的设计的问题在于它在纸面上看起来可能非常好,但在您实际必须对它进行编程时却存在严重缺陷。 土木工程师使用的模型基于多年的实践经验,这些经验都体现在工程规范中。 此外,关键问题(例如力在设计中的作用方式)可以通过数学分析来解决。 我们可以对类似 UML 的图表进行的唯一检查是对等评审。 虽然这很有帮助,但会导致设计中的错误,这些错误通常只在编码和测试过程中才会发现。 即使是像我这样自认为是熟练的设计师,在我们将这样的设计变成软件时也常常会感到惊讶。
另一个问题是比较成本。 当您建造一座桥梁时,设计工作量的成本约为整个工作的 10%,其余为施工。 在软件中,花在编码上的时间要少得多。 McConnell 表示,对于一个大型项目,只有 15% 的项目是代码和单元测试,这与桥梁建造比率几乎完全相反。 即使您将所有测试都归为施工的一部分,那么设计仍然占工作的 50%。 这就提出了一个重要的问题,即与软件设计在其他工程分支中的作用相比,软件设计的性质如何。
这些类型的问题导致 Jack Reeves 建议,实际上源代码就是设计文档,而构建阶段实际上是编译器和链接器的使用。 事实上,任何您可以将其视为构建的东西都可以而且应该自动化。
这种想法导致了一些重要的结论
- 在软件中:构建非常便宜,以至于免费
- 在软件中,所有的努力都是设计,因此需要有创造力和才能的人
- 创造性过程不容易计划,因此可预测性很可能是一个不可能实现的目标。
- 我们应该对传统的软件构建工程比喻持非常谨慎的态度。 这是一种不同的活动,需要不同的流程
需求的不可预测性
在我遇到的每个问题项目中,我都听到过一个说法。开发人员来找我说:“这个项目的问题是需求总是在变”。这种情况让我感到惊讶的是,竟然有人对此感到惊讶。在构建业务软件时,需求变更很正常,问题是我们如何应对它。
一种方法是将不断变化的需求视为需求工程不佳的结果。需求工程背后的理念是在开始构建软件之前全面了解需求,获得客户对这些需求的签字确认,然后建立程序以限制签字确认后的需求变更。
这样做的问题之一是,仅仅试图了解需求的选择就很困难。更难的是,开发组织通常不提供需求的成本信息。你最终会陷入这样的境地:你可能想要在你的车上安装一个天窗,但销售员无法告诉你它是增加了 10 美元还是 10,000 美元。在对成本没有太多了解的情况下,你怎么能确定你是否愿意为那个天窗买单呢?
估算很困难,原因有很多。部分原因是软件开发是一项设计活动,因此难以计划和估算成本。部分原因是基本材料在不断快速变化。部分原因是很多事情取决于参与的个人,而个人难以预测和量化。
软件的无形性也起到了作用。在真正使用软件功能之前,很难看出它的价值。只有当你使用某个软件的早期版本时,你才会真正开始了解哪些功能是有价值的,哪些部分是没有价值的。
这导致了一个讽刺的观点,即人们期望需求应该是可变的。毕竟软件应该是*软*的。所以,需求不仅是可变的,而且应该是可变的。让软件客户确定需求需要花费大量的精力。如果他们自己曾经涉足过软件开发,那就更糟了,因为他们“知道”软件很容易更改。
但即使你能够解决所有这些问题,并且真的能够获得一套准确且稳定的需求,你可能仍然注定要失败。在当今的经济环境下,基本的商业力量正在改变软件功能的价值,而且速度非常快。现在可能是一套很好的需求,但在六个月后就不是了。即使客户能够确定他们的需求,商业世界也不会为他们而停滞不前。商业世界的许多变化是完全不可预测的:任何说不可预测的人要么是在撒谎,要么已经在股票市场交易中赚了十亿美元。
软件开发中的其他一切事物都取决于需求。如果你无法获得稳定的需求,你就无法获得可预测的计划。
可预测性是不可能的吗?
总的来说,不能。在某些软件开发中,可预测性是可能的。像美国宇航局航天飞机软件小组这样的组织就是软件开发可以预测的典型例子。它需要大量的仪式、充足的时间、庞大的团队和稳定的需求。有些项目就像航天飞机一样。然而,我认为很多商业软件不属于这一类。为此,你需要一种不同的流程。
最大的危险之一是在你无法遵循可预测的流程时假装你可以遵循。从事方法论工作的人不擅长识别边界条件:方法论从适用到不适用的地方。大多数方法论学家希望他们的方法论对每个人都适用,所以他们不理解也不宣传他们的边界条件。这导致人们在错误的情况下使用一种方法论,比如在不可预测的情况下使用可预测的方法论。
这样做很有诱惑力。可预测性是一个非常理想的特性。然而,如果你相信你可以在不可预测的情况下做到可预测,就会导致人们在早期制定计划,然后在计划落空时无法妥善处理这种情况。你会看到计划和现实慢慢地渐行渐远。在很长一段时间里,你可以假装计划仍然有效。但在某个时候,这种偏差变得太大,计划就会落空。通常情况下,这种失败是痛苦的。
因此,如果你处于不可预测的情况下,你就不能使用预测性方法论。这是一个沉重的打击。这意味着许多用于控制项目的模型,许多用于整个客户关系的模型,都不再适用了。可预测性的好处是如此之大,以至于很难让人们放弃它。就像许多问题一样,最困难的部分只是意识到问题的存在。
然而,放弃可预测性并不意味着你必须回到无法控制的混乱状态。相反,你需要一个能够让你控制不可预测性的流程。这就是适应性的意义所在。
控制不可预测的过程 - 迭代
那么,我们如何在不可预测的世界中控制自己呢?最重要也是最困难的部分是准确地了解我们身处何处。我们需要一个诚实的反馈机制,它可以准确地告诉我们目前的情况,并且要经常反馈。
这种反馈的关键是迭代开发。这并不是一个新想法。迭代开发已经存在了一段时间,它有很多名字:增量式、演进式、阶段式、螺旋式……很多名字。迭代开发的关键是频繁地生成最终系统的可工作版本,这些版本具有所需功能的一个子集。这些可工作系统的功能可能不足,但在其他方面应该忠实于最终系统的需求。它们应该完全集成,并且像最终交付一样经过仔细测试。
这样做的意义在于,没有什么比经过测试的集成系统更能给任何项目带来强有力的现实感了。文档可以隐藏各种缺陷。未经测试的代码可以隐藏大量的缺陷。但当人们真正坐在系统前使用它时,缺陷就会变得非常明显:无论是错误还是误解的需求。
迭代开发在可预测的流程中也是有意义的。但在自适应流程中,它是必不可少的,因为自适应流程需要能够处理需求功能的变化。这导致了一种计划风格,即长期计划非常不稳定,唯一稳定的计划是为单次迭代制定的短期计划。迭代开发为你提供了一个坚实的基础,你可以在每次迭代的基础上制定后续计划。
这里的一个关键问题是,一次迭代应该持续多长时间。不同的人给出不同的答案。极限编程建议迭代周期为一到两周。Scrum 建议迭代周期为一个月。Crystal 可能会更长。然而,趋势是使每次迭代尽可能短。这提供了更频繁的反馈,因此你可以更频繁地了解自己的位置。
适应性强的客户
这种自适应流程需要与客户建立一种不同于通常考虑的关系,尤其是在由独立公司进行开发的情况下。当你聘请一家独立公司进行软件开发时,大多数客户会更喜欢固定价格合同。告诉开发人员他们想要什么,询问报价,接受报价,然后由开发机构负责构建软件。
固定价格合同需要稳定的需求,因此需要可预测的流程。自适应流程和不稳定的需求意味着你无法使用通常的固定价格概念。试图将固定价格模型应用于自适应流程最终会导致非常痛苦的爆炸。这种爆炸的可怕之处在于,客户受到的伤害与软件开发公司一样大。毕竟,如果客户的业务不需要某些软件,他们就不会想要它。如果他们没有得到它,他们的业务就会受到影响。因此,即使他们一分钱也不付给开发公司,他们仍然会遭受损失。事实上,他们损失的比他们为软件支付的费用还要多(如果软件的商业价值更低,他们为什么要为软件付费呢?)
因此,在无法使用预测性流程的情况下签订传统的固定价格合同,对双方来说都是危险的。这意味着客户必须以不同的方式工作。
这并不意味着你不能预先确定软件的预算。但这确实意味着你不能确定时间、价格和范围。通常的敏捷方法是确定时间和价格,并允许范围以受控的方式变化。
在自适应流程中,客户对软件开发流程有更细粒度的控制。在每次迭代中,他们都可以检查进度并改变软件开发的方向。这导致与软件开发人员建立更密切的关系,成为真正的业务合作伙伴。这种参与程度并不适合所有客户组织,也不适合所有软件开发人员;但它是使自适应流程正常运作的关键。
所有这些都为客户带来了一些优势。首先,他们可以获得响应更快的软件开发。一个可用的(尽管是最小的)系统可以尽早投入生产。然后,客户可以根据业务变化以及从系统在现实中的使用情况中学习到的知识来改变其功能。
与之同样重要的是,可以更清楚地了解项目的真实状态。预测性流程的问题在于,项目质量是通过与计划的一致性来衡量的。这使得人们很难在现实与计划出现偏差时发出信号。常见的结果是在项目后期进度出现大幅下滑。在敏捷项目中,每次迭代都会对计划进行不断的修改。如果潜藏着坏消息,它往往会更早地出现,那时还有时间采取措施。事实上,这种风险控制是迭代开发的一个关键优势。
敏捷方法通过保持较短的迭代周期,以及以不同的方式看待这些变化,将这一点进一步发扬光大。玛丽·波彭迪克(Mary Poppendieck)用她的一句话“需求的后期变化是一种竞争优势”最恰当地概括了这种观点上的差异。我认为大多数人都注意到,业务人员一开始就很难真正理解他们需要软件做什么。我们经常看到,人们在过程中会了解哪些元素是有价值的,哪些元素是没有价值的。通常情况下,在客户有机会试用软件之前,最有价值的功能一点也不明显。敏捷方法试图利用这一点,鼓励业务人员在系统构建过程中了解他们的需求,并以一种可以快速整合变化的方式构建系统。
所有这些都对构成一个成功的项目具有重要的意义。预测性项目通常是根据其符合计划的程度来衡量的。按时、按成本完成的项目被认为是成功的。这种衡量标准在敏捷环境中是毫无意义的。对于敏捷主义者来说,问题在于商业价值——客户是否获得了比投入成本更有价值的软件。一个好的预测性项目会按计划进行,一个好的敏捷项目会构建出与最初计划预见的不同且更好的东西。
以人为本
执行自适应流程并不容易。特别是,它需要一个非常有效的开发团队。团队需要在个人素质和团队融合方式上都非常出色。还有一个有趣的协同效应:不仅适应性需要强大的团队,大多数优秀的开发人员也更喜欢自适应流程。
即插即用的编程单元
传统方法论的目标之一是开发一个流程,在这个流程中,参与的人员是可替换的部件。有了这样的流程,你就可以把人当作各种类型的可用资源来对待。你有一个分析师、一些编码员、一些测试员和一个经理。个人并不重要,重要的是角色。这样一来,如果你计划一个项目,你得到哪个分析师和哪个测试员并不重要,重要的是你知道你有多少人,这样你就知道资源数量如何影响你的计划。
但这引发了一个关键问题:参与软件开发的人员是否可替代?敏捷方法的关键特征之一就是拒绝这种假设。
也许最明确反对将人视为资源的人是 Alistair Cockburn。在他的论文《将人描述为软件开发中的非线性、一阶组件》中,他指出可预测的流程需要以可预测的方式运行的组件。然而,人并不是可预测的组件。此外,他对软件项目的研宄使他得出结论,人是软件开发中最重要的因素。
(在他的文章)标题中,我将人称为“组件”。这就是流程/方法设计文献中对待人的方式。这种方法的错误之处在于,“人”是高度可变和非线性的,具有独特的成功和失败模式。这些因素是一阶的,不可忽略的因素。流程和方法设计者未能考虑到这些因素,导致我们经常看到的那种计划外的项目轨迹。
人们不禁要问,软件开发的本质是否对我们不利。当我们为计算机编程时,我们控制的是一个本质上可预测的设备。由于我们擅长于此,所以我们非常适合在面对人类时搞砸。
尽管 Cockburn 以最明确的方式表达了他以人为中心的软件开发观点,但以人为本的概念是许多软件思想家的共同主题。问题往往在于,方法论一直反对将人作为项目成功的首要因素。
这会产生强烈的正反馈效应。如果你期望你所有的开发人员都是即插即用的编程单元,你就不会试图将他们视为个体。这会降低士气(和生产力)。优秀的人会寻找更好的去处,而你最终会得到你想要的东西:即插即用的编程单元。
决定以人为本是一个重大的决定,需要很大的决心才能贯彻下去。将人视为资源的观念在商业思维中根深蒂固,其根源可以追溯到弗雷德里克·泰勒科学管理方法的影响。在工厂运营中,这种泰勒主义方法可能是有意义的。但对于高度创造性和专业性的工作,我认为软件开发就是如此,这不成立。(事实上,现代制造业也在摆脱泰勒主义模式。)
程序员是负责任的专业人士
泰勒主义概念的一个关键部分是,从事这项工作的人并不是最能找到最佳工作方式的人。在工厂里,这可能是真的,原因有很多。部分原因是许多工厂工人不是最聪明或最有创造力的人,部分原因是管理层和工人之间存在紧张关系,因为当工人赚的钱减少时,管理层赚的钱就更多。
最近的历史越来越表明,这对软件开发来说是多么不真实。越来越多的聪明能干的人被吸引到软件开发领域,他们被软件开发的光鲜亮丽和潜在的丰厚回报所吸引。(这两点都曾诱惑我放弃电子工程。)尽管 21 世纪初出现了经济衰退,但软件开发领域仍然存在着大量的 талант 和创造力。
(这很可能是一种代际效应。一些轶事证据让我怀疑,在过去 15 年左右的时间里,是否有更多更聪明的人冒险进入了软件工程领域。如果是这样的话,这就是为什么计算机行业会出现这种年轻人崇拜的原因,就像大多数崇拜一样,这其中需要有一点道理。)
当你想要雇佣和留住优秀人才时,你必须认识到他们是称职的专业人士。因此,他们是决定如何开展技术工作的最佳人选。泰勒主义关于由一个独立的计划部门来决定如何做事的概念,只有在计划者比实际做事的人更了解如何做好工作的情况下才有效。如果你有聪明、有干劲的人在做这项工作,那么这个概念就不成立。
管理以人为本的过程
以人为本在敏捷流程中以多种不同的方式体现出来。它会导致不同的效果,并非所有效果都是一致的。
其中一个关键要素是接受流程,而不是强加流程。软件流程通常是由管理人员强加的。因此,它们经常遭到抵制,特别是当管理人员已经离开积极开发岗位很长时间的时候。接受一个流程需要承诺,因此需要团队所有成员的积极参与。
这最终导致了一个有趣的结果,即只有开发人员自己才能选择遵循自适应流程。对于 XP 来说尤其如此,因为它需要大量的纪律来执行。Crystal 将自己视为一种纪律性较低的方法,适用于更广泛的受众。
另一点是,开发人员必须能够做出所有技术决策。XP 抓住了这一点的本质,在其计划过程中,它声明只有开发人员才能对完成某项工作所需的时间进行估算。
对于许多管理职位的人来说,这种技术领导力是一个很大的转变。这种方法需要分担责任,开发人员和管理人员在项目的领导中处于平等的地位。请注意,我说的是平等。管理层仍然发挥着作用,但要认识到开发人员的专业知识。
造成这种情况的一个重要原因是我们行业技术的快速变化。几年后,技术知识就会过时。这种技术技能的半衰期在任何其他行业都是没有的。即使是技术人员也必须认识到,进入管理层意味着他们的技术技能将迅速退化。前开发人员需要认识到,他们的技术技能将迅速消失,他们需要信任和依赖当前的开发人员。
度量的难度
如果你有一个流程,其中说明如何工作的人与实际做事的人不同,那么领导者就需要一些方法来衡量做事者的效率。在科学管理中,人们大力推动开发客观的衡量人员产出的方法。
这对软件来说尤其重要,因为很难对软件进行度量。尽管我们尽了最大努力,但我们仍然无法度量软件最简单的东西,比如生产力。如果没有对这些东西进行良好的度量,任何形式的外部控制都注定要失败。
在没有良好度量的情况下引入度量管理会导致其自身的问题。罗伯特·奥斯汀对此进行了精彩的论述。他指出,在衡量绩效时,你必须将所有重要因素都纳入衡量范围。任何遗漏的东西都会不可避免地导致做事者为了产生最佳的衡量结果而改变他们的做事方式,即使这样做明显降低了他们所做事情的真正效率。这种度量失调是基于度量的管理的致命弱点。
奥斯汀的结论是,你必须在基于度量的管理和授权管理(由做事者决定如何做事)之间做出选择。基于度量的管理最适合于重复性的简单工作,这类工作知识要求低,产出易于度量,而这正是软件开发的反面。
所有这一切的关键在于,传统方法一直是在这样的假设下运作的:基于度量的管理是最有效的管理方式。敏捷社区认识到,软件开发的特点决定了基于度量的管理会导致非常严重的度量失调。实际上,使用授权式的管理方式效率更高,而这种方式正是敏捷主义者观点的核心。
企业领导的作用
但技术人员不能自己完成整个过程。他们需要业务需求方面的指导。这导致了自适应流程的另一个重要方面:他们需要与业务专家保持非常密切的联系。
这超出了大多数项目对业务角色的参与。敏捷团队不可能在偶尔沟通的情况下存在。他们需要持续获得业务专业知识。此外,这种访问不是在管理层面上处理的,而是每个开发人员都应该具备的。由于开发人员在自己的学科领域是能够胜任的专业人员,因此他们需要能够与其他学科领域的专业人员平等地工作。
当然,这在很大程度上是由于自适应开发的性质。由于自适应开发的整个前提是事物变化迅速,因此你需要保持持续的联系,以便让每个人都知道变化。
对于开发人员来说,没有什么比看到自己的辛勤工作付诸东流更令人沮丧的了。因此,重要的是要确保有高质量的业务专家,他们既能让开发人员接触到,又能让开发人员信任他们的质量。
自适应过程
到目前为止,我已经在项目频繁调整其软件以满足客户不断变化的需求的背景下谈论了适应性。然而,适应性还有另一个角度:流程随时间的变化。一个开始使用自适应流程的项目,一年后不会有相同的流程。随着时间的推移,团队会找到适合他们的方法,并修改流程以适应。
自我适应的第一步是定期审查流程。通常情况下,你每次迭代都会这样做。在每次迭代结束时,开一个简短的会议,问问自己以下问题(摘自Norm Kerth)
- 我们做得好的地方是什么?
- 我们学到了什么?
- 我们怎样才能做得更好?
- 什么让我们感到困惑?
这些问题将引导你产生一些想法,以便在下一次迭代中改变流程。通过这种方式,一个一开始就有问题的流程可以在项目进行过程中得到改进,更好地适应使用它的团队。
如果自我适应发生在一个项目中,那么在整个组织中就更加明显了。自我适应的结果是,你永远不应该期望找到单一的企业方法论。相反,每个团队不仅应该选择自己的流程,还应该在项目进行过程中积极调整他们的流程。虽然已发布的流程和其他项目的经验可以作为灵感和基线,但开发人员的专业责任是使流程适应手头的任务。
敏捷开发的风格
“敏捷”一词指的是一种软件开发哲学。在这个广泛的保护伞下,有许多更具体的方法,如极限编程、Scrum、精益开发等。每种更具体的方法都有自己的思想、社区和领导者。每个社区都是一个独立的群体,但要被正确地称为敏捷,它应该遵循相同的广泛原则。每个社区也借鉴彼此的思想和技术。许多实践者在不同的社区之间流动,传播不同的思想——总而言之,这是一个复杂但充满活力的生态系统。
到目前为止,我已经就我对敏捷的定义的总体情况发表了我的看法。现在,我想介绍一些不同的敏捷社区。我在这里只能做一个快速的概述,但我确实提供了一些参考资料,以便你在需要的时候可以进一步挖掘。
由于我将开始提供更多参考资料,因此这是一个很好的时机,可以指出一些有关敏捷方法的一般信息来源。网络中心是敏捷联盟,这是一个非营利组织,旨在鼓励和研究敏捷软件开发。对于书籍,我建议阅读Alistair Cockburn和Jim Highsmith的概述。Craig Larman 关于敏捷开发的书籍包含了迭代开发的非常有用的历史。有关我对敏捷方法的更多看法,请参阅我的敏捷指南。
以下列表并不完整,它反映了过去十年左右的时间里,我个人对敏捷开发的理解以及它对我产生的影响。
敏捷宣言
“敏捷”一词在 2001 年初被用于这项活动,当时一群一直积极参与这项工作的人聚在一起交流想法,并提出了《敏捷软件开发宣言》。
在这次研讨会之前,许多不同的团体一直在发展关于软件开发的类似想法。大多数(但并非全部)工作都来自面向对象软件社区,该社区长期以来一直倡导迭代开发方法。这篇文章最初写于 2000 年,旨在将这些不同的思路汇集在一起。当时,这些方法还没有一个通用的名称,但“轻量级”的绰号已经应运而生。许多参与者认为这不是一个好词,因为它没有准确地表达这些方法的本质。
2000 年,在 Kent Beck 于俄勒冈州举办的一次研讨会上,人们就这些方法中更广泛的问题进行了一些讨论。尽管这次研讨会主要关注极限编程(当时最受关注的社区),但也有一些非 XP 人员参加。其中一个讨论是,XP 成为一个广泛的还是具体的运动会更好。Kent 更喜欢一个更专注、更有凝聚力的社区。
如果我没记错的话,这次研讨会主要是由 Jim Highsmith 和 Bob Martin 组织的。他们联系了那些他们认为在具有类似想法的社区中很活跃的人,并召集了其中的 17 个人参加了 Snowbird 研讨会。最初的想法只是聚在一起,更好地了解彼此的方法。Robert Martin 热衷于得到一些声明,一份可以用来团结业界支持这些技术的宣言。我们还决定要选择一个名称作为各种方法的总称。
在研讨会期间,我们决定使用“敏捷”作为总称,并提出了宣言中的价值观部分。原则部分是在研讨会上开始的,但大部分是在之后的维基上发展起来的。
这项工作显然触动了人们的神经,我认为我们都对宣言所受到的关注和赞赏程度感到非常惊讶。尽管宣言很难说是对敏捷的严格定义,但它确实提供了一个焦点声明,有助于集中思想。在我们完成宣言后不久,Jim Highsmith 和我为《SD Magazine》撰写了一篇文章,对宣言进行了一些评论。
同年晚些时候,撰写宣言的 17 人中的大多数人与其他许多人一起,在 2001 年的 OOPSLA 大会上再次聚首。有人建议宣言的作者应该开始一些持续的敏捷运动,但作者们一致认为,他们只是碰巧参加了那次研讨会并产生了那份宣言的人。这个团体不可能声称领导整个敏捷社区。我们帮助这艘船起航了,应该让任何想乘坐它的人去航行。因此,这就是 17 位宣言作者作为一个有组织的团体的终结。
接下来的一步是在这些作者中的许多人的积极参与下,成立了敏捷联盟。该组织是一个非营利性组织,旨在推广和研究敏捷方法。除其他外,它还赞助在美国举办的年度会议。
XP(极限编程)
在 20 世纪 90 年代后期敏捷方法的早期流行期间,极限编程是最受关注的一种方法。在很多方面,它仍然如此。
XP 的根源在于 Smalltalk 社区,特别是 Kent Beck 和 Ward Cunningham 在 20 世纪 80 年代后期的密切合作。在 90 年代早期,他们两人在众多项目中完善了自己的实践,扩展了他们对一种既适应性强又以人为本的软件开发方法的理解。
Kent 在咨询工作中继续发展他的想法,特别是克莱斯勒 C3 项目,该项目后来被称为极限编程的创建项目。他在 1997 年左右开始使用“极限编程”一词。(C3 也标志着我最初接触极限编程以及与 Kent 友谊的开始。)
在 20 世纪 90 年代后期,极限编程的消息传播开来,最初是通过新闻组和 Ward Cunningham 的维基百科上的描述,Kent 和 Ron Jeffries(C3 的同事)在上面花了很多时间解释和辩论各种想法。最后,在 90 年代末和 00 年代初出版了许多书籍,详细解释了该方法的各个方面。这些书大多以 Kent Beck 的白皮书为基础。Kent 在 2004 年出版了白皮书的第二版,这对该方法进行了重要的重新阐述。
XP 从五个价值观(沟通、反馈、简单、勇气和尊重)开始。然后,它将这些价值观细化为 14 条原则,再细化为 24 条实践。其理念是,实践是团队每天可以做的事情,而价值观是支撑这种方法的基本知识和理解。没有实践的价值观很难应用,而且可以应用的方式太多,以至于很难知道从哪里开始。没有价值观的实践只是没有目的的死记硬背的活动。价值观和实践都是必要的,但两者之间存在很大差距——原则有助于弥合这一差距。XP 的许多实践都是经过实践检验的旧技术,但往往被许多人遗忘,包括大多数计划性流程。XP 不仅复活了这些技术,还将它们编织成一个协同的整体,其中每一种技术都得到其他技术的加强,并通过价值观赋予其目的。
最让我印象深刻,也是最初吸引我的一点是,它非常强调测试。虽然所有流程都提到了测试,但大多数流程对测试的重视程度都很低。然而,XP 将测试作为开发的基础,要求每个程序员在编写生产代码时都要编写测试。这些测试被集成到一个持续集成和构建过程中,为未来的开发提供了一个高度稳定的平台。XP 在这方面的做法,通常被称为测试驱动开发(TDD),即使在没有采用太多 XP 其他内容的地方也产生了影响。
关于极限编程的出版物很多。然而,有一个方面容易混淆,那就是白皮书第一版和第二版之间的转变。我在上面说过,第二版是对极限编程的“重新阐述”,因为方法还是一样,但描述方式不同。第一版(有四个价值观、十二种实践和一些重要但大多被忽视的原则)对软件行业产生了巨大影响,大多数关于极限编程的描述都是根据第一版的描述写成的。在阅读有关 XP 的资料时,请记住这一点,尤其是在 2005 年之前编写的资料。事实上,大多数常见的 XP 网络描述都是基于第一版的。
了解更多信息的自然起点是白皮书的第二版。这本书在短短 160 页的篇幅中解释了 XP 的背景和实践。Kent Beck 在世纪之交编辑了一套关于极限编程的多色系列丛书,如果非要我推荐一本的话,我会选择紫色那本,请记住,像大多数资料一样,它是基于第一版的。
网上有很多关于 XP 的资料,但大多数都是基于第一版的。我所知的少数几个考虑到第二版的描述之一是 Michele Marchesi(他在撒丁岛举办了最初的 XP 会议)撰写的一篇关于新 XP(PDF)的论文。关于 XP 的讨论,有一个雅虎邮件列表。
我在早期参与以及与 XP 社区的友谊意味着我对 XP 有着独特的熟悉、喜爱和偏爱。我认为它的影响力在于将敏捷开发的原则与一套可靠的实际执行技术结合起来。早期关于敏捷的许多著作都忽略了后者,这引发了人们对敏捷思想是否真的可行的质疑。XP 提供了实现敏捷希望的工具。
Scrum
Scrum 也发展于 80 年代和 90 年代,主要是在面向对象开发圈子中,作为一种高度迭代的开发方法。它最著名的开发者是 Ken Schwaber、Jeff Sutherland 和 Mike Beedle。
Scrum 专注于软件开发的管理方面,将开发划分为 30 天的迭代(称为“冲刺”),并通过每日的 Scrum 会议进行更密切的监控。它不太强调工程实践,许多人将其项目管理方法与极限编程的工程实践相结合。(XP 的管理实践并没有太大区别。)
Ken Schwaber 是 Scrum 最积极的支持者之一,他的网站是开始寻找更多信息的理想场所,他的书籍可能是最好的入门参考资料。
水晶方法
Alistair Cockburn 长期以来一直是敏捷社区的主要声音之一。他开发了 Crystal 系列软件开发方法,作为一组针对不同规模团队量身定制的方法。Crystal 被视为一个系列,因为 Alistair 认为,随着团队规模的变化和错误的严重程度的变化,需要不同的方法。
尽管存在差异,但所有 Crystal 方法都有共同的特点。所有 Crystal 方法都有三个优先级:安全(项目成果)、效率、可居住性(开发人员可以接受 Crystal)。它们还具有一些共同的属性,其中最重要的三个是:频繁交付、反思改进和密切沟通。
可居住性优先级是 Crystal 思维方式的重要组成部分。Alistair 的追求(在我看来)是在假设人类不可避免地缺乏纪律性的情况下,寻找能够取得成功的最少流程。因此,Alistair 认为 Crystal 比极限编程需要更少的纪律性,以牺牲效率为代价来换取更高的可居住性和更低的失败几率。
尽管有 Crystal 的概述,但并没有对其所有表现形式的全面描述。描述最详细的是Crystal Clear,它有一个现代的书籍描述。还有一个维基百科,用于进一步了解和讨论 Crystal。
上下文驱动测试
从一开始,推动敏捷社区发展的就是软件开发人员。然而,还有许多其他人参与了软件开发,并受到这一新运动的影响。其中一个明显的群体就是测试人员,他们所处的世界往往被瀑布式思维所包围。常见的指导方针指出,测试的作用是确保软件符合预先制定的规范,因此,测试人员在敏捷世界中的作用还远不明确。
事实证明,测试社区中的一些人多年来一直在质疑许多主流测试思维。这导致了一个被称为上下文驱动测试的群体的出现。对此最好的描述是《软件测试经验教训》一书。这个社区在网络上也非常活跃,可以看看由Brian Marick(敏捷宣言的作者之一)、Brett Pettichord、James Bach和Cem Kaner主持的网站。
精益开发
我记得几年前,我在软件开发大会上做了一个关于敏捷方法的演讲,并与一位热切的女士谈论了敏捷思想与制造业精益运动之间的相似之处。玛丽·波彭代克(和她的丈夫汤姆)一直是敏捷社区的积极支持者,特别是关注精益生产和软件开发之间的重叠和启发。
制造业的精益运动是由丰田公司的大野耐一开创的,通常被称为丰田生产系统。精益生产启发了早期许多敏捷主义者——波彭代克夫妇最引人注目的是描述了这些思想是如何相互作用的。总的来说,我非常警惕这种类比推理,事实上,设计和施工之间的工程分离首先让我们陷入了这种混乱。然而,类比可以带来好的想法,我认为精益思想为敏捷运动引入了许多有用的想法和工具。
(理性)统一过程
另一个从面向对象社区中诞生的著名流程是 Rational 统一流程(有时简称为统一流程)。最初的想法是,像 UML 统一建模语言一样,UP 可以统一软件流程。由于 RUP 的出现与敏捷方法大致相同,因此有很多关于两者是否兼容的讨论。
RUP 是一个非常庞大的实践集合,它实际上是一个流程框架,而不是一个流程。它不是为软件开发提供单一流程,而是寻求为团队提供一组通用的实践,供他们在单个项目中选择。因此,团队使用 RUP 的第一步应该是定义他们自己的流程,或者像 RUP 所说的那样,定义一个开发案例。
RUP 的关键共同点是它是用例驱动的(开发由用户可见的功能驱动)、迭代的和以架构为中心的(优先构建一个在整个项目中都能持续存在的架构)。
我对 RUP 的经验是,它的问题在于它的无限可变性。我见过对 RUP 使用的描述,从带有“分析迭代”的僵化瀑布模型到完美的敏捷模型。令我震惊的是,人们将 RUP 作为单一流程进行营销的愿望导致了一个结果,即人们可以做任何事情并将其称为 RUP——导致 RUP 成为一个毫无意义的短语。
尽管如此,RUP 社区中还是有一些非常强大的人,他们的想法与敏捷思维非常一致。我一直对与 Philippe Kruchten 的所有会面印象深刻,他的书籍是了解 RUP 的最佳起点。Craig Larman 在他广受欢迎的关于面向对象设计的入门书籍中也描述了如何以敏捷风格使用 RUP。
你应该选择敏捷吗?
使用敏捷方法并不适合所有人。如果您决定走这条路,则需要牢记许多事情。但是,我当然相信,这些方法具有广泛的适用性,应该被更多的人使用,而不仅仅是目前考虑使用它们的人。
在当今的环境中,最常见的方法是编码和修复。应用比混乱更多的纪律几乎肯定会对您有所帮助,而且敏捷方法的优势在于,它比使用重量级方法的步骤要少得多。在这里,敏捷方法的轻量级是一个优势。当您习惯于没有任何流程时,就更有可能遵循更简单的流程。
对于敏捷方法的新手来说,问题是从哪里开始。与任何新技术或流程一样,您需要对其进行自己的评估。这使您可以了解它如何适应您的环境。因此,我在这里给出的许多建议都与我为其他新方法给出的建议相同,这让我回想起我第一次谈论面向对象技术时的情景。
第一步是找到合适的项目来试用敏捷方法。由于敏捷方法从根本上是以人为本的,因此,从一个想要尝试以敏捷方式工作的团队开始至关重要。一个不情愿的团队不仅更难合作,而且将敏捷方法强加给不情愿的人从根本上与敏捷开发的整个概念背道而驰。
让客户(需要软件的人)也愿意以这种协作的方式工作也是很有价值的。如果客户不合作,那么您将看不到自适应流程的全部优势。话虽如此,我们已经多次发现,我们与不想合作的客户合作,但当他们在最初的几个月里开始了解敏捷方法时,他们改变了主意。
很多人声称敏捷方法不能用于大型项目。我们(Thoughtworks)在拥有约 100 人和多个大陆的敏捷项目中取得了巨大的成功。尽管如此,我还是建议选择一个规模较小的项目作为开始。大型项目本身就更加困难,因此最好从一个规模更易于管理的项目开始学习。
有些人建议选择一个对业务影响较小的项目作为开始,这样即使出现任何问题,损失也会更小。然而,一个不重要的项目通常是一个糟糕的测试,因为没有人关心结果。我更倾向于建议人们选择一个比您觉得舒服的项目稍微重要一点的项目。
也许您可以做的最重要的事情是找到一个在敏捷方法方面更有经验的人来帮助您学习。每当任何人做任何新的事情时,他们都不可避免地会犯错误。找一个已经犯过很多错误的人,这样你就可以避免自己犯同样的错误。同样,对于任何新技术或新技术来说,这都是正确的,一个好的导师 worth her weight in gold。当然,这个建议是自私的,因为 Thoughtworks 和我在这个行业的许多朋友都在做敏捷方法的指导。这并不能改变我坚信找到一个好导师的重要性。
一旦你找到了一个好的导师,就听从他们的建议。很容易对其中的很多内容进行事后诸葛亮,而且我从经验中学到,许多技术在你没有做出合理的尝试之前是无法真正理解的。我听到的最好的例子之一是我们的一位客户,他决定试用极限编程几个月。在那段时间里,他们明确表示,他们会按照导师的指示去做——即使他们认为这是一个坏主意。在试用期结束时,他们会停下来,决定是继续使用其中的任何想法,还是恢复到以前的工作方式。(如果您想知道,他们决定继续使用 XP。)
关于敏捷方法的一个悬而未决的问题是边界条件在哪里。任何新技术的问题之一是,在你跨越边界并失败之前,你并不知道边界条件在哪里。敏捷方法还太年轻,无法看到足够的行动来了解边界在哪里。更复杂的是,很难确定成功和失败在软件开发中的意义,而且变量太多,无法轻易确定问题的根源。
那么,你不应该在哪里使用敏捷方法呢?我认为这主要取决于人。如果相关人员对敏捷工作所需的这种密切协作不感兴趣,那么让他们使用它将是一场艰苦的斗争。特别是,我认为这意味着你永远不应该试图将敏捷工作强加给一个不想尝试的团队。
在过去的十年中,敏捷方法积累了大量的经验。在 Thoughtworks,如果我们的客户愿意,我们总是使用敏捷方法,大多数时候他们都愿意。我(和我们)仍然是这种工作方式的忠实粉丝。
重大修订
2005 年 12 月 13 日:全面修订了这篇论文。将方法列表更改为敏捷风格的调查。
2003 年 4 月:修订了几个部分。添加了关于测量难度和上下文驱动测试的部分。
2002 年 6 月:更新了参考文献
2001 年 11 月:更新了一些最近的参考文献
2001 年 3 月:更新以反映敏捷联盟的出现
2000 年 11 月:更新了关于 ASD 的部分,并添加了关于 DSDM 和 RUP 的部分
2000 年 12 月:精简版发表在软件开发杂志上,标题为“让你的流程减肥”
2000 年 7 月:在 martinfowler.com 上首次发表