摘要
在IT界中,“敏捷”是一个很酷的词汇,“敏捷”的相关理论可谓铺天盖地。
“敏捷”一词实质没有统一定义,各家有自家的说法,本教程将让你了解“敏捷”的来龙去脉,抓住“敏捷”本质,并能在工作中实践“敏捷”。

大纲:
“敏捷”陷阱
为什么会有“敏捷”这个说法?
极限编程
敏捷开发
RUP
敏捷开发的实质是什么?
如何才能敏捷起来?


作者:
张传波
首席专家
软件知识原创基地
www.umlonline.cn


正文:

“敏捷”陷阱

小甲想到某开发公司应聘开发工程师,向该公司的某开发人员打听他们的开发方式。
小甲:请问贵公司开发模式是怎样的?
开发人员:咱们敏捷开发!不用写文档,写好代码就可以了。
小甲心想:哇,爽啊!赶紧去应聘!

小甲已经在该公司工作了数周,他觉得很郁闷:
无需求文档,要做东西都是口头分配的。
无计划可言,想到啥就做啥。
加班不在话下,返工是家常便饭。
这就是敏捷开发吗?

不少公司搞CMMI认证,推行过程改进,往往被开发人员嗤之以鼻,开发人员喜欢自由奔放有创造力的工作模式,喜欢敏捷!
然而很多号称“敏捷”的公司,其实只是手工作坊的工作模式,想到啥就干啥,如果你是开发人员可能还会好一点,如果你是测试人员、实施人员,在这样的公司你简直会觉得无法沟通无法工作!

到底什么是敏捷呢?如何才不会跌入敏捷陷阱呢?

为什么会有“敏捷”这个说法?

大学时我们就被灌输了这样的知识:
生命周期模型有瀑布型、喷泉型、迭代型、螺旋型等。
一般来说,大型的、复杂的、对安全要求高的系统,应该采用传统的瀑布型来开发,应采取重型过程。
对于中小型、需要快速投产的系统,应采用灵活的生命周期,采用敏捷的方式开发。

其实“敏捷”是相对于“重型”提出来的,重型开发有这样的特点:(摘自互联网)
1.刻板而严格控制。
2.很多活动和工件,官僚主义气息浓重。
3.文档繁多。
4.长期而详细的计划。
5.过程高于本质核心的工作。
6.面向过程而不是面向人,把人看成机械方法中的插件。
7.预见而不是适应。

于是我就很有疑问了,如果重型开发有这样的特点,那么请问:对于大型的、复杂的、安全要求高的系统,也需要用具备上述特点的重型过程来开发吗?如果是这样,谁愿意在这样的工作环境下工作?具备这样特点的过程对项目成功有什么好处?

“重型”的重要特点是呆板,因为大家不喜欢呆板,喜欢灵活,所以提出了“敏捷”的说法!
我猜想:
1.重型过程其实是一些没有实际项目经验的理论家搞出来的产物。
2.重型过程的出发点纯粹就是为了过程而过程。
当然上述论述纯属瞎猜,无法证实。

每个人对“重型”与“敏捷”的理解其实都不太一样,这里我用一个问题来测试一下你:
我国的航天事业取得长足的发展,让国人振奋,请问:你认为嫦娥工程采用的过程是重型的还是敏捷的?

这么重大的项目,很多人可能认为应该是重型过程,很多人可能认为敏捷的过程是不太严禁的过程,其实嫦娥工程是灵活而又十分严谨的工程。
大家有没有留意到我们火箭发射时间是如何预报的?是不是具体说某天某时某刻发射?
不是!而是说某段时间内择机发射!“择机发射”是多么灵活、科学、严谨的发射计划啊,完全与我们传统的计划想法不一样,难道你能说这也是重型过程吗?

所谓“重型”与“敏捷”其实都是相对的,我们没有必要去争论到底是“重型”还是“敏捷”。我们平时见到这么多“重型”“敏捷”的不同说法,其实大家都是各自从不同的标准出发。

