极限编程

软件开发方法旨在提高软件质量和响应不断变化的客户需求

极限编程(英语:Extreme programming,缩写为XP),是一种软件工程方法学,是敏捷软件开发的一种方式。如同其他敏捷方法学,极限编程和传统方法学的本质不同在于它更强调可适应性而不是可预测性。极限编程的支持者认为软件需求的不断变化是很自然的现象,是软件项目开发中不可避免的、也是应该欣然接受的现象;他们相信,和传统的在项目起始阶段定义好所有需求再费尽心思的控制变化的方法相比,有能力在项目周期的任何阶段去适应变化,将是更加现实更加有效的方法。

极限编程为管理人员和开发人员开出了一剂指导日常实践的良方;这个实践意味着接受并鼓励某些特别的有价值的方法。支持者相信,这些在传统的软件工程中看来是“极端的”实践,将会使开发过程比传统方法更加好的响应用户需求,因此更加敏捷,更好的构建出高质量软件。

历史

极限编程的创始者是肯特·贝克沃德·坎宁安罗恩·杰弗里斯英语Ron Jeffries,他们在为克莱斯勒综合报酬系统英语Chrysler Comprehensive Compensation System的薪水册项目工作时提出了极限编程方法。肯特·贝克在1996年3月成为克莱斯勒系统的项目负责人,开始对项目的开发方法学进行改善。他写了一本关于这个改善后的方法学的书,并且于1999年10月将之发行,这就是《极限编程解析》(2005第二版出版)。克莱斯勒在2000年2月取消了实质上并未成功的克莱斯勒系统,但是这个方法学却一直流行在软件工程领域中。直到2006年,很多软件开发项目都一直以极限编程做为他们的指导方法学。

该书阐述了如下的极限编程的哲学思想:

  • 一种社会性的变化机制
  • 一种开发模式
  • 一种改进的方法
  • 一种协调生产率和人性的尝试
  • 一种软件开发方法

把极限编程一般化并用于其它类型的专案称为极限专案管理

极限编程的推广之一为把不同的敏捷软件实践和传统实践节奏地结合起来,弹性地合用于不同企业开发环境。这就是软件开发节奏(Software Development Rhythms)的中心思想

目标

极限编程的主要目标在于降低因需求变更而带来的成本。在传统系统开发方法中,系统需求是在项目开发的开始阶段就确定下来,并在之后的开发过程中保持不变的。这意味着项目开发进入到之后的阶段时出现的需求变更(而这样的需求变更在一些发展极快的领域中是不可避免的)将导致开发成本急速增加。

极限编程透过引入基本价值、原则、方法等概念来达到降低变更成本的目的。一个应用了极限编程方法的系统开发项目在应对需求变更时将显得更为灵活。

核心实践

极限编程实践作业的核心可以被区分为以下四个范围(12个实践作业):[1]

细微反馈

持续程序

共识

  • 编码标准
  • 代码集体共有
  • 简单设计
  • 系统隐喻

程序员的利益

  • 可持之以恒的速度

在第二版的《极限编程解析》中,在主要实践之外,还列出了一系列延伸的实践。

核心实践源自被广泛接受的最佳实践,并且被推向极致:

  • 开发人员和客户之间的交互是有益的。因此,一个极限编程的小组从理论上要求需要一个软件用户在身边,这个用户制定软件的工作需求和优先等级,并且尽可能在各种问题出现的时候马上就能回答(实际工作中,这个角色是由客户代理商完成的).
  • 如果学习是好的,那么就把它做到底:这样减少了开发和回馈周期的长度,测试也能更早完成。
  • 简单的代码更可能工作。所以极限编程的程式设计师在一个软件专案中唯写出能够满足目前实际需求的代码,这样或多或少降低了代码的复杂性和重复性。
  • 如果简单的代码是好的,那么把变得复杂的代码改写成简单的。
  • 代码评审是好的。因此,极限编程的程式设计师以两人搭档的方式工作。他们共享一个屏幕和键盘,增加了队员之间的交流,也让代码在一被写出的时候就被人评审了。
  • 测试代码是好的。因此,在极限编程中,测试用例在实际代码之前就被写出来了。代码只有在通过测试的时候才被认为完成了。(当然,需要进一步分解来降低复杂性)。整个软件系统用一种周期化的,实时的,被预先编好的自动化测试方式来保证它的确有作用。参看测试驱动的开发。
  • 一般来说,极限编程被认为对于少于12人的小团队很有用。一些人认为极限编程可以用于大的团队,但是其它人认为Rational统一过程更适合大的团队。然而,极限编程很难在一些超过100人的开发小组中获得成功。并不是极限编程不能够推广到更大的团队,而是很少有更大的团队来试著用它。极限编程的人员也拒绝去随便推测这个问题。

