简介: 越来越多的公司开始实施敏捷开发。如果我们把敏捷开发看作一剂应对软件危机的良药的话,那么实施敏捷开发的先决条件就是这副良药的药引子。本文根据作者黄文海的实际敏捷开发与项目管理经验分享了实施敏捷开发的技术方面的先决条件,希望为准备引入敏捷开发的团队提供方向上的指引。
自动化测试工具支持
迭代开发是所有敏捷开发方法的共同特征。迭代开发中的两个迭代之间往往涉及对同一个功能的变更。这种情况下,当前迭代测试时不仅要执行针对这一功能变更的修改和新增测试用例,还要执行那些不需要改动的用例,以保证两个版本间的兼容性。随着时间的推移,迭代过程中需要运行的兼容性测试用例会越来越多。此时,如果没有自动化测试工具支持,要在一个迭代内运行之前所有迭代的兼容性测试用例往往成为一件实际不可行的事情。然而,保持版本间的兼容性又尤为重要。可见,如果说敏捷开发是动车的话,那么自动化测试工具就是动车的轨道。
敏捷开发中的优秀实践,如持续集成(Continuous Integration)和重构(Refactoring),也都是要求自动化测试工具支持的。
软件架构支持与架构看护
很多系统,一开始还有清晰的架构,甚至在若干年后,代码上还留有其最初的开发者对于架构的思考痕迹。但是,随着时间的推移,原有开发人员的离职以及其后不断的人员变更,现有功能的变更、新增功能所带来的代码变更,往往使得这个系统的重复代码越来越多,模块间的耦合度越来越大。最后,这个系统成了个一改代码就会”牵一发而动全身”的没人敢碰的”烫手山芋”:代码不改动倒好,一旦改动,则系统到处出错。这种情况很大程度上是系统的架构缺少看护,导致日积月累的代码修改将原有的架构抛在一边,最终使得该系统的架构逐渐退化。
迭代开发中,往往前一个迭代实现的功能,这个迭代就涉及到了它的变更,同时又有新的功能要增加。这种变更所带来的频繁的代码改动,应该要有适用的架构提供支持,以便一个功能的修改和新增能够以最小的代码改动来实现,并且这些代码改动对现有代码所可能产生的影响最小。否则,代码改动困难以及对现有代码的影响太大可能导致的返工会加大开发和测试的工作量。这对于敏捷开发来说,影响是重大的。因为敏捷开发一个迭代周期可能短到两周,根本不允许工作量浪费。这就要求系统的架构足够灵活,或者足够简单以至于即便新增或者修改功能要求架构进行变更,这种变更也显得很容易。
架构本身的清晰度和简单性也很重要。一个过于复杂的架构会增加其理解与学习的难度,不利于其运用和对其进行看护,导致加速其退化。
笔者在所带领的项目中则是通过设计会话(Design Session)和代码复审这两个活动落实和体现架构看护。
模块化打包与服务端热部署支持
敏捷开发往往采用 Story 驱动开发。Story 驱动开发中的一个 Story 代表着软件的利益干系人角度来看的软件价值的最小单位。因此,如果敏捷开发中的各个活动如编码和测试都能够以 Story 为单位,则更加能够体现 Story 驱动开发的本意---聚焦用户价值。模块化打包和部署意味着我们能够以一个 Story 而不是整个应用系统为单位进行打包和测试。这为 Story 驱动开发提供了坚实的技术支持:
其一,在一个迭代中通常有多个 Story 需要实现的情况下,任何一个 Story 只要其具备可以转测试的条件都可以通过以 Story 为单位进行打包转 Story 测试,而不必等其它 Story 也具备转测的条件再一起打包进行集中转 Story 测试。也就是说此时各个 Story 对应的 Story 测试(Story Test)可以并发进行,从而为减少了测试过程中的等待,有利于项目进度。
其二,在以 Story 为单位进行打包和部署的前提下,一个 Story 的相关产物一经测试验证达到可以交付的条件时,并不会因为其它 Story 的产出物有问题需要重新进行打包进行转测而使该 Story 需要重新打包测试。这意味着以一个 Story 的测试一旦通过,则相应的需求分析、编码、测试这些工作的成果就可以固定下来,避免了不必要的重复劳作。
传统的 J2EE 系统中,打包是以整个 Web 应用系统为单位打成一个 WAR(Web Application Archive)的。这种打包方式往往意味着当一个后达到可以转测的 Story 打包时,先完成的 Story 也被迫要重新进行打包。此时即便这个 Story 已经完成了 Story 测试,也要重新进行测试。因为后打包的 Story 可以由于代码上的耦合影响先打包的 Story。而采用 Story 为单位进行打包,通常意味着这个 Story 的实现代码及其依赖库、相关配置是从物理同其它 Story 隔绝开来的从而实现了各个 Story 的产出物相对独立。比如 Java 平台中的 OSGi(Open Service Gateway Initiative)就支持这种使各个 Story 的产出物能够从物理上隔绝开来的特性。
笔者所带的敏捷团队中就是采用以 Story 为单位对某个 Story 的相关产出物进行打包先进行Story 测试。Story 测试阶段着重的是软件的功能。待 Story 测试通过后,再以 Story 为单位进行性能评估测试。这个测试也通过后,则说明相应的 Story 已经达到可以交付的条件了,即这个 Story 从敏捷开发的角度来说”完成”了。这样,整个团队为这个 Story 所付出的工作也就固化下来了。
模块化部署包的热部署意味着可以在不重新启动应用服务器的情况下部署模块。这便于在同一个测试服务器上并行多个 Story 的测试,使得这些先后部署的模块相互间不影响(因为一个模块的部署不要求重新启动应用服务器从而避免了先前已经部署的模块的测试被迫中断),从而使团队能够充分利用有限的硬件资源及时间。
Java 平台中的 OSGi 规范的实现就支持模块化部署包的热部署。