下面我们将介绍常见的几种敏捷开发,每种理念其实背后的道理是很类似的,我们没有必要去争论哪种方式更好,你完全可以吸取百家所长化为自己的理念,按照你的想法将项目做好。

极限编程

极限编程英文叫:Extreme Programming,简称叫XP,最开始我接触到XP的说法时,还觉得是Windows XP的XP呢!

我第一次学习极限编程的最佳实践时,让我震撼不已,后来再工作中不断体会,有了自己的见解。我将这些最佳实践分为几类:需求、设计、测试、编码、项目管理

需求方面的最佳实践:

1.客户故事:强调以客户的语言来表达需求。

需求分析有很多科学系统的方法,采用这些系统方法有时候往往不如使用最原始的土方法,就是用客户的陈述来表达需求!
极限编程认为,客户不能清晰认识自己想要什么是很正常的事情,项目组也没有必要成为业务专家,所以通过这两个最佳实践让客户来引导项目。项目的开发工作讲究短平快,系统会分为多个小版本发布,客户经过多个版本发布会逐步清楚认识到自己想要什么。

这个最佳实践鉴于我国的情况,其实是很难执行的。我们的项目一般合同价钱是签死的,项目时间也是死的,基本都没有机会让我们来回折腾,如果我们不能在项目初期精准地分析出客户真正的需求,项目失败的机会是非常高的。

我在实际工作中往往会通过用户故事来获取原始需求,然后对这些用户故事进行提炼,提炼后的需求再跟客户确认。我认为项目组还是很有必要成为业务专家,项目组中还是很需要有需求分析方面的高手,项目经不起折腾啊!

2.客户全程参与:强调从项目一开始到最后,客户应该与项目紧密联系,发挥更大的作用。

这个实践在实际工作中应该很好地贯彻,不要仅在需求阶段才让客户介入,客户最好就能常驻在项目小组内。下面有一些让客户多参与的建议做法:
1)需求阶段要与各用户反复确认需求。
2)系统做出界面时马上让客户看看。
3)项目计划要让客户知道。
4)每周向客户发送项目进展报告。
5)让客户参与测试软件。

设计方面的最佳实践只有一条:

1.简单设计:不用长远考虑,只要设计能保证当前功能可以实现就行。

软件开发的可谓千变万化,能将功能做出来的最简单设计就是最好的设计,你不需要考虑以后发生变化还能重用这些设计和代码,明天的事情鬼知道,搞定今天的事情就可以了!

这个实践有点剑走偏锋,有人还会因为这个实践不仔细思考软件设计就编码了,我们有很多项目因为设计得太烂而吃了不少苦头。实战简单设计时,我有这样的一些建议:
1)对于没有类似经验的项目,设计应该尽量简单,但简单的设计是需要严谨的思考得到的,你不要认为简单想一个设计出来就是简单设计。
2)思考项目设计时,应考虑有什么东西可以重用,同时适当考虑本项目有什么东西可供以后的项目重用。

测试方面的最佳实践:

1.测试驱动开发:先有测试再有开发。

我们一般的顺序是先开发后测试,然则这个实践要求我们先将测试想好,然后开发来满足这些测试。
这个思路其实就是目标驱动,我们先假设软件已经做好,那么我们先写出测试用例,然后我们编写的开发代码应该能通过这些测试用例。这样思路的好处就是能让我们想清楚目标,所有的开发都是有针对性的,减少无用功,提高工作效率,同时因为测试已经写好了,代码的质量会更加有保障。