概念

活动

极限编程描述了在软件开发过程中四种基本的行为,包括

  1. 编码
  2. 测试
  3. 倾听
  4. 设计

极限编程的提倡者争辩说在系统开发过程的产物中真正重要的只有编码,并认为没有经过测试的代码什么都不是。如果你没有测试,客户可能感觉不到,很多软件在发布的时候没有经过完整的测试,它们还都在工作(或多或少的工作)。极限编程认为,在软件开发程序中,如果一个函数没有经过测试就不能认为它可以工作。

价值

极限编程技术以沟通、简单、反馈、勇气和尊重为价值标准。[2]

沟通

构建一个软件系统的基本任务之一就是与系统的开发者交流以明确系统的具体需求。在一些正式的软件开发方法中,这一任务是通过文档来完成的。

极限编程技术可以被看成是在开发小组的成员之间迅速构建与传播制度上的认识的一种方法。它的目标是向所有开发人员提供一个对于系统的共享的视角,而这一视角又是与系统的最终用户的视角相吻合的。为了达到这一目标,极限编程支持设计、抽象、还有用户-程序员间交流的简单化,鼓励经常性的口头交流与回馈。

简单

极限编程鼓励从最简单的解决方式入手再通过不断重构达到更好的结果。这种方法与传统系统开发方式的不同之处在于,它只关注于对当前的需求来进行设计、编码,而不去理会明天、下周或者下个月会出现的需求。极限编程的拥护者承认这样的考虑是有缺陷的,即有时候在修改现有的系统以满足未来的需求时不得不付出更多的努力。然而他们主张“不对将来可能的需求上投入精力”所得到的好处可以弥补这一点,因为将来的需求在他们还没提出之前是很可能发生变化的。为了将来不确定的需求进行设计以及编码意味着在一些可能并不需要的方面浪费资源。而与之前提到的“交流”这一价值相关联来看,设计与代码上的简化可以提高交流的质量。一个由简单的编码实现的简单的设计可以更加容易得被小组中的每个程序员所理解。

反馈

在极限编程中,“反馈”是和系统开发的很多不同方面相关联的:

  • 来自系统的反馈:通过编写单元测试,程序员能够很直观的得到经过修改后系统的状态。
  • 来自客户的反馈:功能性测试是由客户还有测试人员来编写的。他们能由此得知当前系统的状态。这样的评审一般计划2、3个礼拜进行一次,这样客户可以非常容易的了解、掌控开发的进度。
  • 来自小组的反馈:当客户带着新需求来参加项目计划会议时,小组可以直接对于实现新需求所需要的时间进行评估然后反馈给客户。

反馈是与“交流”、“简单”这两条价值紧密联络的。为了沟通系统中的缺陷,可以通过编写单元测试,简单的证明某一段代码存在问题。来自系统的直接反馈资讯将提醒程序员注意这一部分。用户可以以定义好的功能需求为依据,对系统进行周期性的测试。用Kent Beck的话来说:“编程中的乐观主义是危险的,而及时反馈则是解决它的方法。”

勇气

极限编程理论中的“系统开发中的勇气”最好用一组实践来诠释。其中之一就是“只为目前的需求设计以及编码,别为不可预期的未来做太多考虑”这条戒律。这是努力避免陷入设计的泥潭、而在其他问题上花费了太多不必要的精力。勇气使得开发人员在需要重构他们的代码时能感到舒适。这意味着重新审查现有系统并完善它会使得以后出现的变化需求更容易被实现。另一个勇气的例子是了解什么时候应该完全丢弃现有的代码。每个程序员都有这样的经历:他们花了一整天的时间纠缠于自己设计和代码中的一个复杂的难题却无所得,而第二天回来以一个全新而清醒的角度来考虑,在半小时内就轻松解决了问题。

尊重

尊重的价值体现在很多方面。在极限编程中,团队成员间的互相尊重体现在每个人保证提交的任何改变不会导致编译无法通过、或者导致现有的测试案例失败、或者以其他方式导致工作延期。团队成员对于他们工作的尊重体现在他们总是坚持追求高质量,坚持通过重构的手段来为手头的工作找到最好的解决设计方案。

原则

组成极限编程基础的原则,正是基于上面描述的那几条价值。在系统开发项目中,这些原则被用来为决策做出指导。与价值相比,原则被描述的更加具体化,以便在实际应用中更为简单的转变为具体的指导意见。

快速反馈

