敏捷软件开发(上篇)

作为三篇系列文章的第一篇,我们将带你了解敏捷软件开发的重要做法——如何使用它们、你可能会碰到什么样的问题,以及你将从它们那里获得什么。

敏捷软件开发不是一个具体的过程,而是一个涵盖性术语(umbrella term),用于概括具有类似基础的方式和方法。这些方法,其中包括极限编程(Extreme Programming)、动态系统开发方法(Dynamic System Development Method)、SCRUM、Crystal和Lean等,都着眼于快速交付高质量的工作软件,并做到客户满意。

尽管构成这个敏捷开发过程的每种方法都具有类似的目标,但是它们实现这个目标的做法(practice)却不尽相同。我们把在自己完成所有过程中经历过的最佳做法集中到了本系列的文章里。

下面的图表基本勾画出了我们提炼出来的这些敏捷开发最佳做法。最中间的圆环代表一对程序员日常工作的做法。紧接着的中间一个圆环表示开发人员小组使用的做法。最外面的一个圆环是项目所涉及的所有人的做法——客户、开发人员、测试人员、业务分析师等等。

这些圆环里的所有做法都直接与四个角上显示的敏捷开发的核心价值相关:沟通(Communication)、反馈(Feedback)、勇气(Courage)和简单(Simplicity)。也就是说,每个做法都给予我们一条实现敏捷开发价值并让它们成为该过程一部分的具体方法。

 

在理想状况下,如果决定采用敏捷软件开发的方法,你就应该在一个经过管理层许可的敏捷开发实验项目里尝试所有的作法。这是掌握敏捷开发的最好方法之一,因为这样能保证得到支持,为你的努力提供更多的回报,帮助捕捉学习到的东西,这样你才能让敏捷开发过程来适应你独特的环境。

然而,这并不总是可行的,所以有的时候最好采用步步为营的方法。在这种情况下,我们建议从最里面的圆环向外面的圆环推进。也就是从开发人员实践开始,然后是小组这一层次的做法,最后再融入“统一小组(one team)”的概念。

为技术优势设个限——开发人员做法
技术优势是敏捷开发过程的核心。为了让其他的做法真正生效,我们必须在开发人员中进行技术优势的培训。从表面上看,技术优势可能看起来并不是核心优先对象,但是如果把我们注意力都放在上面,它将确保我们编写出不同寻常的优秀代码。这反过来同样会给予公司、客户,以及用户对软件和对我们交付能力的信心。

开发人员做法(developer practice)是我们推动技术优势的切实可行的方法。即使是独立完成,而没有其他敏捷开发做法的介入,开发人员做法也能够给你的软件带来巨大的收益。

开发人员做法可以被分解为四个做法(如果你把实际的编写代码的过程加上去就是五个做法)。它们分别是测试-编码-重整循环(Test-Code-Refactor cycle)、配对编程(Pair Programming)和简单设计(Simple Design)等。

测试-编码-重整(TCR)循环——第一步
由测试驱动的开发和重整常常被当作是各自独立做法,但是它们事实上是TCR循环的一部分。要建立我们正在寻求的紧密反馈循环,我们就需要把它们放在一起。

我们在这里的目标有两层:测试让我们对代码质量的充满信心,并能表明我们加入新代码的时候没有破坏任何东西;重整和测试有助于让代码变成我们就代码实际在做什么而进行沟通的最真实形式——任何人都应该可以看到它,并知道什么是什么。

由测试驱动的开发(TDD)是一个循环,它从测试失败开始,然后是编写足够的代码通过测试,再是重整代码,使得代码在实现系统当前功能的条件下尽可能地简单。

测试-编码-重整循环非常短暂——也就几分钟。如果超出这个时间范围那就意味着测试的级别过高,有可能加入了未经测试的实现代码。

在本文的开始部分,我们不会举出TDD的例子,有关的内容会在后面2, 3, 4详细讨论。在这里,从整体上把握并把重点放在TCR循环更有趣的方面上会更加有用。

