为了理解敏捷和架构的关系,我们要讨论3个主要的方法:XP、Scrum和RUP。
1 极限编程:架构形成
XP是以程序员为中心的开发,其中没有一个核心实践明确讨论了软件架构,然而,这并不是说XP项目和XP团队不用或不理解架构在软件开发中的作用。Beck[2000]提到:“架构在XP项目中和在其他软件项目中一样重要”。因此,我们在概念上从XP方法入手是一个好的开端。接着Beck继续解释架构是如何形成的。
首次迭代,先挑选一些简单的和基本的故事,这些故事可以支持你创建整个架构。接下来,缩小范围,用最简单有效的方法实现这些故事。这个过程一旦结束,你就拥有了架构。
这些评论在XP的视角上提供了附加的解释。如果一个范围适度的系统,通过少量故事的一两次迭代展现出一个合理的架构基线,那么这种方法可能非常有效,使用这种模型就可能形成相当好的架构。并且,由于XP主要被推荐和应用于小团队,其有关团队大小和架构策略的观点是一致的。
此外,如果时间证明形成的系统架构不能支持系统继续演化,那么系统也可以较快地改写或者重构。事实上,重构代码是XP这个快速开发方法的关键组成部分,也是XP的特色。正如Beck[2000]所提到的:XP热中于重做,而不是减少重做的频率。对XP程序员来说,没有重构的日子就像没有阳光的日子一样。
在一个重构课堂上,Highsmith讲述了一个敏捷项目第一次发布的情况,项目是由一个10人小团队花费了大约7个月的时间后交付的。这次交付足以使公司在一个新兴市场稳坐头把交椅,并通过产品用户的客观反馈,更好地理解产品到底需要做什么。Highsmith接着讲述了一个大约60天的重构阶段,团队重新改写了系统以前实现的一个重要部分,把这部分加入到更好的结构基线中,并实现了新出现的需求。
由于仅花费两个月来重新开发系统,尝试早期交付过程的确是获取需求和形成架构的高效方法,并且能够很快推出满足新兴市场需求的产品,而尽早交付是XP方法的基本原则。因此,该重构模型在此环境中非常有效。
2 Scrum
Scrum是一个敏捷软件项目管理过程,其特征是面向团队和授权、固定周期的评审和调整,以及驱动组织变更以实现提高软件生产率的目标的过程。
虽然Scrum并没有描述软件工程实践本身,[9]但是许多Scrum领导者认为XP是合适的开发过程,并且许多Scrum主管推荐把XP作为Scrum的同伴过程。例如,Sutherland[2005b]在PatientKeeper公司把XP实践应用于系统开发,以及Scrum和高级Scrum持续改进中。此外,Scrum中的3个角色(开发者,产品主管和Scrum主管)都不承担特定的架构职责。相反,Scrum依赖于一条久经考验的敏捷宣言原则“最好的架构、需求和设计来自于自组织的团队”。因此,正如其言,Scrum没有多少关于软件架构的内容,我们需要在其他地方寻找敏捷架构指南。
3 在FDD中的架构
域对象建模是FDD 8个最佳实践之一(其他7个是按特征开发、私有代码所有权、特征团队、审查、定期构建、配置管理和结果的可视化)。域对象建模是唯一涉及系统架构的最佳实践,这样,域对象建模在特定敏捷实践中为架构概念占据了重要的一席之地。
域对象建模是从应用系统支持的现实世界对象(实体)的视角创建系统模型的过程,是所有面向对象设计和架构技术的关键原则,也是FDD的一项关键实践。域对象模型除了定义这些对象之外,还用于定义这些实体间的关系。这些关系可以是静态的(通用性/特异性、多重性和依赖性),也可以是动态的(消息传递),这样域模型就可以达到团队想要的足够高(或足够低)的建模深度。正如Palmer[Palmer和Felsing 2002]所提到的一样。
当分析师和开发者得知需求……他们开始在头脑中形成待建系统的思维图像。他们非常细心,并对这个想象中的设计做些假设。这些隐含的假设可能造成人们工作的不一致。开发全局的域模型会使这些假定暴露出来。
显然,当敏捷方法应用于可伸缩系统时,任何这样的误解都会引起系统性能的不一致(实用程序或性能缺陷)和系统间接口的不一致(设计缺陷)。反过来,本来可以避免的一些重构或重做工作就成为必须要做的事情了。因此,在可伸缩系统中必须保证有一些建模。
根据我们的经验,当团队采用更多的敏捷开发实践时,许多团队都很少依赖需求和架构约定(和更具扩展性的建模),这些需求和架构约定可能是他们以前方法中的“生命周期”早期阶段获取的。然而,同时,这些团队会依赖于简单却高效的域模型的可视化展示,将其作为项目的原始架构。我们也看到,许多敏捷团队不论在开始还是在开发过程中都相当依赖这个关键制品。
4 RUP:以架构为中心
我们在第1部分中提到过,RUP的根源在于开发一套支持面向对象开发方法的软件过程。此外,RUP的大部分内容融入了Rational公司技术领导在做咨询时从应用程序到大规模系统中所获取的经验教训,这些技术领导有Grady Booch、Philippe Kruchten、Walker Royce和 Ivar Jacobson等人。综合起来,形成RUP的实践主要来自于针对面向对象开发方法的大规模系统的开发。的确,RUP已经被一些公司(如Ericsson等公司)应用于大规模系统的项目,在这样的项目中同时有几千名开发人员参与开发。
RUP的主要特点是“以架构为中心和用例驱动”。Booch对“以架构为中心”进行了如下描述:
(1)架构是可以命名和管理的东西;
(2)人们使用架构容纳用例,有意识地管理风险,并且通过迭代和增量的方式完善架构。
所以,作为高效大规模系统软件开发的基础实践,RUP考虑架构已经很长时间了。Kruchten[2004]提出了可伸缩系统架构的重要性的演变。
由于很多软件系统并不复杂,架构可以让开发者保持相互理解。然而,为了适应新的需求,随着系统的演变和发展,情况就完全不同了,系统无法同步增长。集成新技术需要完全重建系统。此外,设计者也缺少判断系统组成部分合理性的智能工具。所以,糟糕的架构总是被列为软件失败的原因就不奇怪了。没有架构,或者使用糟糕的架构是软件项目的主要技术风险。
那么,RUP拥有应用于迭代和增量软件过程条件下的架构开发指南就不足为奇了。目前,RUP指南包括一组用于定义系统的架构视图,每个视图都从架构上反映了一个或多个重要利益相关者的视角。其中,有如下两个强制的视图。
用例视图。每个系统只有一个用例视图,用例视图图示了所有用例和场景,从架构上包含了重要的系统行为、类或者技术风险。
逻辑视图。每个系统只有一个逻辑视图,逻辑视图图示了关键的用例实现、子系统、包和类,从架构上包含了重要的系统行为。
此外,RUP额外规定了4种可选的视图,这4种视图可以根据所配置系统类型等方面的重要性酌情使用。
进程视图。当系统拥有多个控制线程,并且线程之间有交互或依赖时推荐使用该视图。该视图通过把类和子系统映射为进程和线程说明了系统的进程分解。
配置视图。当系统分布在多个结点之间并且结构上存在牵连时,推荐使用该视图。配置视图图示了处理系统中一组结点的分布,包含进程和线程的物理分布。
实现视图。当实现不是严格由设计驱动时,即设计和实现模型中的相应包之间的责任分布是不同的时,推荐使用该视图。实现视图在给个人或团队分配实现任务时非常有用。恰当的实现结构会支持高效的持续集成。
数据视图。当持续数据是系统的关键部分时,推荐使用该视图,例如,包含数据模式、数据定义和算法等内容的系统