当回馈能做到及时、迅速,将发挥极大的作用。一个事件和对这一事件做出反馈之间的时间,一般被用来掌握新情况以及做出修改。与传统开发方法不同,与客户的发生接触是不断反复出现的。客户能够清楚地洞察开发中系统的状况。他/她能够在整个开发过程中及时给出反馈意见,并且在需要的时候能够掌控系统的开发方向。

单元测试同样对贯彻反馈原则起到作用。在编写代码的过程中,应需求变更而做出修改的系统将出现怎样的反应,正是通过单元测试来给出直接反馈的。比如,某个程序员对系统中的一部分代码进行了修改,而假如这样的修改影响到了系统中的另一部分(超出了这个程序员的可控范围),则这个程序员不会去关注这个缺陷。往往这样的问题会在系统进入生产环节时暴露出来。

假设简单

假设简单认为任何问题都可以"极度简单"地解决。传统的系统开发方法要考虑未来的变化,要考虑代码的可重用性。极限编程拒绝这样做。

包容变化

可以肯定地是,不确定因素总是存在的。“包容变化”这一原则就是强调不要对变化采取反抗的态度,而应该包容它们。比如,在一次阶段性会议中客户提出了一些看来戏剧性的需求变更。作为程序员,必须包容这些变化,并且拟定计划使得下一个阶段的产品能够满足新的需求。

实践

策划游戏

在极限编程中主要的策划程序称为策划游戏,本节将通过程序模型介绍这个程序。

策划程序分为两部分:

  • 发布策划:
  • 反复状态:

提交状态—发布计划

这一阶段涉及成本、利润和计划影响这三个因素,包含四个部分:

  • 按照价值排序:业务方按照商业价值为用户故事排序。
  • 按风险排序:开发方按风险为用户故事排序。
  • 设置周转率:开发方决定以怎样的速度开展项目。
  • 选择范围:挑选在下一个发布中需要被完成的用户故事,基于用户故事决定发布日期。

价值排序

业务方按照商业价值为用户故事排序。它们会被分为三类:

  • 关键:没有这些故事系统无法运作或变得毫无意义。
  • 重要的商业价值:有重要业务价值的非关键用户故事。
  • 最好能有:并没有重要商业价值的用户故事;例如在可用性或用户界面上的改进。

风险排序

程序员按照风险对用户故事进行排序。他/她们将用户故事的风险划分成三类:低、中、高。以下是这种方式的一个示例:

  • 决定风险索引:依照以下因素给每个用户故事一个0到2的索引:
    • 完全度(我们是否已经了解所有的故事细节?)
      • 完全(0)
      • 不完全(1)
      • 未知(2)
    • 发散性(可能会发生变化吗?)
      • 低(0)
      • 中(1)
      • 高(2)
    • 复杂度(是否难以建构?)
      • 简单(0)
      • 标准(1)
      • 复杂(2)

为每个用户故事增加所有这些索引后,给这些用户故事指定一个风险索引:低(0–1),中(2–4),高(5–6)。

激励状态—发布计划

在作业阶段开发人员和业务人员可以“操纵”整个程序。这意味着,他们可以做出改变。个体的用户故事,或是不同用户故事的相对优先等级,都有可能改变;预估时间也可能出现误差。这是做出相应调整的机会。

探索阶段—反复计划

反复计划中的探索阶段是关于建立任务和预估实施时间。

  • 收集用户故事:收集并编辑下一个发布的所有用户故事。
  • 组合/分割任务:如果程序员因为任务太大或太小而不能预估任务完成时间,则需要组合或分割此任务。
  • 预估任务:预测需要实现此任务的时间。

约定阶段—反复计划

在反复计划的约定阶段以不同用户故事作为参考的任务被指派到程序员。

  • 程序员接受任务:每个程序员都挑选一个他/她负责的任务。
  • 程序员预估任务:由于程序员对此任务负责,他/她必须给出一个完成任务的估计时间。
  • 设置负载系数:负载系数表示每个程序员在一个反复中理想的开发时间。比如:一周工作40小时,其中5小时用于开会,则负载系数不会超过35小时。
  • 平衡:当团队中所有程序员都已经被配置了任务,便会在预估时间和负载系数间做出比较。任务配置在程序员中达到平衡。如果有一个程序员的开发任务过重,其它程序员必须接手他/她的一部分任务,反之亦然。

作业阶段—反复计划

各个任务是在反复计划的作业阶段中一步步实现的。

  • 获取一张任务卡片:程序员获取一张由他/她负责的任务的卡片。
  • 找寻一名同伴:这个程序员将和另一位程序员一同完成开发工作。这在实施结队程式设计中会做更深入的探讨。
  • 设计这个任务:如果需要,两位程序员会设计这个任务所达成的功能。
  • 编辑单元测试:在程序员开始编辑实现功能的代码之前,他/她们首先编辑自动测试。这在实施单元测试中会做更深入的探讨。
  • 编辑代码:两位程序员开始编辑代码。
  • 执行测试:执行单元测试来确定代码能正常工作。
  • 执行功能测试:执行功能测试(基于相关用户故事和任务卡片中的需求)。