就同任何极限编程/敏捷开发项目一样,要做的第一个素材(story)是一个经过简化的应用程序,用来完整地说明程序的功能。在本文里,这样的应用程序是一个二十一点纸牌游戏。在经过简化的第一个素材里,只有一个玩家外加一个发牌人,每个玩家只会得到两张牌,获胜者是两张牌发完后点数最大的人。

素材/要求
一个简单的二十一点纸牌游戏

玩家下注 
给玩家和发牌人每人两张牌 
给获胜者支付奖金(玩家获胜的机会为2:1) 
验收测试
要知道我们的素材什么时候完成就需要经过一系列验收测试。我们这个简单游戏的验收测试如下:

玩家获胜
 发牌人获胜
 平局
 
玩家赌注总额=100
 玩家赌注总额=100
 玩家赌注总额=100
 
发牌人赌注总额=1000
 发牌人赌注总额=1000
 发牌人赌注总额=1000
 
玩家下注10
 玩家下注10
 玩家下注10
 
玩家发到10 & 9
 玩家发到8 & 9
 玩家发到8 & 9
 
发牌人发到8 & 9
 发牌人发到10 & 9
 发牌人发到8 & 9
 
玩家赌注总额=110
 玩家赌注总额=90
 玩家赌注总额=100
 
发牌人赌注总额=990
 发牌人赌注总额=1010
 发牌人赌注总额=1000
 


任务
素材往往单独解决起来往往非常困难,所以在一般情况下我们都把它分解为一系列任务来完成。在本文的二十一点纸牌游戏里,需要进行下列任务:

创建一副牌 
创建一个投注台面 
创建一手牌 
创建游戏 
创建一副牌
在把素材分解成为任务的时候,我们可以把各个任务再分解成一系列待办事项,从而指导我们进行测试。这让我们可以保证在通过所有测试之后完成这个任务。对于这一副牌,我们有下列事项需要完成。

向牌桌上放一张纸牌 
在发牌的同时将其从牌桌上移走 
检查牌桌是否为空 
检查牌桌上纸牌的张数 
将牌桌上的一副牌的张数限制为52张(如果超过,就要显示异常) 
不断发牌,直到发完 
洗牌 
检查牌桌上纸牌的张数是否正确 
在进行过第一轮的几个简单测试之后,我们的待办事项列表就像下面这样了:

向牌桌上放一张纸牌 
在发牌的同时将其从牌桌上移走 
检查牌桌是否为空 
检查牌桌上纸牌的张数 
将牌桌上一副牌的张数限制为52张(如果超过,就要显示异常) 
不断发牌,直到发完 
洗牌 
检查牌桌上纸牌的张数是否正确 
下一个要进行的测试是从牌桌上发牌。当我们在为测试方法编写代码的时候,我们所扮演的角色就是将要编写的应用程序的用户。这就是为什么我们给自己的类创建的接口要与给用户的接口像类似的原因。在本文的这个例子里,我们将按照命令/查询分离原则(Command/Query Separation Principle5)编写出下面这样的代码。

Deck类。如列表A所示。

列表A

import java.util.List;

import java.util.ArrayList;

public class Deck {

private static final int CARDS_IN_DECK = 52;

private List cards = new ArrayList();

public boolean isEmpty() {

return size() == 0;

}

public int size() {

return cards.size();

}

public void add(int card) throws IllegalStateException {

if(CARDS_IN_DECK == size())

throw new IllegalStateException("Cannot add more than 52 cards");

cards.add(new Integer(card));

}

public int top() {

return ((Integer) cards.get(0)).intValue();

}

public void remove() {

cards.remove(0);

}

 }

 

我们所有的测试都通过了,而且我们没有看到任何重复或者其他必要的重整,所以应该是时候进行下面的测试了。然而事实却不是这样的。我们top和remove 方法的实现里有一个潜在的问题。如果对一个空的Deck调用它们,会发生什么?这两个方法都会从纸牌的内部列表里跳出一个 IndexOutOfBoundsException异常,但是目前我们还没有就这个问题进行沟通。回头看看简单性的原则,我们知道自己需要沟通。我们的类的用户应该知道这个潜在的问题。幸运的是,我们将这种测试当作是一种沟通的方式,因此我们增加了下面的测试。

 

