Visual Studio Team Architect 团队的敏捷软件开发
 
2009-04-10 作者:Ramesh Rajagopal 翻译:郑洁 朱永泰 来源:msdn.com
 

在最近几次与客户面对面的交流中,我有幸分享了我们团队如何在日常工作中进行敏捷软件开发。毫无疑问,这在中国开发人员中是个热门话题,我也想利用博客这个平台与更多的读者进行书面的交流。当然关于敏捷开发利弊得失的争论有不少,而相关的开发模式也分成了TDD (Test Driven Development), Scrum, XP(eXtreme Programming)等流派。就我个人而言,一个团队是否严格遵循某种既定的敏捷方法并不重要,但一定得选择并采用一种(或几种)最适合自己开发团队和开发项目的。我认为重要的是团队能否遵循《敏捷软件开发宣言》所涉及的12条原则。

在我深入这一议题前,请允许我介绍一下团队:我们属于微软开发工具部(Developer Division,以下简称DevDiv),这个部门拥有几千名软件工程师,核心产品Visual Studio系列的用户从软件开发爱好者一直到大型企业里的专业开发人员及架构师。

大量而且复杂的依赖关系、代码改动、紧迫的开发周期等因素使管理软件开发生命周期并按时发布高质量的Visual Studio产品极具挑战性。为了降低风险和复杂度,DevDiv在开发Visual Studio 2008过程中采用了功能分支架构(Feature Branch Structure)和功能小组模型(Feature Crew Model)。其实这一方式之前已在Office开发团队的实践中取得不错的效果。它的最大好处之一就是使负责某个功能的团队在独立开发过程中有更大自由。由于篇幅所限,在这篇博文中我将侧重介绍我们团队是如何进行敏捷软件开发的。

我们团队负责Visual Studio系列中的Visual Studio Team System Architecture Edition,帮助架构师、运营经理及开发人员以可视化方式构造面向服务的解决方案、降低(软件产品开发的)复杂度。目前我们已开发了基于UML和DSL几个建模工具。这基本上是一个全新项目。

从产品开发来看,我们属于全球分布式开发,团队分布在三大洲的四个城市,包括亚洲的上海,北美洲的雷德蒙和夏威夷,以及欧洲的剑桥。为了尽可能减少分布式研发对团队间交流所造成的障碍,我们尽量使功能小组的成员集中于一地。基本上,每个功能小组的核心部分都在某一个城市完成,在其他城市可能会有个别工程师参与相关开发。例如,我们在上海就有一个功能小组,其他一些工程师在雷德蒙的公司总部工作。但有时,基于客户场景的特殊要求,我们也会将一个功能小组拆分成若干个,由多个城市的团队同时开发。

在本文后半部分和之后的系列文章中,我所谈及得敏捷软件开发流程都是同一个功能小组所遵循的,即是我们中国团队所遵循的。

我们中国团队主要负责开发基于UML的核心图形设计工具,包括即将发布的Logical Class Designer, Use Case Designer。此外,我们还负责在项目中提供建模元素视图功能的Model Explorer。我们所采用的敏捷开发方法是Scrum的修改版。就如我之前提到的,我们认为敏捷开发方法和技术没有哪一种是万灵丹,适合自己才是最好的。我们的团队中已有两位工程师参与过Scrum实践,也因此促成我们最终选择了它。

下面是一个我们敏捷软件开发流程的概要视图:

产品待开发事项(Product Backlog,视图的左上角)可以被视作一份这个团队以优先级排列的、需要完成的功能需求单:来自相关产品利益相关者(Stakeholders)对产品提出一系列高端要求。例如,我们最初的要求是为客户增加逻辑级(更抽象的)和物理级(更靠近代码)建模提供支持,由此衍生出了高端功能需求,诸如开发在逻辑级方便客户生成逻辑模型、兼容UML的关系图和开发帮助创建无力模型的DSL关系等。然后我们会对将要支持的UML关系图种类按优先级进一步分解(UML共有13种不同的关系图)。产品利益相关者的意见会驱动整个优先级选择过程,最终我们得出五个最重要的关系图:Logical Class Diagrams, Use Case Diagrams, Sequence Diagrams, Activity Diagrams 和Component Diagrams。于是,团队依据当时对产品和市场的了解,以故事标题的形式完成一份产品待开发事项。无疑,整个开发工程中一旦要求发生变化,也会导致需求排列优先级的变更。

在与客户的交流中,我被问得最多的问题之一是是否需要在敏捷开发过程中创建架构模型设计。和咨询公司一样,我的答复也是:视情况而定:)。围绕Big Design Upfront (BDUF), You Are Not Going to Need It (YAGNI)以及让团队在开始实施新功能时“重构”现有的代码/设计等所存在陷阱的争论也不少,其中有不少值得借鉴。尽管如此,我坚信设计初期存在这么一个阶段可以尽责地做架构设计以生成高端架构。例如,你打算建一个网上贷款流程的应用程序,你可能需要决定在这个架构里有几层。当然,能有这样一个基于最初要求的,并可能随着项目进展有所变更的架构是很重要的。在我看来,重构在敏捷开发中有其重要地位,但是如果是变更基础架构的“大重构”代价就太大了。如果大家感兴趣,我将在之后的文章中与大家探讨架构在敏捷软件开发过程中所扮演的角色。