这个思路其实是相当优秀的,但这个实践可能是这么多最佳实践中最难成功实施的!我们公司曾经推行过一段时间,最终还是失败告终。难以施行有以下原因:
1)开发人员普遍没有这么高的编程素质。
先不说测试驱动开发,我们往往连单元测试也做不到!测试驱动开发其实就是要求我们先写出单元测试代码,然后再写出满足单元测试代码的代码。
2)编码是一个循序渐进的过程,不太可能一开始接口就想好并且后面不会变了。
我自己编写代码也不太可能一开始就完全想清楚类中的各个属性方法,有时候会觉得方法名字不好会换掉,参数不太合适也会调整。如果我们先写出测试的代码,其实就要求我们先确定各类名称以及各类的公开接口,但往往我们需要不断调整,这样就会导致开发代码与测试代码都需要同时调整,工作量就增大了。
3)达不到自动化测试的技术层次。
自动化测试需要工具支持,并不是所有公司都具备这样的条件。

测试驱动开发的意义还是很重大的,我有这样的一些实践建议:
1)先写开发代码,然后写单元测试代码。
2)编写代码时,应该先想清楚类职责,类公开接口,然后再写具体实现代码。
3)某个类完成时或者阶段性完成了一些功能时,应该马上写出相应的测试代码,并保证开发代码能通过测试。
4)如果不能针对所有类都写出测试类,那至少应该针对重要的、核心的、被使用次数多的类编写测试代码。
5)单元测试应该能做到自动化。

2.自动化测试:自动化单元测试、自动化UI测试。

自动化单元测试,目前很多开发工具都支持,技术上问题不大,问题大的是大家不去执行或者说是能力不够执行不了。

UI方面的自动化测试就有点麻烦了,有这样两点:
1)就算是比较好的自动UI测试工具,也难以捕捉到软件界面上所有的控件以及动作。
2)软件的界面经常调整是很常见的时间,界面不冻结,UI自动化测试寸步难行。

要推行100%的自动化测试难度还是很高的,不过应该还是尽量自动化测试,单元自动化测试与性能自动化测试在技术上是没有问题的,是执行的能力与决心问题。

自动化测试这个最佳实践与测试驱动开发是紧密相关的,这两个最佳实践其实是整个极限编程中最核心、最精彩、要求最严格的两个实践。只要将这两个实践做好,代码随便你改,只要能通过测试就行,不用害怕需求变更带来的代码隐患,变就变,反正有自动化测试全面检查!

编码方面的最佳实践:

1)重构:不讲究一次将代码写好,但需要重构时应该毫不犹豫。

重构的意思是代码的接口和实现功能不变,但修改代码的具体实现,从而使代码的结构、可读性、性能、安全性等更好。
重构因为有测试驱动以及自动化测试这两个实践的支持,故不需要担心重构带来的影响,万一重构失败,取回原来的代码便可。

2)结对编程:两个人,组成一对,共用一台电脑编程。

头次听说这个,还觉得很难想象,两个人坐在一起,只用一台电脑,一个人写代码,另外一个看,过一会两个人可以交换一下。
两个人一起写代码,相当于随时在做同行评审,似乎效率降低了,但代码的质量得到保障,并且能保证所有代码至少有两个人了解的。
另外要注意的是:组成一对的两个人,应该水平相当。

这个实践很有意思,不过往往也是很难实践的。
就我个人来说,我就不喜欢两个人一起编程,我觉得每个人的思考其实很难同步的,每个人都需要静下心来一个人思考问题,思考后才适合与别人讨论,如果思考过程也与别人在一起,很难想象这个思考能有好的效果。

我们曾经将两位编码新手放在一起,让他们结对编程,尝试了这个实践,似乎有一点效果,但我们后期就没有再推行过。

3)代码共有:每个人写的代码都是属于全体的,每个人可以去改别人的代码。

这里强调共享与进步精神,欢迎互相研究代码,欢迎写出更好的代码,只要能通过测试就可以了!这个实践是依赖于测试驱动开发以及自动化测试这两个实践的,如果不能做到那两个实践,就不应该随便改动别人的代码。

4)强调编码标准

对于这点大家应该没啥异议了,现在有不少开发工具支持编码标准检查呢!

项目管理方面的最佳实践:

1.持续集成

