简介 迭代开发是OOA/D成为最佳实践的核心,也是本书所介绍的OOA/D的核心。 敏捷实践(如敏捷建模)是有效地应用UML的关键。UP是相对流行的、示范性的迭代方法。本章将对这些主题进行介绍。
相对于顺序或“瀑布”(waterfall)生命周期,迭代和进化式开发(interative and evolutionary development)对部分系统及早地引入了编程和测试,并重复这一循环。这种方式通常会在还没有详细定义所有需求的情况下假设开发开始,同时使用反馈来明确和改进演化中的规格说明。
在迭代开发中,我们依赖于短时快速的开发步骤、反馈和改写来不断明确需求和设计。相比之下,瀑布模型提倡在编程之前就预先完成需求和设计步骤。一直以来,成功/失败的研究表明,瀑布模型和软件项目高失败率具有极大关系,对它的推广源于信念和风闻,而不是具有统计意义的证据。研究证实,迭代方法与较高的成功率、生产率和低缺陷率具有关系。
什么事UP? 其他方法能否对其进行补充 软件开发工程描述了构造、部署以及维护软件的方式。 统一过程已经成为一种流行的构造面向对象系统的迭代软件开发过程。特别是,Rational统一过程(Rational Unified Process ,RUP)是对统一过程的详细精化,并且已经被广泛采纳。
UP是十分灵活和开放的,并且鼓励引进其他迭代方法中的有用的实践,诸如极限编程(Extreme Programming,XP)、Scrum等等。 例如,在UP项目中可以引入XP的测试驱动开发(test-driven development)、重构(refactoring)和持续集成(continuous integration)等实践。同样,也可以引入Scrum的公共项目室(“作战室”)和Scrum日常会议等实践。
概括而言,本章介绍UP源于下述三个理由:
1、UP是迭代过程。迭代开发对本书介绍OOA/D的方式,以及OOA/D的最佳实践具有影响。
2、UP实践提供了如何实施OOA/D的示范结构。这也形成了本书的结构。
3、UP具有灵活性,可以应用于轻量级和敏捷方法,这些方法包括其他敏捷方法(诸如XP或Scrum)的实现,稍后将对此作更多介绍。
什么是迭代和进化式开发 迭代开发(interative development)是UP和大多数其他现代方法中的关键实践。在这种生命周期方法中,开发被组织成一系列固定的短期(如三个星期)小项目,称为迭代(iterative),每次迭代都产生经过测试、集成并可执行的局部系统。每次迭代都具有各自的需求分析、设计、实现和测试活动。
迭代生命周期基于对经过多次迭代的系统进行持续扩展和精化,并以循环反馈和调整为核心驱动力,使之最终成为适当的系统。随着时间和一次又一次迭代的递进,系统增量式地发展完善,因此这一方法也被称为迭代和增量式开发(interative and incremental development)(参见图2-1)。因为反馈和调整使规格说明和设计不断进化,所以这种方法也称为迭代和进化式开发(interative and evolutionary development)。
每次迭代都产生可执行的但不完整的系统,它不是已经准备好可以交付的产品。直到多次迭代之后,系统才能够合格的用于产品部署。
迭代的输出不是实验性的或将丢弃的原型,迭代开发也不是构造原型。与之相反,其输出是最终系统的产品子集。
如何在迭代项目中处理变更
每次迭代选择一小组需求,并快速设计、实现和测试。在早期迭代中,对需求和设计的选择对于最终期望来说可能并不准确。但是,在最终确定所有需求或经过深思熟虑而定义完整设计之前,快速地实施一小步的方式可以得到快速反馈--来自用户、开发人员和测试的反馈。
这种反馈具有极高的价值。与“推测”完整、正确的需求或设计相反,团队可以从实际构造和测试的反馈中,挖掘出至关重要和实际的观点,并修改和调整对需求或设计的理解。 早期频繁地在“不错。。。但是”中循环,正是改进软件和发现什么对涉众有真正价值的实用方式。然而这并非对开发者不断变换方向的无序和反应式开发的认可,作为一条中间路线是可行的。
除了明确需求之外,负载测试将验证局部设计和实现是否正确,或者是否需要在下次迭代中改变核心架构。最好及早解决和验证具有风险的、关键的设计决策,而迭代开发提供了完成这项工作的机制。
因此,工作是通过一系列有序的构造--反馈--调整循环向前进展的。早期迭代中系统偏离“正确轨迹”的程度会大于后继迭代。随着时间的发展,系统将沿着这一轨迹收敛。如图2-2
迭代开发的优点
迭代开发的优点包括:
1、减少项目失败可能性,提高生产率,降低缺陷率。对迭代和进化式的研究表明了这一点。
2、在早期(而不是晚期)缓解高风险(技术、需求、目标、可用性等等)
3、早期可见的进展
4、早期反馈、用户参与和调整,会产生更接近涉众真实需求的精化系统。
5、可控复杂性:团队不会被“分析瘫痪”或长期且复杂的步骤所淹没
6、一次迭代中的经验可以被系统地用于改进开发过程本身,并如此反复进行下去。
一次迭代的持续时间和时间定量
大部分迭代方法建议迭代时间在2~6周之间。小步骤、快速反馈和调整时迭代开发的主要思想,迭代时间过长会破坏迭代开发的核心动机并增加项目风险。 迭代的一个关键思想是时间定量(timeboxed),或时长固定。
什么是瀑布生命周期 在瀑布生命周期过程中,试图在编程之前(详细定义所有或大部分需求)。而且在通常与编程之前创建出完整的设计。同样,会试图在开始前定义“可靠的”计划或时间表,但常常事与愿违。
反馈和改写的必要性
在复杂、变更系统中(如大多数软件项目),反馈和调整是成功的关键要素。
1、来自早期开发中的反馈,有助于程序设计人员理解规格说明,客户演示也有助于精化需求。
2、来自测试中的反馈,有助于开发者精化设计或模型。
3、来自团队处理早期特性过程中的反馈,有助于精化时间表和估计
4、来自客户和市场的反馈,有助于重新定义下一次迭代实现特性的优先级。
+ -
如何进行进化和迭代式分析和设计 这里的介绍可能会给人留下这样的印象,即编程前的分析和设计毫无价值,但这是与瀑布思维同样偏激的误解。迭代和进化式分析设计师中庸之道。这里有个简短的例子,用以说明在运转良好的UP项目中,迭代方法是如何被运用的。这里假设在项目交付前,最终将有20次迭代。
-
在第一次迭代之前,召开第一个时间定量的需求工作会议,例如确切的定义为两天时间。业务和开发人员(包括首席架构师)需要出席。
1> 在第一天上午,进行高阶需求分析,例如仅仅确定用例和特性的名称,以及关键的非功能性需求。这种分析不可能是完美的。
2> 通过咨询首席架构师和业务人员,从高阶列表中选择10%列表项(例如,30个用例中的10%),这些项目要具备以下三种性质:A、具有重要的架构意义(如果要实现,我们必须设计、构造和测试的核心架构) B、具有高业务价值(业务真正关心的特性) C、具有高风险(例如“能够处理500个并发交易”等)。所选的三个用例可能被标识为:UC2、UC11和UC14。
3>在剩下的一天半内,对这三个用例的功能和非功能性需求进行详细的分析。完成这一过程后,对10%进行了深入分析,90%进行了高阶分析。
在第一次迭代之前,召开迭代计划会议,选择UC2、UC11和UC14的子集,在特定时间内(例如,四周的时间定量迭代)进行设计、构造和测试。要注意的是,因为其中包含大量工作,所以并不是在第1次迭代中就要构造出全部三个用例。在选择了特定子集目标后,在开发团队的帮助下,将其分解为一系列更为详细的迭代任务。
在三到四周内完成第1次迭代(选择时间定量,并严格遵守时间)。
1> 在开始的两天内,开发者和其他成员分组进行建模和设计工作,在首席架构师的带领和指导 下,于“公共作战室”的众多白板上,画出UML的草图(及其他的模型)。
2> 然后,开发者摘掉其"建模帽子"并带上"编程帽子",开始编程、测试和集成工作并且剩余的时间均用于完成这项工作。开发者将建模草图作为其灵感的起点,但要清楚这些模型只是局部的,并且通常是含糊的。
3> 进行大量的测试,包括单元测试、验收测试、负载测试和可用性测试等。
4> 在结束前的一周,检查是否能够完成初始的迭代目标;如果不能,则缩小迭代的范围,将次要目标置回任务列表中。
5> 在最后一周的星期二,冻结代码;必须检入、集成和测试所有代码,以建立迭代的基线。
6> 在 星期三的上午,向外部涉众演示此局部系统,展示早期可视进展,同时要求反馈。
在第一次迭代即将结束时(如最后一周的星期三和星期四),召开第二次需求工作会,对上一次会议的所有材料进行复查和精化。然后选择具有重要架构意义和高业务价值的另外10%到15%的用例,用一到两天对其进行详细分析。这项工作完成后,会详细记录下大概25%的用例和非功能性需求。当然,这也不是完美的。
于周五上午,举行下一次的迭代计划会议。
以相同步骤进行第二次迭代
反复进行四次迭代和五次需求工作会,这样在第四次迭代结束时,可能已经详细记录了约80%~90%的需求但只实现了系统的10% (注意,这些大量、详细的需求集是基于反馈和进化的,因此其质量远高于纯粹依靠推测而得出的瀑布式规格说明)
我们大概推进了整个项目过程的20%。在UP的术语里,这是细化阶段(elaboration phase)的结束。此时,可以估计这些精化的、高质量的需求所需工作量和时间。因为具有依据现实得出的调查、反馈结论并进行了早期编程和测试,因此估计能够做什么和需要多长时间的结果会更为可靠。
此后,一般不需要再召开需求工作会;需求已经稳定了(尽管需求永远不会被冻结)。接下来是一系列为期三周的迭代,在最后一个周五召开的迭代计划会议上选择适宜的下一步工作,每次迭代都要反复询问:“就我们现在所知,下一个三周应该完成的、最关键的技术和业务特性是什么?”
PPT2-5 中描述了经过20次迭代的项目。
利用这种方式、经过早期探索式开发的几次迭代之后,团队将能够更准确地回答“什么、多少、何时”。
什么是风险驱动和客户驱动的迭代计划 UP(及大多数新方法)提倡风险驱动(risk-driven)与客户驱动(client-driven)相结合的迭代计划。这意味着早期的迭代目标要能够识别和降低最高风险,并且能构造客户最关心的可视化特性。
风险驱动迭代开发更为明确地包含了以架构为中心(architecture-centric)迭代开发的实践,意味着早期迭代要致力于核心架构的构造、测试和稳定。为什么?因为没有稳固的架构就会带来高风险。
什么是敏捷方法及其观点 敏捷开发(agile development)方法通常应用时间定量的迭代和进化式开发、使用自适应计划、提倡增量交付并包含其他提倡敏捷性(快速和灵活的响应变更)的价值和实践。除此之外,他们还提倡反映简易、轻量、沟通、自组织团队等更多敏捷性的实践和原则。
Scrum敏捷方法中的实践范例包括公共项目工作室和自组织团队,这些实践通过每日例行会议来协调工作,在例会上要求每位成员回答四个特定的问题。 极限编程(XP)方法中的实践范例包括结对编程和测试驱动开发(test-driven development)。
包括UP在内的任何迭代方法都可以施加以敏捷精神。
什么是敏捷建模 有经验的分析员和建模者了解以下这条建模的秘诀: 建模(构建UML草图)的目的主要是为了理解,而非文档。 也就是说,建模的真正行为能够并且是应该能够对理解问题或解决方案空间提供更好的方式。
在"Agile Modeling" 一书中,将这种观点及与之一致的敏捷方法称为敏捷建模(agile modeling)。 这其中包含了以下许多实践和价值:
1、采用敏捷方法并不意味着不进行任何建模,这是个错误理解。Feature-Driven Development、DSDM和Scrum等许多敏捷方法、一般都包含重要的建模期。正如Ambler(XP 方法和敏捷建模的专家)所言,即便是XP(可能是最少强调建模的最为知名的敏捷方法)的奠基人也认可敏捷建模,并且多年来有大量建模者都在实践中采用了敏捷建模。
2、建模和模型的目的主要用于理解和沟通,而不是构建文档。
3、不要对所有或大多数软件设计建模或应用UML。可以将简单的设计问题推延到编程阶段,在编程和测试过程中解决这些问题。只需对设计空间中不常见、困难和棘手的一小部分问题建模和应用UML
4、尽可能使用最简单的工具。建议使用支持快速输入和改变的“低能耗”创造力增强型的简易工具。同时,选择支持大可视空间的工具。例如,最好在白板上草图UML,使用数码相机捕获图形。(这里 并不是说UML CASE工具或字处理软件不可取或毫无价值,但是对于创造性工作来说,在白板上画草图更为流畅并便于修改。关键的规则是简单和敏捷,而不论使用何种技术)
5、不要单独建模,而是结对在白板上建模,同时要记住建模的目的是发现、理解和共享大家的理解。小组成员要轮流画草图,以使每个人都参与其中。
6、并行的创建模型。例如,在一块白板上勾勒UML动态视图的交互图,同时在另一白板上勾画出补充性的UML静态视图的类图。同时开发这两种模型(视图),并不断交替。
7、在白板上用笔画草图时,应使用“足够好”的简单表示法。UML细节是否精准并不重要,关键是建模者能够互相理解,坚持使用简单、常用的UML元素。
8、要知道所有模型都可能是不准确的,最终代码或设计会与模型有差异,甚至具有极大的差异。只有测试过的代码才能证实真正的设计;先前绘制的模型图都是不完整的,最好只是将其视为一次探索。
9、开发者应该为自己进行OO设计建模,而不是创建模型图后交给其他编程者去实现--这是非敏捷的面向瀑布的方法。
本书中的敏捷建模:为什么使用UML草图的快照 因为这些图是为了提高可读性而使用工具精心绘制的。为了让大家感受真实情况,本书有时会使用在白板绘制的UML草图的数码快照。这样虽然易读性差一些,但是可以提醒读者敏捷建模是很有用的,并且这种方式是案例研究所使用的实际工作方式。
什么是敏捷UP UP的创始人并没有为其赋予重量级或非敏捷的含义,尽管其庞大的可选活动集和制品集会给人留下这种印象。实际上,UP可以采纳和应用可适应性和轻量级的精神--敏捷UP。以下是应用的一些示例:
1、推荐使用UP活动和制品的简集。虽然某些项目得益于使用较多的UML活动和制品,但一般来说应该保持简洁。要记住,所有UP制品都是可选的,除非它们能增加价值,否则避免创建这些制品。应该致力于早期的编程,而非构建文档。
2、UP是迭代和不断进化的,所以在实现前的需求和设计师不完整的。它们是在一系列迭代中,基于反馈而产生的。
3、以敏捷建模实践应用UML
4、对于整个项目不应有详细的计划。应该制定估计结束日期和主要里程碑的高阶计划(称为阶段计划),但是不要对这些里程碑详细定义细粒度的步骤。只能预先对一个迭代制定更为详细的计划(称为迭代计划)。详细计划是由一次次迭代的调整而完成的。
UP的其他关键实践 UP所倡导的核心思想是:短时间定量迭代、进化和可适应性开发。其他一些UP的最佳实践和关键概念包括:
1、在早期迭代中解决高风险和高价值的问题
2、不断地让用户参与评估、反馈和需求
3、在早期迭代中建立内聚的核心架构
4、不断的验证质量;提早、经常和实际地测试
5、在适当的地方使用用例
6、进行一些可视化建模(使用UML)
7、认真管理需求
8、实时变更请求和配置管理
什么是UP的阶段 UP项目将其工作和迭代组织为四个主要阶段:
1、初始(Inception):大体上的构想、业务案例、范围和模糊评估
2、细化(Elaboration):已精化的构想、核心架构的迭代实现、高风险的解决、确定大多数需求和范围以及进行更为实际的评估
3、构造(Construction):对遗留下来的风险较低和比较简单的元素进行迭代实现,准备部署
4、移交(Transition):进行beta测试和部署
图2-6说明了UP中常用的面向进度表的术语。注意,一个开发周期(以系统发布为产品作为结束标志)由多个迭代组成
什么是UP科目 UP描述了科目(discipline)中的工作活动,例如编写用例。科目是在一个主题域中的一组活动(及相关制品),例如需求分析中的活动。在UP中,制品(artifact)是对所有工作产品的统称,如代码、Web图形、数据库模式、文本文档、图、模型等。
UP中有几个科目,本书中只关注以下三个科目中的制品:
1、业务建模: 领域模型制品,使应用领域中的重要概念的可视化。
2、需求:用以捕获功能需求和非功能需求的用例模型及其补充性的规格说明制品。
3、设计:设计模型制品,用于对软件对象进行设计。
图2-7列出了更多的UP科目。 在图中,实现表示编程和构建系统,而不是部署。环境科目是指建立工具并为项目定制过程,也就是说,设置工具和过程环境。
科目和阶段之间的关系 如图2-7所示,一次迭代的工作会遍历大部分或全部科目。然而,跨越这些科目的相对工作量会随着时间发生变化。自然而然,早期迭代倾向于更多的需求和设计,后期迭代则较少进行这方面的工作,因为通过反馈和改写过程,需求和核心已经趋向于稳定。
就UP阶段(初始、细化等)的这一主题,图2-8阐述了对应于各阶段的相对工作量的变化。请注意,这只是建设性意见,而非强制。
UP阶段和科目对本书结构的影响 案例研究强调初始和细化阶段。其重点是业务建模、需求和设计科目中的一些制品,因为这些都是需求分析、OOA/D、模式和UML的主要应用之处。
下面的列表和图2-9描述了本书关于UP阶段的组织。
1、初始阶段对应的章介绍需求分析的基本内容
2、迭代1介绍OOA/D基础和如何为对象分配职责
3、迭代2的重点是对象设计,特别介绍一些经常使用的“设计模式”
4、迭代3介绍各种主题,例如架构分析和框架设计。
如何定制过程和UP开发案例
UP中有可选制品或实践吗 当然! 几乎所有的制品和实践都是可选的。也就是说,某些UP实践和原则是一成不变的,例如迭代和风险驱动开发以及质量的持续验证。 然而,UP的一个关键内涵是,所有活动和制品(模型、图、文档。。。)都是可选的--或许除了代码!
UP中描述的一组可能的制品可以看作药房里的一组药剂。就像不会有人不加选择地随便吃药,而是要对症下药一样,对于UP项目,开发团队应该选择一组能够解决其特定问题和需要的制品。一般来说,要关注一组具有较高实践价值的制品。
定义:什么是开发案例 为项目选择实践和UP制品可以编写为简短文档,这称为开发案例(环境科目中的制品)(PPT01)可以作为本书所探讨的"NextGen项目"案例研究中的开发案例
判断你是否理解迭代开发或UP 若出现以下迹象,表明你并没有理解以敏捷精神采用迭代开发和UP的真正含义。
1、在开始设计或实现之前试图定义大多数需求。同样,在开始实现之前试图定义大多数设计;试图在迭代编程和测试之前定义和提交完整的架构
2、在编程之前花费数日或数周进行UML建模,或者认为在绘制UML图和进行设计时要准确完整地定义及其详细的设计和模型。并且,认为编程只是简单机械地将其转换为代码的过程
3、认为初始阶段=需求阶段,细化阶段=设计阶段,构造阶段=实现阶段(也就是说将瀑布模型叠加于UP之上)
4、认为细化的目的是完整仔细地定义模型,以能够在构造阶段将其转换为代码
5、坚信合适的迭代时间长度为三个月之久,而不是三周
6、认为采用UP就意味着要完成大量可能的活动和创建大量的文档,并且认为UP是需要遵循大量步骤的、正规和繁琐的过程
7、试图对项目从开始到结束制定详细计划;试图预测所有迭代,以及每个迭代中可能发生的事情。