在我们团队所遵循的敏捷软件开发实践过程中,我们的项目被分解成类似Scrum的若干个四周sprints或迭代开发周期。尽管没有测试驱动开发(Test Driven Development)或结对编程(Pair Programming),但我们的开发人员会编写单元或签入测试(Unit/Check-in Test)来检查功能,开发和测试工程师也会在一起调试、调查或评审某个特定问题和变更等。我们还会使用极限编程(eXtreme Programming)中的使用者故事(User Story)模式。事实上,我们的产品待开发事项和每个迭代周期中的待开发事项(Sprint Backlog)都会以故事的形式被追溯。这些使用者故事就是描述一个系统的最终用户会如何使用某个特定功能。

通常,我们都会在一个Sprint阶段的最后一周计划下一个Sprint阶段:通常负责某个功能的团队(主要是主管们)会依据团队需要侧重的故事来进行由下至上的计划;然后再与产品利益相关者对项目中故事优先级的规划相协调;协调后的需求优先级清单一般会在Sprint的第一天完成。团队于是评估这些使用者故事,并完成设计初稿、实施成本,确认故事完成的标志。依据这个设计和成本,团队将承诺这个Sprint将完成的内容。

十分感谢你们通过博客或者私下里给我的反馈。我希望在这篇博文中回答一些你们提出的问题。同时,为了延续整个系列的行文思路,我也会涉及一些我们团队计划sprint的方法以及sprint过程中发生的事情,并穿插着回答你们提出的那些问题。

首先,我想说的是,不存在敏捷无需计划的神话。可是,敏捷开发中的计划的确和传统软件开发中的计划有着很大区别。正如我在上一篇博文中所说,我们针对利益攸关方(stakeholders)给出的上层需求创建了带有优先级的产品待开发事项(product backlog)。这一带有优先级的任务列表形成了最基本的sprint计划。在这一过程中,我们一般遵循三阶段的步骤:在主管间进行的预计划阶段,所有团队成员都参加的计划阶段以及包含利益相关者的计划提交阶段。这里的关键是:计划是在所有成员的通力合作中进行,最重要的是由组员自发来制定标准、而不是依赖于某个项目经理。

预计划阶段在上一个sprint的最后一周进行,在这一阶段中,团队中分别带领项目经理,开发和测试的几位主管会聚集到一起讨论出在即将进行的下一个sprint中,需要开发的故事(story)列表。这个过程取决于很多因素,其中最重要的是:上一个sprint的进展情况,从利益相关者那里得到的反馈,需求或故事优先级发生的变化以及预计的团队速度。项目经理(有时甚至是开发人员或者测试人员)在阐述故事的时候会尽量简短到只描述出目标、故事的简单介绍以及故事的具体流程。我们发现OneNote很好的满足了我们这一需求(稍后会给出一个故事的截图)。

产品待开发事项总是列出对客户有价值的条目,同时它也可以增加这个团队要求的条目。但是,只有那些最终会给客户带去价值的条目才可以出现在待开发事项中。举例来说,创建并维护一个持续集成服务器以持续保证最终产品的质量,这样的条目被允许出现在待开发事项中的。

计划阶段通常在sprint的第一天进行。在开会前,项目经理会把OneNote页面的链接发送给组员,以便大家评估,并且为计划会议做好准备。通常,组员会在OneNote页面中交换意见,从而在会议之前澄清那些不明了的地方。在计划会议当天,团队组员会聚集到一起,过一下所有的故事,解决之前发现的任何问题,把故事进一步细分成一些任务,并描述每个故事的验收测试。组员同时也会对完成这些故事所需要的时间做一个大致的估计,然后根据这些估计决定在这个sprint中,团队可以完成哪些故事。

计划提交阶段在之后的一天进行,主管会再度聚集在一起并且向利益相关者介绍团队承诺完成的任务。此时,利益相关者可以提出建议对优先级进行调整。比如,如果团队成员可以完成故事A,B以及C,但是不能完成D和E,利益相关者可以建议团队在这一个sprint中完成A,B,D以及E(假设D和E消耗的总时间和C相同)。然后,项目经理会把这些故事输入用来管理我们项目的Visual Studio Team Foundation Server。

注:我们花了好几个sprint来学习并总结出以上这个计划流程。这就是sprint回顾(我会在以后的博文中提及)发挥的重要作用。

现在,让我来回顾一些针对我上一篇博文提出的问题:

在sprint中的变化以及干扰