持续集成与微软的“每日构建”是一样道理的,强调我们的软件要随时处在可以编译通过可以发布的状态,持续集成让软件的问题提早暴露更快解决。持续集成需要一定的工具和管理措施支持,我有这样的一些实践建议:
1)代码的签入与签出要定下严格的规矩,如:每天工作前先获取最新代码,每次签入前必须先保证编译通过。
2)如果能做到测试驱动测试和自动化测试,那么还应该规定必须通过所有测试才能签入代码。
3)一般来说我们没有条件做到每日构建,也没有这么多工具支持,那么至少一周要编译一次内部版本,检查软件各部分的协调情况。

2.站立会议

每天早上项目组全体开5-10分钟会议,所有人站立讲话,简单讲述昨天工作概要、今天计划、需要别人协调或解决的问题。站立的目的就是让大家言简意赅,提高会议效率。每天开这个会,是保证大家有足够的及时的口头沟通。极限编程认为,口头沟通才是最有效直接的沟通。

在我们的项目中,我也会推行站立会议,但不一定是早上,当然也不一定非要站立,但是会议一定必须是高效的!口头沟通很有效,但必要的记录还是应该有的。一些公司推行站立会议,往往是没有会议记录的。而我的做法是会议中如果有决定、有×××工作,我会要求记录下来。口头沟通算然来得直接,但容易理解错、容易忘记等缺点是避免不了的,应该辅以适当的书面记录。

3.小版本发布

分小版本多次发布,最符合客户的利益,客户可以先使用部分功能,可以在此基础上更好地思考后续应该做什么。
小版本到底应该有多小呢?国外很多书会建议3个月,不过3个月对于国内的项目来说,太长了!我们经常要在很短的时间内做出一个大系统!
我们公司每个版本的发布周期以前大概是一个月,现在已经缩小到2-3周了。

4.每周工作40小时

加班是我们IT人的家常便饭,极限编程反对加班!那么是不是我们只要工作时间到了,哪怕很多事情没有做完,就直接下班呢?
这条实践的真正意思是我们应该充分利用好工作的40小时,少做最好不做无用功,少返工。实际上我们很多加班是因为我们做了很多无用功、返工导致的。
人的脑袋每天能高速运转8小时其实已经很了不起了,如果还要加班,那么只能带来更多的bug,得不偿失!不过我们很多公司的老板喜欢看到我们这些打工仔忙,看到我们加班,而不管实际的效果,这真是悲哀啊。

极限编程的各条实践是有关系的,我觉得最基础的最重要的是测试驱动与自动化测试,这两条做不能做好,重构、代码共用等实践就难以实施。
极限编程很多东西很讲究灵活,但测试驱动这条是最死的要求最严格的,整个灵活的体系其实就是靠这一条来保证质量的。很多公司实践极限编程时,不能做到测试驱动,就简单设计,就随便改代码,随便因应需求变化而变动代码,这些工作都没有了质量保障的基础。

极限编程我们需要整体来理解各条最佳实践,并根据实际情况加以调整,为我所用!

下面将会稍微简单一点介绍另外了两个比较常见的敏捷开发。

敏捷开发

有一种敏捷开发,就叫敏捷开发。你可以认为这种是“狭义”敏捷开发,而本文标题所说的敏捷开发是泛指所有带有敏捷特点的开发模式。

这种敏捷开发有这样的特点:

1.个体和交互胜过过程和工具。
以人为本,注重编程中人的自我特长发挥。

2.可以工作的软件胜过面面具到的文档。
强调软件开发的产品是软件,而不是文档。文档是为软件开发服务的,而不是开发的主体。

3.客户合作胜过合同谈判。
客户与开发者的关系是协作,不是合约。
开发者不是客户业务的“专家”,也不是为了开发软件,把开发人员变成客户业务的专家。
要适应客户的需求,就要通过客户合作来阐述实际的需求细节。

4.响应变化胜过遵循计划。
设计周密是为了最终软件的质量,但不表明设计比实现更重要。
要适应客户需求的不断变化,设计也要不断跟进,所以设计不能是“闭门造车”、“自我良好”。
要不断根据环境的变化,修改自己的设计,指导开发的方向。