结对程式设计

结对程式设计的意思是所有的代码都是由两个人坐在一台电脑前一起完成的。一个程序员控制电脑并且主要考虑编码细节。另外一个人主要关注整体结构,不断的对第一个程序员写的代码进行评审。

结对不是固定的:我们甚至建议程序员尽量交叉结对。这样,每个人都可以知道其它人的工作,每个人都对整个系统熟悉,结对程式设计加强了团队内的沟通。(这与代码集体所有制是息息相关的).

集体所有制

集体所有制意味着每个人都对所有的代码负责;这一点,反过来又意味着每个人都可以更改代码的任意部分。结队程式设计对这一实践贡献良多:借由在不同的结队中工作,所有的程序员都能看到完全的代码。集体所有制的一个主要优势是提升了开发程序的速度,因为一旦代码中出现错误,任何程序员都能修正它。

在给予每个开发人员修改代码的权限的情况下,可能存在程序员引入错误的风险,他/她们知道自己在做什么,却无法预见某些依赖关系。完善的单元测试可以解决这个问题:如果未被预见的依赖产生了错误,那么当单元测试执行时,它必定会失败。

现场客户

在极限编程中,“客户”并不是为系统付账的人,而是真正使用该系统的人。极限编程认为客户应该时刻在现场解决问题。例如:在团队开发一个财务管理系统时,开发小组内应包含一位财务管理人员。

单元测试

单元测试是用以测试一小段代码的自动测试(例如:类,方法)。在极限编程中,在代码编辑前就编辑单元测试。这种方式的目的是激励程序员设想他/她的代码在何种条件下会出错。极限编程认为当程序员无法再想出更多能使他/她的代码出错的情况时,这些代码便算完成。

重构

由于极限编程教条提倡编辑程序时只满足目前的需求,并且以尽可能简单的方式实现。有时会碰上一套僵硬的系统,所谓僵硬的系统,表现之一是需要双重(或多重)维护:功能变化需要对多份同样(或类似)的代码进行修改;另一种表现是对代码的一部分进行修改时会影响其它很多部分。XP教条认为当这种情况发生时,意味着系统正告诉你通过改变系统架构以重构代码,使它更简单、更泛用。参见重构

极限编程的特征

极限编程方法的基本特征是:

争论的观点

极限编程也有其被争论的一面:

绝大多数设计活动都匆匆而过,并渐进式的,开始一个“最简单的可能工作的东西”并当其需要时(测试失败)才增加复杂性。单元测试促成为了设计纪律

参考文献

引用

  1. ^ Extreme programming explained
  2. ^ 《极限编程解析》第二版

来源

书籍

延伸阅读

  • Ken Auer and Roy Miller. Extreme Programming Applied: Playing To Win, Addison–Wesley.
  • Ken Auer; Ron Jeffries; Jeff Canna; Glen B. Alleman; Lisa Crispin; Janet Gregory. Are Testers eXtinct? How Can Testers Contribute to XP Teams?. Springer-Verlag. 2002. doi:10.1007/3-540-45672-4_50. 
  • Kent Beck: Extreme Programming Explained: Embrace Change, Addison–Wesley.
  • Kent Beck and Martin Fowler: Planning Extreme Programming, Addison–Wesley.
  • Kent Beck and Cynthia Andres. Extreme Programming Explained: Embrace Change, Second Edition, Addison–Wesley.
  • Alistair Cockburn: Agile Software Development, Addison–Wesley.
  • Martin Fowler: Refactoring: Improving the Design of Existing Code, Addison–Wesley.
  • Harvey Herela (2005). Case Study: The Chrysler Comprehensive Compensation System. Galen Lab, U.C. Irvine.
  • Jim Highsmith. Agile Software Development Ecosystems, Addison–Wesley.
  • Ron Jeffries, Ann Anderson and Chet Hendrickson (2000), Extreme Programming Installed, Addison–Wesley.
  • Craig Larman & V. Basili (2003). "Iterative and Incremental Development: A Brief History", Computer (IEEE Computer Society) 36 (6): 47–56.
  • Matt Stephens and Doug Rosenberg (2003). Extreme Programming Refactored: The Case Against XP, Apress.
  • Waldner, JB. (2008). "Nanocomputers and Swarm Intelligence". In: ISTE, 225–256.

外部链接