极限编程(XP,eXtreme Programming)是一种软件工程方法学,是敏捷软件开发中最富有成效的几种方法学之一。如同其他敏捷方法学,极限编程和传统方法学的本质不同在于它更强调可适应性而不是可预测性。XP的支持者认为软件需求的不断变化是很自然的现象,是软件项目开发中不可避免的、也是应该欣然接受的现象;他们相信,和传统的在项目起始阶段定义好所有需求再费尽心思的控制变化的方法相比,有能力在项目周期的任何阶段去适应变化,将是更加现实更加有效的方法。
XP为管理人员和开发人员开出了一剂指导日常实践的良方;这个实践意味着接受并鼓励某些特别的有价值的方法。支持者相信,这些在传统的软件工程中看来是“极端的”实践,将会使开发过程比传统方法更加好的响应用户需求,因此更加敏捷,更好的构建出高质量软件。
历史
极限编程的创始者是肯特·贝克(Kent Beck)、沃德·坎宁安( Ward Cunningham)和罗恩·杰弗里斯(Ron Jeffries),他们在为克莱斯勒综合报酬系统(Chrysler Comprehensive Compensation System )(C3) 的薪水册项目工作时提出了极限编程方法。Kent Beck在1996年3月成为C3的项目负责人,开始对项目的开发方法学进行改善。他写了一本关于这个改善后的方法学的书,并且于1999年10月将之发行,这就是《极限编程解析》(2005第二版出版)。克莱斯勒在2000年2月取消了实质上并未成功的C3项目,但是这个方法学却一直流行在软件工程领域中。至今2006年,很多软件开发项目都一直以极限编程做为他们的指导方法学。
该书阐述了如下的极致编程的哲学思想 :
一种社会性的变化机制
一种开发模式
一种改进的方法
一种协调生产率和人性的尝试
一种软件开发方法
把极致编程一般化并用于其它型别的专案称为极致专案管理。
未来的方向
极限编程的推广之一为把不同的敏捷软件实践和传统实践节奏地结合起来,弹性地合用于不同企业开发环境。这就是软件开发节奏(Software Development Rhythms)的中心思想
XP的目标
极限编程的主要目标在于降低因需求变更而带来的成本。在传统系统开发方法中(如SDM),系统需求是在专案开发的开始阶段就确定下来,并在之后的开发过程中保持不变的。这意味着专案开发进入到之后的阶段时出现的需求变更—而这样的需求变更在一些发展极快的领域中是不可避免的—将导致开发成本急速增加。这一概念可以用下图来表示:
极限编程透过引入基本价值、原则、方法等概念来达到降低变更成本的目的。一个应用了极限编程方法的系统开发专案在应对需求变更时将显得更为灵活。下图展示了这一降低变更成本的目的:
XP 核心的实践
极致编程实践作业的核心,正如 Extreme programming explained 所描述的,可以被区分为以下四个范围(12个实践作业):
小规模回馈
- 测试驱动开发
- 策划游戏
- 全队(原名:在场客户)
- 结对程式设计
反覆性程序而不是批量的
- 持续整合
- 设计最佳化(原名:软件重构)
- 小型发布
共同认识(共识)
- 简单的设计
- 系统隐喻
- 集体程式码所有
- 程式设计标准/程式设计规约
程式设计师的利益
- 恒定速路
- 可反覆性速率(原名:每周40小时)
在第二版的Extreme programming explained中,在主要实践之外,还列出了一系列延伸的实践。
核心实践源自被广泛接受的最佳实践,并且被推向极至:
开发人员和客户之间的交互是有益的. 因此,一个极致编程的小组从理论上要求需要一个软件使用者在身边,这个使用者制定软件的工作需求和优先等级, 并且尽可能在各种问题出现的时候马上就能回答(实际工作中,这个角色是由客户代理商完成的).
如果学习是好的, 那么就把它做到底: 这样减少了开发和回馈周期的长度,测试也能更早完成.
简单的代码更可能工作。所以极致编程的程序设计师在一个软件专案中唯写出能够满足目前实际需求的代码,这样或多或少降低了代码的复杂性和重复性.
如果简单的代码是好的, 那么把变得复杂的代码改写成简单的.
代码评审是好的。因此,极致编程的程序设计师以两人搭档的方式工作. 他们共享一个屏幕和键盘,增加了队员之间的交流,也让代码在一被写出的时候就被人评审了.
测试代码是好的。因此,在极致编程中,测试用例在实际代码之前就被写出来了. 代码只有在通过测试的时候才被认为完成了. (当然,需要进一步分解来降低复杂性). 整个软件系统用一种周期化的,实时的,被预先变好的自动化测试方式来保证它的确有作用.参看 测试驱动的开发.
一般来说,极致编程被认为对于少于12人的小团队很有用。一些人认为极致编程可以用于大的团队,但是其它人认为统一软件程序更适合大的团队。然而,极致编程在一些超过100人的开发小组中获得成功. 并不是极致编程不能够推广到更大的团队,而是很少有更大的团队来试著用它. 极致编程的人员也拒绝去随便推测这个问题.
XP的价值
最初,极限编程技术只提出了四条价值标准,而在《极限编程解析》的第二版中又加入了第五条。以下就是这五条标准:
沟通
简单
回馈
勇气
尊重(最新添加的价值)
软件重构
构建一个软件系统的基本任务之一就是与系统的开发者交流以明确系统的具体需求。在一些正式的软件开发方法中,这一任务是通过文档来完成的。
极限编程技术可以被看成是在开发小组的成员之间迅速构建与传播制度上的认识的一种方法。它的目标是向所有开发人员提供一个对于系统的共享的视角,而这一视角又是与系统的最终用户的视角相吻合的。为了达到这一目标,极限编程支持设计、抽象、还有用户-程序员间交流的简单化,鼓励经常性的口头交流与反馈。
简单
极限编程鼓励从最简单的解决方式入手再通过不断重构达到更好的结果。这种方法与传统系统开发方式的不同之处在于,它只关注于对当前的需求来进行设计、编码,而不去理会明天、下周或者下个月会出现的需求。极限编程的拥护者承认这样的考虑是有缺陷的,即有时候在修改现有的系统以满足未来的需求时不得不付出更多的努力。然而他们主张“不对将来可能的需求上投入精力”所得到的好处可以弥补这一点,因为将来的需求在他们还没提出之前是很可能发生变化的。为了将来不确定的需求进行设计以及编码意味着在一些可能并不需要的方面浪费资源。而与之前提到的“交流”这一价值相关联来看,设计与代码上的简化可以提高交流的质量。一个由简单的编码实现的简单的设计可以更加容易得被小组中的每个程序员所理解。
反馈
在极限编程中,“反馈”是和系统开发的很多不同方面相关联的:
来自系统的反馈:通过编写单元测试,程序员能够很直观的得到经过修改后系统的状态。
来自客户的反馈:功能性测试是由客户还有测试人员来编写的。他们能由此得知当前系统的状态。这样的评审一般计划2、3个礼拜进行一次,这样客户可以非常容易的了解、掌控开发的进度。
来自小组的反馈:当客户带着新需求来参加项目计划会议时,小组可以直接对于实现新需求所需要的时间进行评估然后反馈给客户。
反馈是与“交流”、“简单”这两条价值紧密联系的。为了沟通系统中的缺陷,可以通过编写单元测试,简单的证明某一段代码存在问题。来自系统的直接反馈信息将提醒程序员注意这一部分。用户可以以定义好的功能需求为依据,对系统进行周期性的测试。用Kent Beck的话来说:“编程中的乐观主义是危险的,而及时反馈则是解决它的方法。”
勇气
极限编程理论中的“系统开发中的勇气”最好用一组实践来诠释。其中之一就是“只为今天的需求设计以及编码,不要考虑明天”这条戒律。这是努力避免陷入设计的泥潭、而在其他问题上花费了太多不必要的精力。勇气使得开发人员在需要重构他们的代码时能感到舒适。这意味着重新审查现有系统并完善它会使得以后出现的变化需求更容易被实现。另一个勇气的例子是了解什么时候应该完全丢弃现有的代码。每个程序员都有这样的经历:他们花了一整天的时间纠缠于自己设计和代码中的一个复杂的难题却无所得,而第二天回来以一个全新而清醒的角度来考虑,在半小时内就轻松解决了问题。
尊重
尊重的价值体现在很多方面。在极限编程中,团队成员间的互相尊重体现在每个人保证提交的任何改变不会导致编译无法通过、或者导致现有的测试case失败、或者以其他方式导致工作延期。团队成员对于他们工作的尊重体现在他们总是坚持追求高质量,坚持通过重构的手段来为手头的工作找到最好的解决设计方案。
原则
组成极限编程基础的原则,正是基于上面描述的那几条价值。在系统开发项目中,这些原则被用来为决策做出指导。与价值相比,原则被描述的更加具体化,以便在实际应用中更为简单的转变为具体的指导意见。
快速反馈
当反馈能做到及时、迅速,将发挥极大的作用。一个事件和对这一事件做出反馈之间的时间,一般被用来掌握新情况以及做出修改。与传统开发方法不同,与客户的发生接触是不断反复出现的。客户能够清楚地洞察开发中系统的状况。他/她能够在整个开发过程中及时给出反馈意见,并且在需要的时候能够掌控系统的开发方向。
单元测试同样对贯彻反馈原则起到作用。在编写代码的过程中,应需求变更而做出修改的系统将出现怎样的反应,正是通过单元测试来给出直接反馈的。比如,某个程序员对系统中的一部分代码进行了修改,而假如这样的修改影响到了系统中的另一部分(超出了这个程序员的可控范围),则这个程序员不会去关注这个缺陷。往往这样的问题会在系统进入生产环节时暴露出来。
假设简单
假设简单认为任何问题都可以"极度简单"的解决。传统的系统开发方法要考虑未来的变化,要考虑程序码的可重用性。极致编程拒绝这样作。
增量变化
极限编程的提倡者总是说:罗马不是一天建成的。一次就想进行一个大的改造是不可能的。极限编程采用增量变化的原则。比如说,可能每三个星期发布一个包含小变化的新版本。这样一小步一小步前进的方式,使得整个开发进度以及正在开发的系统对于用户来说变得更为可控。
包容变化
可以肯定地是,不确定因素总是存在的。“包容变化”这一原则就是强调不要对变化采取反抗的态度,而应该包容它们。比如,在一次阶段性会议中客户提出了一些看来戏剧性的需求变更。作为程序员,必须包容这些变化,并且拟定计划使得下一个阶段的产品能够满足新的需求。
活动
XP 描述了在软件开发过程中四种基本的行为。 XP describes four basic activities that are performed within the software development process.
编码
XP的提倡者争辩说在系统开发过程的产物中真正重要的只有编码
软件测试
没有经过测试的程序码什么都不是。如果你没有测试,客户可能感觉不到,很多软件在发布的时候没有经过完整的测试,它们还都在工作(或多或少的工作)。 在软件开发程序中,极致编程认为,如果一个函数没有经过测试就不能认为它可以工作。
实践
策划游戏
在极致编程中主要的策划程序称为策划游戏。 本节将通过程序模型介绍这个程序。
策划程序分为两部分:
发布策划:
反覆状态:
Image:Planninggame.gif
送出状态 – 发布计划
这一阶段涉及成本、利润和计划影响这三个因素,包含四个部分:
按照价值排序:业务方按照商业价值为使用者故事排序。
按风险排序:开发方按风险为使用者故事排序。
设定周转率:开发方决定以怎样的速度开展专案。
选择范围:挑选在下一个发布中需要被完成的使用者故事,基于使用者故事决定发布日期。
价值排序
业务方按照商业价值为使用者故事排序。它们会被分为三类:
关键:没有这些故事系统无法运作或变得毫无意义。
重要的商业价值:有重要业务价值的非关键使用者故事。
最好能有:并没有重要商业价值的使用者故事;例如在可用性或使用者界面上的改进。
风险排序
程序设计师按照风险对使用者故事进行排序。他/她们将使用者故事的风险划分成三类:低、中、高。以下是这种方式的一个范例:
决定风险索引:依照以下因素给每个使用者故事一个0到2的索引:
完全度(我们是否已经了解所有的故事细节?)
完全(0)
不完全(1)
未知(2)
发散性(可能会发生变化吗?)
低(0)
中(1)
高(2)
复杂度(是否难以建构?)
简单(0)
标准(1)
复杂(2)
为每个使用者故事增加所有这些索引后,给这些使用者故事指定一个风险索引:低(0–1),中(2–4),高(5–6)。
激励状态 – 发布计划
在作业阶段开发人员和业务人员可以“操纵”整个程序。这意味着,他们可以做出改变。个体的使用者故事,或是不同使用者故事的相对优先等级,都有可能改变;预估时间也可能出现误差。这是做出相应调整的机会。
探索阶段- 反覆计划
反覆计划中的探索阶段是关于建立任务和预估实施时间。
收集使用者故事:收集并编辑下一个发布的所有使用者故事。
组合/分割任务:如果程序设计师因为任务太大或太小而不能预估任务完成时间,则需要组合或分割此任务。
预估任务:预测需要实作此任务的时间。
约定阶段 - 反覆计划
在反覆计划的约定阶段以不同使用者故事作为参考的任务被指派到程序设计师。
程序设计师接受任务:每个程序设计师都挑选一个他/她负责的任务。
程序设计师预估任务:由于程序设计师对此任务负责,他/她必须给出一个完成任务的估计时间。
设定负载系数:负载系数表示每个程序设计师在一个反覆中理想的开发时间。比如:一周工作40小时,其中5小时用于开会,则负载系数不会超过35小时。
平衡:当团队中所有程序设计师都已经被配置了任务,便会在预估时间和负载系数间做出比较。任务配置在程序设计师中达到平衡。如果有一个程序设计师的开发任务过重,其它程序设计师必须接手他/她的一部分任务,反之亦然。
作业阶段 - 反覆计划
各个任务是在反覆计划的作业阶段中一步步实作的。
取得一张任务卡片:程序设计师取得一张由他/她负责的任务的卡片。
找寻一名同伴:这个程序设计师将和另一位程序设计师一同完成开发工作。这在实施结队程序设计中会做更深入的探讨。
设计这个任务:如果需要,两位程序设计师会设计这个任务所达成的功能。
编辑单元测试:在程序设计师开始编辑实作功能的程序码之前,他/她们首先编辑自动测试。这在实施单元测试中会做更深入的探讨。
编辑程序码:两位程序设计师开始编辑程序码。
执行测试:执行单元测试来确定程序码能正常工作。
执行功能测试:执行功能测试(基于相关使用者故事和任务卡片中的需求)。
结对程序设计
结对程序设计的意思是所有的程序码都是由两个人坐在一台电脑前一起完成的。一个程序设计师控制电脑并且主要考虑编码细节。另外一个人主要关注整体结构,不断的对第一个程序设计师写的程序码进行评审。
结对不是固定的: 我们甚至建议程序设计师尽量交叉结对。这样,每个人都可以知道其它人的工作,每个人都对整个系统熟悉,结对程序设计加强了团队内的沟通。 (这与程序码集体所有制是息息相关的).
集体所有制
集体所有制意味着每个人都对所有的程序码负责;这一点,反过来又意味着每个人都可以更改程序码的任意部分。结队程序设计对这一实践贡献良多:借由在不同的结队中工作,所有的程序设计师都能看到完全的程序码。集体所有制的一个主要优势是提升了开发程序的速度,因为一旦程序码中出现错误,任何程序设计师都能修正它。
在给予每个开发人员修改程序码的权限的情况下,可能存在程序设计师引入错误的风险,他/她们知道自己在做什么,却无法预见某些依赖关系。完善的单元测试可以解决这个问题:如果未被预见的依赖产生了错误,那么当单元测试执行时,它必定会失败。
现场客户
在极致编程中,“客户”并不是为系统付帐的人,而是真正使用该系统的人。极致编程认为客户应该时刻在现场解决问题。例如:在团队开发一个财务管理系统时,开发小组内应包含一位财务管理人员。
单元测试
单元测试是用以测试一小段程序码的自动测试(例如:类,方法)。在极致编程中,在程序码编辑前就编辑单元测试。这种方式的目的是激励程序设计师设想他/她的程序码在何种条件下会出错。极致编程认为当程序设计师无法再想出更多能使他/她的程序码出错的情况时,这些程序码便算完成。
重构
由于XP教条提倡编辑程序时只满足目前的需求,并且以尽可能简单的方式实作。有时会碰上一套僵硬的系统,所谓僵硬的系统,表现之一是需要双重(或多重)维护:功能变化需要对多份同样(或类似)的程序码进行修改;另一种表现是对程序码的一部分进行修改时会影响其它很多部分。XP教条认为当这种情况发生时,意味着系统正告诉你通过改变系统架构以重构程序码,使它更简单、更泛用。参见重构。
极致编程的特征
极致编程方法的基本特征是:
增量和反覆式的开发 - 一次小的改进跟着一个小的改进。
反覆性,通常是自动重复的单元测试,回归测试。参见JUnit。
结对程序设计
在程序设计团队中的使用者交互(在场的客户)
软件重构
共享的程序码所有权
简单
回馈
用隐喻来组织系统
可以忍受的速度
这些内容属性来源于那些被认为是有效的原则,并把它们发挥到极致:
开发人员和客户之间的交互是有益的. 因此,一个极致编程的小组从理论上要求需要一个软件使用者在身边,这个使用者制定软件的工作需求和优先等级, 并且尽可能在各种问题出现的时候马上就能回答.
如果学习是好的, 那么就把它做到底: 这样减少了开发和回馈周期的长度,测试也能更早完成.
简单的程序码更可能工作。所以极致编程的程序设计师在一个软件专案中唯写出能够满足目前实际需求的程序码,这样或多或少降低了程序码的复杂性和重复性.
如果简单的程序码是好的, 那么把变得复杂的程序码改写成简单的.
程序码评审是好的。因此,极致编程的程序设计师以两人搭档的方式工作. 他们共享一个屏幕和键盘,增加了队员之间的交流,也让程序码在一被写出的时候就被人评审了.
测试程序码是好的。因此,在极致编程中,测试用例在实际程序码之前就被写出来了. 程序码只有在通过测试的时候才被认为完成了. (当然,需要进一步分解来降低复杂性). 整个软件系统用一种周期化的,实时的,被预先变好的自动化测试方式来保证它的确有作用.参看 测试驱动的开发.
一般来说,极致编程被认为对于少于12人的小团队很有用。一些人认为极致编程可以用于大的团队,但是其它人认为统一软件程序更适合大的团队。然而,极致编程在一些超过100人的开发小组中获得成功. 并不是极致编程不能够推广到更大的团队,而是很少有更大的团队来试着用它. 极致编程的人员也拒绝去随便推测这个问题.
争论的观点
极致编程也有其被争论的一面:
没有书面的详细的规格说明书
客户代表被安排在专案中
程序设计师以结对的方式工作
测试驱动的开发
绝大多数设计活动都匆匆而过,并渐进式的,开始一个“最简单的可能工作的东西”并当其需要时(测试失败)才增加复杂性。单元测试促成为了设计纪律。
极致编程中的沟通
建构软件系统的一个基本任务是向系统的开发人员传达系统的需求。在形式的软件开发方法学中,沟通是通过文件完成的。
极致编程方法可以被看作为在开发团队成员间快速建构和散布统一的知识的一种方法。目的在于给所有开发人员一个共享的关于系统的看法,这个看法与使用者持有的看法相一致。为了这个目的,极致编程热衷于简单的设计,隐喻,使用者与程序设计师之间的合作,频繁的口头沟通和回馈。