你可能会感觉到这些特点与极限编程的相似与不同之处,同时你也会感觉到这些特点很多与传统的重型开发针锋相对的。

RUP

统一软件过程,英文全写为:Rational Unified Process。

下面这两张图最能反应RUP的特点:

敏捷开发纵横谈_第1张图片

敏捷开发纵横谈_第2张图片

以上两图来自互联网

为了方便大家理解,我弄了中英文两张图,两者是一个意思,不过内容组织稍微有点不同,大家注意一下就行了。

要精确理解RUP的意思还是有点难度的,简单谈谈我对RUP的理解。

按照时间顺序,项目分为初始(inception)、细化(Elaboration)、构造(Construction)、交付(Transition)四个阶段,
每个阶段会有很多个小迭代。这四个阶段其实很难说有明显界限的,我觉得大家大概了解每个阶段的工作内容就可以了。

按照工作的性质,项目的工作可以分为以下几类:
商业建模(Business Modeling)
需求(Requirements)
分析和设计(Analysis & Design)
实现(Implementation)
测试(Test)
部署(Deployment)
配置管理与变更管理(Configuration & Change Mgmt)
项目管理(Project Management)
环境(Environment)

以上这些工作,在项目的不同时期工作量分布是不太一样的,如:商业建模、需求这些工作往往是头大尾小,分析与设计、实现等是中间大两头小,项目管理、环境方面的工作一直都会持续进行。

RUP的思想打破了“需求-设计-编码-测试”这样的传统瀑布模式,需求、设计、编码、测试这些工作其实一直都在进行的,只是不同时间比重不一样。这个思想是很符合“敏捷”的特点,也和实际情况非常吻合。

大家理解这个意思后,我觉得完全可以按照自己公司的实际情况重新定义时间上的阶段,也可以自己重新定义项目的各类工作,以及思考各类工作在项目不同时间的工作量分布。

关于敏捷开发的流派还有很多,如:自适应软件开发、水晶方法、实用编程等等,我觉不同流派其实本质还是很类似的,这里就不一一介绍了。

敏捷开发的实质是什么?

什么是敏捷?我想大家各有各的说法,我觉得敏捷过程应该是这样的:
1.一个项目目标明确的过程。
2.有利于实现项目目标的事情,一定要做。
3.对项目目标没有帮助的事情,一律不做。
4.有效和高效是最重要的项目管理原则。
5.敏捷的过程是让人愉快、工作起来有战斗力的过程。

敏捷开发简单说就是有有效的办法去做有用的事情,过程的目的是让项目做得更好,不是为了过程而过程,不是用过程来“框死”项目,过程是为项目服务的。

各家各派的敏捷方法论,其实基本道理都是这样的,只是各自从不同的角度来阐述如何做软件开发。我们没有必要盲目崇拜某某方法论,各种方法论也没有必要PK,我们应该集百家所长,为我所用!

如何才能敏捷起来?

有时候我们会这样说:懒人会更聪明,因为他会想尽一切可以偷懒的办法。如果说,敏捷开发其实就是“懒人”想出来的,这样也不算奇怪。
那是不是我们就可以做“懒人”了?当然不是了,如果你不足够聪明你就没有资格做“懒人”!
其实“懒人”一点都不懒,因为他的脑袋从来是不偷闲的,他的脑袋是很勤快的。

说了这么多,我其实想说的是:要敏捷,最关键在于多思考!
不要尽信各种敏捷方法论,你必须思考,必须能提出自己的疑问和见解,这样你才算理解这些方法论。
你需要多实践、多充实自己的知识,这样你才会有更多的思考本钱,更多的打仗用的武器。
你需要多总结,总结使人进步!

敏捷很容易,只要你开始思考如何让工作更有效,只要你开始改善你的工作方法,你已经开始敏捷了!

 

-----全文完-----