public void testTopOnEmptyDeck() {

Deck deck = new Deck();

try {

deck.top();

fail("IllegalStateException not thrown");

} catch(IllegalStateException e) {

assertEquals("Cannot call top _disibledevent="http://eddiboysen.spaces.live.com/Blog/cns%21AB2AA80C6592E82%21258.entry">http://eddiboysen.spaces.live.com/Blog/cns!AB2AA80C6592E82!258.entry

目录   译者序   第2版前言   第1版前言   第0章不可知和不可说   0.1和解析体验相关的问题   0.1.1解析模式的冲突   0.1.2检测解析模式   0.1.3思考不准确的思想   0.2沟通的不可能性   0.2.1内部重新组织   0.2.2触及共享体验   0.2.3管理不完美的沟通   0.3聆听的三个层次   0.3.1三个层次和方法集   0.3.2三个层次与本书   0.3.3守-破-离   0.4那么,明天我做什么   第0A章不可知和不可说:演进   0A.1沟通和共享的体验   0A.2守-破-离   第1章创造和沟通的合作博弈   1.1软件和诗歌   1.2软件与博弈   1.2.1博弈的类型   1.2.2软件与攀岩   1.2.3创造和沟通的博弈   1.2.4软件与工程化   1.2.5软件与模型构建   1.3再论合作博弈   1.3.1程序员成为沟通专家   1.3.2更快地博弈   1.3.3标识物和道具   1.3.4减少回报   1.3.5对于首要目标的充分度   1.3.6对于积淀的充分度   1.3.7博弈中的博弈   1.3.8开放源码开发   1.4这对我意味着什么   第1A章创造和沟通的合作博弈:演进   1A.1沼泽游戏   1A.2合作中的竞争   1A.3其他领域的合作博弈   1A.4软件工程的重建   1A.4.1这一词汇从哪里来   1A.4.2我们从哪里走错了   1A.4.3重建软件工程   1A.4.4技艺   1A.4.5合作博弈   1A.4.6精益制造   1A.4.7重建后的软件工程   1A.4.8其他工程化中的协作   第2章个人   2.1人是古怪的   2.1.1寻找特征函数   2.1.2古怪性格的元素   2.1.3不可避免的多样性   2.1.4技术的作用   2.1.5相互冲突的共同点   2.2克服失败模式   2.2.1犯错误   2.2.2宁可失败也要选择保守   2.2.3创新而不研究   2.2.4不能始终如一的习惯动物   2.2.5使用纪律和容忍来应对   2.3以一些更好的方式工作   2.3.1具体化   2.3.2实物   2.3.3在某些东西的基础上进行修改   2.3.4观察和聆听   2.3.5支持专注和沟通   2.3.6工作分配要与个性相匹配   2.3.7天赋   2.3.8奖励要能保留乐趣   2.3.9组合奖励   2.3.10反馈   2.4利用成功模式   2.4.1善于四处寻找   2.4.2人们学习   2.4.3可塑性   2.4.4贡献和采取主动   2.4.5组合成功模式   2.4.6英雄也是普通人   2.5明天我该做什么   第2A章个人:演进   2A.1策略平衡   第3章团队的沟通与合作   3.1信息的对流   3.1.1延迟和机会损失成本   3.1.2尔格-秒   3.1.3渗透式沟通   3.1.4穿堂风   3.1.5信息辐射源   3.1.6热空气理论的应用   3.2跨越沟通的鸿沟   3.2.1沟通的形态   3.2.2去掉某些形态所产生的影响   3.2.3利用各种形态   3.2.4黏度与跨越空间的鸿沟   3.3团队就是集体   3.3.1友善和冲突   3.3.2工作时间的公民意识   3.3.3敌意的XP与友善的XP   3.3.4使用胜利来建立“团队”   3.3.5团队文化与亚文化   3.4团队就是生态系统   3.5我明天该做什么   第3A章团队:演进   3A.1一个修订后的办公室布局样本   第4章方法集   4.1一个交付软件的生态系统   4.2方法集中的概念   4.2.1结构术语   4.2.2范围   4.2.3概念术语   4.2.4发布一个方法集   4.3方法集的设计原则   4.3.1常见设计错误   4.3.2在方法集上成功的项目   4.3.3与作者的相关性   4.3.4七条原则   4.4细看XP   4.4.1XP简介   4.4.2剖析XP   4.4.3调整XP   4.5到底为什么使用方法集   4.5.1方法集解决什么问题   4.5.2如何评估一个方法集   4.6明天我应该做什么   第4A章方法集:演进   4A.1方法集与策略   4A.2组织级的方法集   4A.3过程就是循环   4A.4更简单地描述方法集   第5章敏捷与自适应   5.1轻但足够   5.1.1刚好足够   5.1.2对于编制文档的建议   5.2敏捷   5.2.1最佳击球点   5.2.2虚拟团队的麻烦   5.3变得自适应   5.3.1不厌其烦地进行反思   5.3.2方法集成长技术   5.3.3反思研讨会技术   5.4明天我该做什么   第5A章敏捷与自适应:演进   5A.1对于寓意的误解   5A.1.1迭代必须简短   5A.1.2敏捷团队必须驻扎在一起   5A.1.3敏捷团队不需要计划   5A.1.4架构已死;重构是你全部所需要的   5A.1.5我们不需要什么经理   5A.1.6敏捷开发在纪律上要求很低   5A.1.7敏捷只适合最优秀的开发人员   5A.1.8敏捷是既老又新的、失败的、没有尝试过的   5A.2敏捷方法集的演进   5A.2.1XP第2版   5A.2.2Scrum   5A.2.3实用主义和无名的   5A.2.4可预测、计划驱动和其他中心调整   5A.2.5约束理论   5A.2.6精益开发   5A.3新的方法集话题   5A.3.1敏捷项目管理   5A.3.2测试   5A.3.3用户体验设计   5A.3.4规划管控、Burn图和系统工程   5A.3.5用例和用户故事   5A.4经久不绝的问题   5A.4.1最佳击球点和下降   5A.4.2固定价格、固定范围的合同   5A.4.3敏捷、CMMI和ISO9001   5A.4.4何时停止建模   5A.4.5高科技/高接触的工具箱   5A.4.6敏捷的中心   5A.4.7你有多敏捷   5A.4.8引入敏捷   5A.5软件开发之外的敏捷   5A.5.1项目组合管理   5A.5.2客户关系   5A.5.3合同   5A.5.4将变更引入组织   5A.5.5程序员读哈佛商业周刊   5A.5.6建造房屋   5A.5.7机场建设   5A.5.8图书出版   5A.5.9会议组织和敏捷模型的限制   第6章Crystal方法集   6.1对Crystal家族塑形   6.1.1核心Crystal元素   6.2CrystalClear   6.2.1CrystalClear的简要描述   6.2.2CrystalClear的反思   6.3CrystalOrange   6.3.1CrystalOrange的简要描述   6.3.2CrystalOrange的反思   6.4CrystalOrangeWeb   6.4.1CrystalOrangeWeb的简要描述   6.4.2CrystalOrangeWeb的反思   6.5明天我该做什么   第6A章Crystal方法集:演进   6A.1Crystal基因代码   6A.1.1合作博弈的理念   6A.1.2方法集的重点   6A.1.3方法集设计原则   6A.1.4高度成功的项目的7个特性   6A.1.5技术与选择   6A.1.6样本方法集设计   6A.2CrystalClear   6A.3把CrystalClear扩展到Yellow   附录A敏捷软件开发宣言   附录Aa敏捷软件开发宣言和相互依赖声明   附录BNaur、Ehn、宫本武藏   附录BaNaur、Ehn、宫本武藏:演进   附录C后记   参考文献
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值