这篇文章最近才读到,可能其中的场景已经不适应,但是它的思想还是值得借鉴。
---------------------------------------------------
在基于瀑布模型java企业开发中的敏捷最佳实践
---------------------------------------------------
有人说2007是敏捷到来年,伴随着的是其最佳实践,像自动化构建、自动化测试和持续集成。尽管理论上这是真的,但是现实却是很多java企业项目仍然采用基于传统的开发方法,譬如瀑布模型。在这篇文章中,ShriKant Vashishtha从开发人员和构建经理的角度揭示了一些传统java企业开发中的一些“伤痛点”。接着,他为我们展示了一些敏捷最佳实践,如何不改变瀑布模型开发流程的情况下容易以及自然的解决这些问题。
围绕敏捷开发方法的议题已经非常流行,但是真要将一个传统型企业变成敏捷型却要付出巨大的努力。同传统软件开发相关的范围、时间、产品交付等并不能很容易的转换到敏捷过程中,甚至有些需要完全的丢弃。经理、开发人员甚至客户都必须在敏捷开发的缩短项目周期和强调更大的个人主动性的特性中承担更多的任务。我们必须通过整个企业来管理这些改变并且评估采用一小套标准后的影响。地理上的分布式开发团队面对敏捷开发过程时在保证目标上尤其需要经受挑战,因为敏捷开发更喜欢面对面交流。你难道不诧异敏捷开发为什么实践跟不上理论的脚步?
通过 Forrester Research
的研究,2007年,仅仅26%的北美和欧洲企业采用敏捷实践。尽管瀑布模型消亡的谣言四起,瀑布开发模型(上一阶段的输出作为下一阶段的输入)仍然在java企业开发中存在。对java开发人员来说,这是一件令人沮丧的事情:我们想改良开发过程和产品质量,并且我们也相信敏捷是正确的道路,但是瀑布模型仍然是个障碍。
或者尝试一下?伴随着一些人简单的在传统模型中采用敏捷,一个渐进的转变也许更加具有实践意义。即使你的公司或者开发团队同瀑布模型联系紧密,采用敏捷最佳实践来改良产品和提高效率也是可能的。实际上,很多基于瀑布模型的项目已经支持敏捷最佳实践,并且还能够支持更多。
在这篇文章中,我将通过一个场景从开发人员和构建经理两个视角来说明在传统项目开发中的一般性问题。然后我会给出敏捷实践像自动化构建、自动化测试、持续集成如何来解决这些问题,即使是在一个瀑布模型开发环境中。同时,我也会介绍很多工具,通过它们你可以在自动化测试和持续集成环境中测试、衡量和改善代码质量。
瀑布模型的演化
列出瀑布模型的弱点,然后通过敏捷实践克服这些缺点,这是能让人信服的。实际上,瀑布模型已经采用了很多同敏捷开发相似的实践。看看下面这些:
大多数团队知道最后一个阶段才进行应用的集成的年代已经一去不复返了。今天,在很多的周期里面进行开发、单元测试、软件集成已经很普遍了。我曾经看到很多基于瀑布模型的项目每天构建2-3次。
传统的瀑布模型项目,直到软件开发完成才交付进行系统测试或者验收测试。现在很少大项目或者时间紧急的项目能够承受这种方式。客户经常希望能够通过代码review来看看软件的质量,鼓励在更短的周期内使用更多的迭代。交付的功能依据客户的需求和开发的可行性被排定顺序,同时客户在每一个迭代完成后给出反馈。这些反馈对于项目的下一次迭代有很直接的影响,并且也不会让客户收到最终的交付产品时很吃惊。
瀑布模型有一个基本的缺点,需求在开发开始前必须定死。在后面的开发周期中都不允许改变,即使这个改变在后面的阶段是不可避免的。很多瀑布型开发企业已经采用了基于紧急程度和工作量来进行变化控制。像图1描述的那样。
图1 典型的变化控制流程
所有这些典型的敏捷最佳实践让瀑布模型在满足客户需求方面更具有操作性。
传统java EE项目能够从下面的这些敏捷开发实践中受益。
吃人的项目
利用项目场景是揭示瀑布模型弱点的最简单的方式。看一个包括150-200人的典型java企业项目。这个项目被分成很多功能模块,从个体来看,每一个都是一个更小的项目。大体上,项目包括10-15个EAR和WAR文件。为了测试整个应用,全部安装是必须的。SVN是这个项目所用的源代码控制工具。
现在让我们来看一下每天开发人员和构建经理的活动,来看看它们所面临的风险。
开发人员角度
第一步是从svn中检出代码安装开发环境。但是每次我从svn上检出最新的代码后,我的开发环境都会崩溃。原因是很多同事提交的代码不能够编译。我认为是一些提交的代码文件存在没有解决的编译问题。当一些内部库类的方法签名突然被改变的时候我也陷入了麻烦,没人通知我!!更坏的情况是你所依赖的一个库被改变了,但是没有提交到svn。那只能在运行时出错。更坏的是即使这个库被提交了,也可能出现版本不一致的情况。
哈,这麻烦了,不是吗?作为一个卑微的开发人员,我只关心我的模块而不担心其他模块的错误。不幸的是,我的模块依赖于其他模块。我只是一个开发人员,我却不得不面对应用安装、类路径、库等等其他信息。不管相信与否,有很多时候安装问题会耗费一整天时间,接下来便是很少时间的开发,这给我带来很大的压力。
另一个问题对我来说简直是地狱:我的模块功能是位于整个应用的最后面,测试我的模块需要其他模块提供的数据支持。在到达我的模块之前有9个步骤,只要其中任何一步出现问题,就到不了我这个模块。经常需要花费我6-7个小时来解决其他问题,然后才能测试我的业务case!
你可能说“哦,可怜的家伙”,而我担心的是我到底在做什么?不是集中精力在开发和修改我自己的模块功能,反而是花费了大量的时间在本不应该属于我的问题上。更坏的是,项目中的每个人都很忙,要修复这些问题意味着需要很多的帮助,这也意味着很多的时间。
我需要什么
我的需求非常简单:每次我检出代码时,能够安装和构建。对于这个应该被满足的基本需求,在svn中的代码首先是应该在任何时间都是可以编译的。应该有最近的库文件并且应该有很少的手工步骤来构建整个系统。
我也应该能测试我的功能,即使在孤立的环境中。我只是想能够在集成之前构建和测试我自己的功能。
构建经理角度
看看上面的问题,我的情况也差不多。目前,每个应用组件(EAR/WAR)都是独立的构建,每个组件都是一个java项目并且依次在一个文件夹中有自己的jar依赖。如果其中一个jar改变了,我的职责就是更新其他依赖于这个jar的组件。这是手工的。
有时团队成员更新这个jar文件失败,事情会变得很糟。这导致运行时错误,并且在这样一个复杂系统中很难调试。一个jar中的改变然后更新到项目的其他lib目录下面是一种痛苦。每个组件有自己的一套库和构建脚本,构建整个系统是耗时的并且需要不停的人工干预。
正常情况下,仅需要30-45分钟来构建和在服务器上部署应用,但是如果编译问题出现了(经常出现),我不得不找相关人员解决,然后才能部署。这让很多人不高兴。开发人员不能在整个环境中进行测试,测试人员不能及时地获取应用进行测试,这即浪费了时间又浪费了公司的money。人们因此idle,测试经理和项目经理开始抱怨,然后我又陷入了麻烦。我需要一个更容易的方式来解决这些问题!
等等 -- 我还没完成!经常负责项目的多个构建环境是我的职责:开发环境、测试环境、性能测试环境。三个构建环境/机器意味着三套应用,每套在应用配置上都应该有所变化,并且 -- 你猜对了 -- 我需要修改属性配置文件。
现在,想象一下15个ear手工的来配置其属性文件,只是make a build,太可怕了。那是体力活?ha,我恨这个,我的同事更加憎恨。
我需要什么
我应该能够通过一个简单的点击来完成系统构建,需要很少的或者根本不需要人工干预。我也需要一种方式来跟踪在不同模块中的代码是否是可编译的和可部署的。因为从一个库里面创建不同的环境构建,我需要一个仅修改配置属性文件就可以准备一个新环境的机制。我也需要一种更新jar文件到整个项目的方式。本质上,我需要能够将一个地方的改变自动应用到所有的关联项目中。
一般需求
在上面的场景中开发人员和构建经理的需求,你也许很熟悉。很容易理解工作在一个指定模块的开发人员不应该担心项目的更大的技术架构。同样,我们也能理解构建经理在如此大的项目上的需求:少一点人工并且专注于重要的任务。我总结了对于这个项目开发人员和构建经理的需求,如下:
- 能够检出代码、手工配置越少越好并且可以在"裸机"上进行构建
- 提交到svn的代码应该是可编译的并且准备好随时被构建
- 最新的库文件应该随时在所有项目中可获取
- 能够跟踪所有项目环境是否可被构建,并且任何人都可以随时查看这个状态
- 能够通过修改配置来为任何环境创建build
- 能够更新一个地方的jar,就可以影响到其他独立的组件。
下面我们将看一下如何采用敏捷实践来满足这些需求,即使是在一个基于瀑布模型开发的项目。
自动化构建
第一个需求说能够在一台裸机上进行代码检出、构建。自动化构建,敏捷开发的重要部分,能够坚决这个需求。很多开发人员使用IDE来进行构建,这对快速构建是有益的,但是你还需要一个独立的自动化构建脚本。ANT和Maven是基于java项目的两个自动化构建工具。Gant正在获得喜欢Groovy的开发人员的喜爱。不管怎么说,构建脚本不是项目私有的并且能够在任何平台上执行。
上例中的成功地自动化构建过程应该实现如下内容:
1. 在svn库中的应用代码首先应该包含所有的默认配置,否则要求开发人员来修改。同时还要包含一个构建脚本来自动化更新这些配置文件来代替手工修改。
2. 应该有一个主要的构建脚本来执行所有的这些应用组件的构建。
测试这个自动化安装脚本是一个好主意,让一个没有经验的开发人员来验证这些过程(安装、构建、部署)。这是一个迭代过程;如果这个开发人员遇到麻烦了,我们也就应该考虑修订或者更新这个构建过程。
每个java项目也应该在项目根目录下面有一个readme.txt文件,来描述手工步骤(自动化构建脚本不能执行的)。举个例子,有些项目可能因为加密实现、JAAS配置需要在JRE安全设置上有所不同,这个readme文件也需要列出在服务器上构建和部署应用所需要的步骤。
构建安装:主构建脚本
假定项目包含很多EAR和WAR文件,手工的来执行每个组件的构建脚本是痛苦的,解决的办法就是象上面说的那样,写一个主构建脚本。
注意如果每个独立的构建脚本都有一个默认的target也是很好的。主构建脚本简单的组织这些构建target即可。List 1 是一个主构建脚本例子
Listing 1。使用antde主构建脚本
<target name="build-ABCSecurityServices" depends="call-ABCSecurityServices-build,export-abc-securityservices.jar ">
<copy todir="${artifact}/${env}">
<fileset dir="${SecurityServices}/dist">
<include name="*.ear"/>
</fileset>
</copy>
</target>
<target name="call-ABCSecurityServices-build">
<ant antfile="${Security}/ABCSecurityServices/build.xml" inheritAll="false" target="all" />
</target>
<target name="export-abc-securityservices.jar">
<copy file="${abc-securityservices.jar}" toFile="${project.internallib.dir}/abc-securityservices.jar"/>
</target>
这个ant主构建脚本调用call-ABCSecurityServices-build,不直接包含独立的构建target,这个主构建脚本仅仅委托任务并且组织多个任务。它也能决定任务被执行的顺序。然后所有的构件被复制到一个指定的位置。
假定这个构建经理需要为多个环境进行构建,在外部定义这些环境因素是一个很好的主意。很多时候,这些是配置文件,而不是EAR/WAR中的文件,他们能够被抽取放到应用服务器的类路径上。通过这种方式,EAR/WAR将与环境无关。在不同的环境里面仅仅需要改变这些配置属性即可进行构建。
这个主构建文件让构建经理的工作更加容易,同时实现了通过一个点击来进行构建的需求。
自动化测试
在很多瀑布模型项目中,开发人员开发完一个组件,然后手工执行一套单元测试。将来,如果修改了这个组件,开发人员需要再次手工执行这些单元测试。通常情况下,改变很小,仅需要测试影响的功能即可。在时间有约束并且假定这个改变不影响其他功能的情况下,这样做看起来合情合理,但是有时微小的改变也可能破坏关联的功能,这将只有在整个应用被测试的时候才能发现。
JUnit是自动化测试的一个选择。
测试方法
有很多的方法来执行自动化测试,对于不同的场景类型至少一把的好的测试工具。
DBUnit,是一个基于JUnit的数据库脚本测试工具。
EasyMock
是一个开源的工具,可以用来创建模拟对象或者模拟接口,这样你就不需要依赖第三方代码。
DBUnit和EasyMock是内部组件测试的两个工具. 但是对于前面场景中开发人员遇到的那个问题,他的模块是第10步才执行又怎么样呢?这个开发人员如何才能保证他的模块可以和其他模块正常工作呢?
解决这个问题的关键是创建不同模块的端到端测试用例,这样模块就被在一个组中被连接测试了。集成测试可以使用上面的任何一款工具来完成。在有些情况下,你需要一个技术框架来执行集成测试,一个选择是Spring testing module
(如果整体上没有使用spring)。
Selenium
是用来测试web应用的一款优秀的容易学习的测试工具。它是通过直接在浏览器中通过模拟用户操作来执行测试。
另一个可以增强你的自动化测试的工具是Cobertura
。它让你能够衡量代码覆盖率,或者多少你的代码、行被真正的测试了。
现在我们已经知道了所有上面这些工具,接下来在持续集成环境中使用他们。
持续集成
代码编译不过去是前面的java EE场景中开发人员和构建经历共同面对的问题,开发人员经常处理提交到svn上的有问题的代码,构建经理也花费了很多时间在编译问题解决上。
第一眼看上去,这个开发团队需要进行更好的训练来保证不提交有编译问题的代码到svn中,但是,问题是人非圣贤。
谁能确保代码可以随时可编译的?在描述的场景中,全都是手工过程,检出代码、执行构建。。经常发现代码不能被编译。构建太晚了以至于发现了问题也不能让开发人员及时修改。这些问题是由于将集成放到了软件开发周期的最后一步导致的。那么,为什么不每天集成多次呢?在持续集成环境中,每次集成都被自动化构建验证,包括尽可能早的通过测试用例发现问题。持续集成,或者CI,提供了很好的发现问题的方式。
CI servers
在大项目中,手工检查不能发现所有的这些因为开发人员或者构建经理引起的问题。修复本身就是一项很大的任务。难道你不觉得自动化这些过程会更好吗?下面是一些像CruiseControl
的持续集成服务器。CruiseControl
自动化执行很多琐碎的任务。看看这些:
- 每次有人提交代码到svn中,它就检出那些代码执行构建。它有一些等待周期设置,可以针对一个人提交多个文件,在这些文件提交期间不启动。每次构建失败,它将检查谁最后提交的代码,然后通过email发送一个编译错误日志。这个团队成员应该立刻采取行动来修复这个构建问题。
- CruiseControl提供了一个web用户界面,用户可以随时查看构建的状态。
- 如果构建失败,CruiseControl并不会再次执行构建,除非又有人提交代码。
- 各种构件像EAR、WAR、Junit reports、PMD reports。。。可以通过web界面下载。
- 。。。。。。
准备好了吗?
即使想采用这些解决方案和工具,开发人员和构建经理仍然可能遇到一些基本的组织结构问题需要解决。最重要的,开发人员和构建经理都需要检查提交到svn的代码的可编译和可随时构建。
这个项目是典型的企业开发项目,它所包含的内在java项目或者功能组件存在着错综复杂的关系。每一个都依赖于一个或者多个其他项目,并且每个项目都依赖于提供的功能类型分别提供一个客户端jar(仅包含客户端编译所需要的接口和必需的类)或者一个完整的jar(包含功能组件的所有内容) 文件。所有的这些jar文件都能在各自的项目lib目录下面找到,但是将他们更新到整个项目却是一个巨大的任务,就像构建经理上面提到的那样。
很难弄清楚互相依赖的这些内部jar和第三方jar文件的版本,这可以通过在统一的位置来存放这些jar文件来解决这个问题。(听起来很像maven管理依赖包的方式)
现在,如果项目团队每天创建了新的内部jars,并且svn中的源代码还在更新中,这可能破坏其他组件的功能。你可能收到运行时错误(jar和源代码不一致造成的)。解决办法就是统一内部jar的发布版本。首先,开发人员提交代码之前必须经过一套用例测试。源代码库不应该存在不稳定或者未经测试的代码。当每次更新代码的时候,要保证功能的稳定性,应用组件团队在一个统一的位置来发布这个更新的jar文件。每个应用组件团队都应该有专人来运行测试和确保提交代码到svn之前代码通过测试。
结论
在这篇文章中,我并不是主张完全采用敏捷开发。即使敏捷世界提出了很多好的最佳实践,我仍然尝试保持瀑布模型的主要部分的完整性。你应该在不破坏瀑布模型的主要流程上进行自动化构建和自动化测试。当你开始考虑结对编程,很少的文档或者没有文档,业务相关人员也作为开发的一部分,没有先期设计,没有角色(架构师,构建经理...)。。。。--你正在破坏瀑布模型开发的核心。
这些因素将直接影响利害相关人和整个IT团队的工作方式。本文中讨论的最佳实践,将为瀑布模型开发团队带来如下的好处--自动化构建提供了代码的随时可构建性,自动化测试为测试代码的过程带来了可预知性、精确性以及可靠性,持续集成对于维护代码的可构建性也大有好处。整体上采用这些技术将改善项目的效率、优化团队个人的工作方式,同时这样做带来的项目的稳定性、流程的增加,也不会影响到瀑布模型的核心。
原文
http://www.javaworld.com/javaworld/jw-03-2008/jw-03-agile-practice.html
分享到:
相关推荐
敏捷开发和瀑布模型是两种截然不同的软件开发方法论,它们反映了不同的开发理念和实践策略。 瀑布模型是一种传统的线性开发方法,其特点体现在以下几个方面: 1. 阶段性依赖:瀑布模型强调从需求分析、设计、编码...
随着技术的快速发展和市场环境的不断变化,传统的瀑布式开发模式已经难以适应敏捷与快速迭代的需求,尤其是对于像闲鱼这类互联网产品。敏捷转型是指企业从传统瀑布式开发模式转向更加灵活、高效的敏捷开发模式的过程...
从系统需求分析开始直到产品发布和维护,每个阶段都会产生循环反馈;...可在迭代模型中应用瀑布模型,并且它提供了一个模板,这个模板使得分析、设计、编码、测试和支持的方法可以在该模板下有一个共同的指导。
瀑布模型、极限编程和敏捷开发是软件开发管理的三种典型模式,它们之间的演进关系反映了软件开发管理者在管理模式上的变化。瀑布模型强调文档、流程化和管理控制,适合大型软件开发项目,但缺乏灵活性和客户参与。...
外瀑布内敏捷流程 外瀑布内敏捷流程是敏捷项目管理中的一种流程模型,它强调快速响应变化、客户满意、团队合作和持续改进。该流程模型将项目分为多个迭代周期,每个迭代周期包括需求池、版本计划、迭代计划、站会、...
threejs 瀑布 动画 数据 threejs 瀑布 动画 数据 threejs 瀑布 动画 数据 threejs 瀑布 动画 数据 threejs 瀑布 动画 数据 threejs 瀑布 动画 数据 threejs 瀑布 动画 数据 threejs 瀑布 动画 数据 threejs 瀑布 ...
本文内容包括:简介项目背景为什么要使瀑布式项目变得敏捷?敏捷方法真正实现的程度如何?其他敏捷元素应对挑战使用的工具实现的获益结束语参考资料尽管一个大型项目整体很好地遵循着一个瀑布模型,但该项目的应用...
手机端瀑布流是一种在移动设备上广泛采用的网页布局方式,其设计灵感来源于现实生活中的瀑布,使得内容以一种连续、不规则的方式呈现,用户在滚动屏幕时,新的内容会像瀑布一样自然滑落,带来流畅且极具吸引力的浏览...
微信小程序 瀑布流布局 (源码)微信小程序 瀑布流布局 (源码)微信小程序 瀑布流布局 (源码)微信小程序 瀑布流布局 (源码)微信小程序 瀑布流布局 (源码)微信小程序 瀑布流布局 (源码)微信小程序 瀑布流布局 (源码)微信...
在《软件项目管理:从瀑布到敏捷》中,作者王文虎详细探讨了项目管理的各个方面,包括从传统的瀑布模型向敏捷方法的转变。 1. **项目管理和软件项目管理** - 项目管理是管理一个独特的任务或系统化流程,以创造新...
小程序源码 瀑布流布局 (代码+截图)小程序源码 瀑布流布局 (代码+截图)小程序源码 瀑布流布局 (代码+截图)小程序源码 瀑布流布局 (代码+截图)小程序源码 瀑布流布局 (代码+截图)小程序源码 瀑布流布局 (代码+截图)小...
使用媒体查询(Media Queries)可以确保布局在手机、平板和桌面等不同设备上都能正常工作。 4. **图片懒加载**:由于瀑布流布局可能包含大量的图片,为了提高页面加载速度,可以采用图片懒加载技术。即只加载当前...
总的来说,这个`uni-app`瀑布流插件提供了一种便捷的方式来实现在多个平台上展示瀑布流布局,而无需深入研究复杂的布局算法。通过查看`pages`和`components`中的代码,开发者可以学习到如何在`uni-app`项目中引入并...
综上所述,这个压缩包中的"横向瀑布流代码"很可能包含了一个使用CSS3和可能的JavaScript技巧实现的横向瀑布流布局示例。通过深入研究这些代码,你可以学习到如何在没有依赖外部库的情况下,利用现代CSS3特性构建美观...
微信小程序源码 瀑布流布局(学习版)微信小程序源码 瀑布流布局(学习版)微信小程序源码 瀑布流布局(学习版)微信小程序源码 瀑布流布局(学习版)微信小程序源码 瀑布流布局(学习版)微信小程序源码 瀑布流布局(学习版)...
- 加载更多:为了节省流量和提高用户体验,通常会采用上拉加载更多(Pull-to-Refresh)的设计。 - 懒加载:对于大数据量的瀑布流,通常会采用懒加载策略,只加载可视区域内的数据,其余数据在需要时再加载。 在...
《30天软件开发:告别瀑布拥抱敏捷》是一本关于敏捷软件开发的实用指南,特别是针对Scrum方法进行深入讲解。这本书承诺在短时间内通过敏捷开发方法提高软件开发的效率和质量,而且特别强调在30天内可以完成一个全新...
与传统的瀑布模型相比,敏捷开发更加注重团队之间的紧密协作、持续改进以及高质量的产品交付。敏捷开发的核心价值在于通过小步快跑的方式,快速迭代产品,并在每个迭代周期内收集用户反馈,从而确保产品的最终形态...
2. **瀑布流布局原理**:瀑布流布局的核心在于根据屏幕宽度动态调整列数,并确保每个元素(通常是图片)在垂直方向上对齐。这种布局的关键在于计算每列的高度,当一列的高度超过其他列时,新的元素会添加到下一列,...