有一位朋友提了这样一个问题,变化是敏捷方法的核心,那么团队应该如何应对sprint过程中发生的变化呢?诚然,快速有效的应对变化是所有敏捷方法的核心部分,然而,在sprint过程中的干扰始终对生产力有着不良影响。在我们的团队中,我们总是尽量避免sprint过程中的干扰,把变化延缓到下一个sprint中。因为我们把sprint的长度控制在4个星期,所以对于那些变化,意味着他们平均需要等待2个星期。:) 最起码,我们希望团队在应对变化之前,先完成那些计划了的故事。这一策略当然需要利益相关者的支持,并且在之前就达成一致。干扰对团队的影响很容易观察到,方法之一就是留意团队速度的下降。(比如在燃尽图上看到曲线的变化)

代码重构:

另一个问题是该怎样应对因需求改变导致的重构现有代码。当研究一个新的设计时,重构是有效的方法;当代码量不大时,重构也不是一个大问题。然而,一旦你的代码量开始变大,重构的代价就会变得很昂贵。由于利益相关者的反馈和需求的变化,我们也曾有相当一部分代码需要重构。 在考量代码重构问题时,最重要的依据是重构对于产品和团队的影响。

举一个例子,我们曾不得不改变当一个图形被拖动到另一个图形内部时的产品行为。因为在最初设计这一行为的时候,我们的信息不够充分。在初期的实现之后,我们注意到有一些人已经对这一行为记录了bug,因为他们认为产品的表现和他们的预期不同。我们针对这一情况采取了下列的方法:1)收集更多的反馈以明确预期的行为;2)提供了一个穿刺(spike)方案(译者注:Spike指在产品线的外部开发的试探性的原型系统),调整了产品的行为;3)对穿刺方案进行代码复查和“伙伴测试”确保解决问题。(译者注:伙伴测试指找产品组成员帮忙适用产品的新功能,以查找问题)4)对已发生的变化撰写单元测试。

另外,我需要指出的是,在任何的重构过程中,自动化测试的好处都不会被过分夸大。它能够确保正在进行的代码改变不会给产品的其他部分带来计划外的破坏。

架构与设计

尽管我们应该预期到设计和实施中会有变化发生,然而,就如我之前提及的,当代码量增大时,对代码的改变和重构的代价呈非线性的增长。面对这个问题,预先进行一定程度的架构与设计就带来了好处。这里的架构与设计并不需要非常具体化,其目的是能够刚好鉴定出在之后的实施中可能面对的主要问题。当然,说起来容易做起来难J。在项目的初期,当上层的需求齐备了,也有一个初步的产品待开发事项列表时,就可以开始进行上层架构了。尽管这可以通过纸笔或者任何建模工具来完成(我们希望在Dev10发布之后,你们会用Visual Studio Team Architect完成这项任务),你将会需要开发一个原型来支持你的设计与架构。我们发现这一步骤对项目的成功非常有帮助。对有一定复杂度的项目,你可以通过这个方法来确定应使用的技术,明确依赖关系等等。对团队来说,这也是对其各自的自动化框架加强建设的好时机。

OK,我已经讲了很多形而上学的东西。下面让我展示一些截图,把我们团队在sprint计划阶段进行的工作映对到我在前文中所讲述的方法原则。

下面的这些截图展示了我们团队在sprint计划以后讨论出的故事列表。 同时,你也会注意到一些不同的团队成员留下的评论。其中的交付编号是在TFS中对应的标识号码。

一个用户故事从用户角度描述了一个需求功能点。一个好的用户故事包括需求功能的描述,谁需要它,怎么使用它,为什么需要它。

Spint计划中的重要一环是让团队对“完成”的定义达成共识。在我们对“完成”的定义中,编写并且运行通过验收测试是重要内容之一。验收测试是在软件交付之前进行的黑盒测试。在我们的语境中,它意味着用户故事的核心内容实现得如同预期的那样。

一个验收测试应该满足两个条件:1)产品的拥有者应该能够根据它鉴定用户故事已经被实现。2)开发人员应该能够根据它检验他们是否已经开发出了预期的功能。我们不开发那些不能被检验的功能。

下面是我们所创建一个典型用户故事的具体组成部分:

接下来,你会看到一个示例故事以及基于这个故事展开的讨论。<作者注:为了节省空间,以及展示团队成员间的合作,在复核阶段对问题展开的讨论,我做了手工编辑并把他们合并在了一起。〉最重要的是对故事的讨论是团队在动手实施之前的协作,团队在那一时刻已经达成了一致。在这里,我们把对质量的要求往上流推进到很早期的阶段,甚至在团队动手开始写任何一行代码之前,我们已经开始为产品质量作了努力。事实证明,这一办法在之后节省了我们很多的时间精力。如下图所示,团队讨论并解决了关于可用性,可实施性以及可测试性的问题。

这篇博文中,我已闲庭信步于sprint计划阶段,不多言了。


火龙果软件/UML软件工程组织致力于提高您的软件工程实践能力,我们不断地吸取业界的宝贵经验,向您提供经过数百家企业验证的有效的工程技术实践经验,同时关注最新的理论进展,帮助您“领跑您所在行业的软件世界”。
资源网站: UML软件工程组织