摘要
软件开发方法学由来已久,通常包括一个流程或建模技巧,或者二者兼而有之。比如,过去和现在使用过的开发方法就包括:Structured
Systems Analysis and Design Methodology(结构化系统分析和设计方法,SSADM)、Object
Modeling Technique(面向对象建模技术,OMT),以及Rational Unified
Process(Rational统一流程,RUP),等等。最近的研究表明,采用SSADM瀑布式开发方式完成Big
requirements up front(预先最大需求,BRUF)或big design up front(预先最大设计,BDUF)的传统方法,不仅造成时间和精力的极大浪费,还会导致软件开发项目遭遇挑战,并/或全盘失败。本文将探讨BRUF和BDUF的替代方法,以尽可能减少企业软件应用程序开发中的这种浪费。
本文大部分内容直接摘自《Agile Java Development With Spring, Hibernate
and Eclipse》一书。
问题
Standish Group是一家积极开展软件开发项目失败原因研究的组织。该组织2000年度的CHAOS报告指出,此年内23%的软件项目以失败告终,49%受到质疑。1994年以来,该组织不断发布具有类似结论的报告。比如,1998年的报告就显示了类似的结论:28%的开发项目以失败告终,46%的项目受到质疑。由Standish
Group发布的另外一组关于应用程序内置功能使用情况的统计数据更让人震惊。该报告认为,在应用程序的功能中,有45%用户从未使用,19%很少使用,16%偶尔使用,13%经常使用,只有7%始终使用。这些数据表明,开发人员构建的大部分功能用户从未使用,这不免让人觉得匪夷所思。
尽管这只是一家之言,但它的确与我20年的信息技术职业生涯的所见所闻相符。既然BRUF和BDUF存在一些问题,我们现在就来探讨一下潜在的解决方案。
解决方案
Standish Group还提出了十大成功因素,称为CHAOS Ten。其中的一些主要因素包括管理层的支持、用户的参与、富有经验的项目经理、明确的业务目标和最小化的范围。我所经历过的被取消、被质疑并/或失败的项目也完全印证了这四大成功因素的重要性。
2001年,17位软件开发方法学家齐聚一堂,将各自的开发方法学进行了汇总,并共同定义了术语敏捷(Agile)。会议最终制定了Manifesto
for Agile Software Development(敏捷软件开发宣言),并确立了一系列敏捷开发方法的价值观念和原则。术语敏捷涵盖了众多开发方法,其中包括Extreme
Programming (极限编程,XP)、Scrum、Feature Driven Development(特性驱动软件开发,FDD)、Agile
Modeling(敏捷建模)以及Crystal等等。由于流程和建模常常互为补充,因此许多软件开发方法学同时包含这二者。
由于敏捷方法遵循一套共同的原则和价值观念,因此该方法不言自明的优点便是用户可拥有各种技术选择,并可按用户环境定制所选技术。本文将在使用极限编程(XP)和敏捷模型驱动开发(Agile
Model Driven Development,AMDD)进行企业应用程序开发时,采取这样的做法。XP提供了完整的软件开发生命周期,而AMDD则提供建模原则。然而,由于XP整个生命周期流程的社会性超出了本文的范围,因此本文将更关注于AMDD而非XP。
使用XP进行软件开发
XP由Kent Beck、Ward Cunningham和Ron Jeffries共同开发,是有纪律并流线化的完整生命周期开发流程。由于XP的方面书籍颇多,因此我只概括说明我对该方法的理解。
XP项目通常先由用户以几项到几十项user story的形式提出成功开发的需求。user story是客户(终端用户、业务分析师或其他项目涉众)用一到三个句子列出的功能需求。此后客户为其指定优先顺序,并将user
story分为一个版本计划中的不同迭代,并优先开发优先级较高的user story。每一次迭代结束后,向客户发布该迭代中实现的user
story的生产就绪代码(也就是说,通过了可接受性测试)。图1为XP生命周期简图。
图1.XP生命周期简图
敏捷方法的共同特征是更短、更频繁的软件开发项目周期。就XP而言,这包括以下方面:
更短的发布时间(比如两到三个月)
更短的迭代周期(比如一到三周)
更短的编译时间(比如十分钟)
更频繁的整合,每天一到数次,甚至在每次代码签入(check in)后不断自动整合。
XP的其他重要方面还包括让开发团队(开发人员、测试人员、项目经理)和客户或其代表同在开发现场。这样做的目的是为了便于交流,而交流正是XP项目成功的关键。
XP也强调简洁。比如,Kent Beck在其《Extreme Programming Explained》(第2版)(中文译名:《解析极限编程》)一书中问道:“可以运行的最简单程序是什么样的?”就软件应用程序的设计而言,这一原则体现在增量设计形式上。Scott
W. Ambler (敏捷建模大师)也喜欢称其为即时设计(Just-in-time Design)。其理念是先完成整体架构和前端设计,把细节设计留到需要时(如迭代周期中)进行。
限于篇幅,本文并未涉及XP其他诸多方面内容,比如结对编程(pair programming ),稳定的开发进度,以及代码集体所有权等问题。此外,有必要指出,XP并不是一种要全部接受或全部拒绝的方法。换句话说,不用在项目中全盘采纳XP的所有做法。比如,Mike
Cohn(由Addison-Wesley出版的《User Stories Applied》一书的作者)近期在一封邮件写到:“我鼓励开发团队从Scrum入手,随后要‘发明XP’,意思是希望他们能找到适合自己环境的XP实践。”简而言之,如果您有兴趣使用XP,我鼓励您通过相关书籍或网站对XP进行研究,这些网站包括extremeprogramming.org、xprogramming.com以及xp123.com。
接下来,我们来看看建模技术。
使用AMDD指导建模
thefreedictionary.com将模型(model)定义为“初期作品或结构,
作为开发成品的计划……用于测试或完善成品。”
由于模型与下文谈及的模型驱动开发(model driven development,
MDD)密切相关,因此在本文中,我将广义地使用模型这一说法,而避免使用诸如图表(diagram)和/或工件(artifact)这些词汇。
Scott W. Ambler创立的敏捷建模(Agile Modeling)包括一整套敏捷方法建模原则、价值观和实践。作为敏捷建模的子集,AMDD为模型驱动开发提供了行之有效的(敏捷)做法。MDD的一个示例是Object
Management Group(OMG)的模型驱动架构(Model Driven Architecture,MDA)。AMDD建议构建“足够好”的模型,而不是全面模型。AMDD提倡在两个层面上建模:初期建模(比如在开始进行XP风格开发之前)和模型头脑风暴(比如在迭代周期内即兴设计讨论时)。
初期建模活动通常包括需求和与架构相关的建模。例如,需求建模可能包括使用模型,比如user story和域模型;以及用户界面(UI)模型,如UI原型和故事板(也称为UI流程图)。架构建模可包括高层体系结构图,以及对扩展性、可靠性、安全性等问题的初期讨论。通过这种方式构建的模型级别更高,本质上更为概念化,并会对所发布的整个应用程序产生深刻影响,因此我将此类模型称为发布级模型(release-level
model)。在每个迭代周期中,模型拥有更多细节,本质上也更为实用。此类模型包括CRC卡片、UML类图表等,这些也被视为迭代级模型。图2展示了一些使用极限编程风格的AMDD时可用的模型选项。
图2.发布级和迭代级模型选项
实际上,这差不多已经是AMDD全部的模型了,因此下文将通过对发布级和迭代级模型的研究,探讨实践中运用AMDD建模的方式。首先我们将定义一个可以用于演示示例的示例应用程序。假设一个虚构组织希望构建工作时间记录系统来管理员工工作时间。首先,客户可先进行问题描述:
问题描述:目前,我们的员工通过书面的时间表提交每周工作时间,这种方式耗费了大量精力,同时容易出错。我们需要开发自动化的解决方案,让员工以电子时间表的形式提交工作时间,公司对其进行批准,并对其支付酬劳。此外,我们希望能实现时间表状态变化自动通知以及每周提醒提交和批准员工工作时间表的功能。
接下来,我们对应用程序命名。“Time Expression”似乎是一个易记的名字,那就定为这个名字。现在,我们准备着手开始发布级建模。
发布级模型
在一个特定发布(如季度性发布)开始之初,确定项目的范围至关重要。各方应就开发范围内容达成一致,范围简表(如表1所示)可轻松完成这一任务。
范围 功能
包括 Time Expression将提供输入、批准、支付员工工时的功能。
延期 Time Expression可计算薪水扣除额,比如联邦/州政府税和医疗费用。
延期 Time Expression可跟踪记录休假或病假。
表1.范围例表
接下来,根据所开发应用程序的性质和规模,开始着手构建域模型或UI原型。若应用程序无UI,则无需构建UI原型。此外,开发先后顺序还取决于公司排定的任务优先级。比如,若公司更重视域模型,则可优先构建域模型。然而,其他公司发现,在UI原型上与用户进行合作,更易于发现域对象。
域模型有助于确定主业务概念(实体)及其相互关系,如图3所示。
图3.域模型示例
作为屏幕界面初期模型,用户界面原型和故事板有助于了解客户对应用程序外观的想法。图4展示了Enter Hours屏幕界面原型示例。图5中的故事板则显示了屏幕界面流程图。
图4.Enter Hours-UI原型示例
图5.故事板示例(也称为UI流程图)
我们希望在发布级定义的另一个模型是类似于图6中所示的高层体系结构图。该图应为迭代周期具体设计提供足够的细节。高层体系结构图有助于对安全性、可扩展性、事务管理、异常处理以及其他重要的应用级问题进行讨论。
图6.高层体系结构示例
此外,发布级还需对术语表(项目中可能用到的通用业务、技术词汇列表)进行定义。这对共同理解专业术语至关重要。比如,我们的示例应用程序或许就包括period
ending date(周期结束日期)、pending status(挂起状态)这样的术语。在XP领域中,初期发布计划(本质上为项目计划)的定义也在此处进行。
迭代级模型
到目前为止,我们已经拥有了足够的应用程序信息,可以开始第一个迭代周期。有时候,我们会对项目进行概念验证(proof-of-concept),如对UI和应用程序数据库的双向连接进行验证。(在XP领域中,这种做法也被称为spike
solution,即一个探索潜在解决方案的简单程序。)由于此次迭代并未交付客户需求的功能,所以此类做法(如概念验证)可视为迭代0的一部分。
面向对象开发的主要任务是对象设计和编码。在XP领域中,团队中的开发人员可通过CRC卡片寻找对象。这种寻找对象的方法也可用于定义类和XP中称为系统隐喻的方法命名约束。我们在开始寻找对象之前,先看看到目前为止,我们对示例应用程序有什么了解。比如,我们已经通过域模型对域对象有所了解,我们的架构设计模式为模型-视图-控制器(Model-View-Controller,MVC),我们通过UI原型对UI界面有所了解,此外我们应该还拥有了一些user
story(可能对每个user story使用简短的标签或名称)。有了这些准备,现在我们可以开始命名对象。因此,如欲开发Enter
Hours界面(图4),可创建名为EnterHoursController的类,该类可依次调用名为TimesheetManager的服务(或模型)对象。TimesheetManager类依次请求Timesheet域对象,如图7所示。
图7.CRC卡片示例
一旦使用CRC卡片确定了基本对象,便可使用应用程序流程图来展示端到端用户功能流程。图8为一个应用程序流程图示例;请留意我们是如何看到MVC架构的所有组件的。此类模型的另一优点是,可通过向受到应用程序各部分影响的数据库表格添加列的方式,在项目内轻松实现扩展。比如,我们可添加4个CRUD(创建、读取、更新、删除)列,显示哪些数据库表格受到影响以及受影响的方式。
图8.应用程序流程图
CRC卡片和自制应用程序流程图适用于某些项目,而对于其他项目而言,UML类图表也许是更好的选择,您也许会和其他开发人员一样,更乐于使用此类技术。对于后者而言,类图或包图可用于替代或补充CRC卡片和/或应用程序流程图。图9和图10展示了示例应用程序的类图和包图。
图9.UML类图
图10.UML包图
XP的另外一个重要内容是可接受性测试。user story在发布级充当高层需求,而可接受性测试以及用户临时问答会话在迭代级充当具体需求。可接受性测试也用于编写单元测试。比如,示例应用程序可接受性测试可包括“所输入的每日最大工作时数不超过24”这一条件。
整体测试
如果您听到过XP程序员只需编写代码而无需设计这样的说法,那么读完本文后,您一定会发现这种说法其实非常荒谬。此外,XP开发人员会考虑每天重构设计,因为这样可以不断改进代码。为了进一步阐明我的观点,图11展示了我们在发布级和迭代级构建的各种模型,从另外一个角度来看,这些模型也可视为概念性和现实性模型。
图11.模型的结合
下一步任务很有可能是创建具体数据库,当然还包括编写代码!
在我看来,数据库和代码基址是长期工件,并可轻松地对模型实施逆向工程。一旦实现了数据库和代码,此前构建的所有模型均可“丢弃”。我这样说是因为我参与过的大多数项目根本无法对设计和需求文档进行维护,因此保留文档有何意义?当然,有朝一日,OMG直接从模型到可执行程序的梦想(不管有无中间生成代码步骤)或许会得以实现。如果这一天真的到来,那就太好了,因为模型将有效取代目前编写的代码,同时也不必对模型和代码进行同步。
敏捷方法与传统方法
在BRUF/BDUF风格的项目中,需求和/或设计文档常常是项目的初期目标。而敏捷项目通常不是这样。因此,您也许已经注意到,本文中所探讨的流程和建模技术并不需要诸多形式上的具体要求或前端设计。
就需求而言,使用XP进行开发时,我们先以简单user story的形式,提出功能需求总体想法,开始发布级规划。在应用程序迭代周期内,可接受性测试充当具体需求,细节问题也在迭代级得到解决。在BRUF风格项目中,这些问题均以具体用例的形式在前端解决,用例包含前置条件、后置条件、成功路径、失败路径、业务规则等等。因此,BRUF风格项目最后常常列出厚厚一本要求,而项目涉众几乎不会通读全文。
就敏捷开发技术或设计而言,我们可以通过使用非正式的高层体系结构来了解开发中的企业应用程序,这也足以让我们完成前几个迭代周期。换句话说,由于发布过程中实际数据库和项目关系不断变化,因此我们不会在实际数据库设计或详细项目关系表创建上投入大量的时间。此外,敏捷方法还包括了不断改进应用程序设计的重构技术。这样做的原因是,只有在完成一定的编码后,我们才能对架构和设计的诸多层面进行清仓并/或验证。在DBUF风格项目中,架构设计通常在开始编写代码之前完成。
结束语
我刚刚谈到了如何使用XP和AMDD这样的敏捷方法开发企业应用程序。这些技术并不是尖端或完全原创的方法,而是建立在多年来已被证实有用或无用的经验之上。但是,这些技术的确整合了一些灵活编程方法,能帮助您快速适应,接受组织、项目和涉众需求的变化。我建议仅将这些技术作为指导,因为一旦流程、模型或文件成为开发目标,您就会忽视真正的重点:为其进行应用程序开发的目标客户。
参考文献
访问Agile Manifesto、Agile Modeling、Extreme Programming、Refactoring和Agile
Draw 的主页。
A Laboratory For Teaching Object-Oriented Thinking提供CRC卡片简介(来自于OOPSLA’89会议)。
本文内容基于《Agile Java Development with Spring, Hibernate
and Spring》一书。
Comparison of Diagramming Methods
敏捷宣言背后的故事
Standish Group
VisualPatterns.com XP和AMDD相关漫画
附录:Agile Draw注释
您也许已经注意到了,本文中使用的许多模型都使用了free-form技术,这并非偶然。这种技术是所谓的Agile
Draw的一部分。作为一项新技术,Agile Draw得到众多著作者(包括我)和其他众多业内人士的支持。该技术实际上没有标记符号,高度简化建模过程,在概念层上尤其如此。Agile
Draw的理念是,使用最简单的工具,尽可能减少标记符号。比如,只使用三种主要图形:圆圈、方框和线条。强调模型所传达的对象,也就是概念和内容;以及传达方式,比如表示符号和工具。此外,Agile
Draw还可以指导对模型进一步修改。如有必要,可通过改变色彩、添加阴影、增加标注等方式,使模型更加好看。
|