UML软件工程组织

软件开发项目取得成功的策略:一种个人的观点
Goran Begic, Senior IT Specialist, IBM

 来自 Rational Edge:一位经验丰富的软件开发专业人员提出了一份他个人的建议,并且描绘了一幅通过改进和提高开发过程从而使项目获得成功的良好习惯,它涉及到交流沟通、用例、测试和市场营销等方面。

 在过去两年中,无论是从事内部的还是外部的软件开发项目,我都会遇到这样或那样的挑战,同样也会发现一些在不同项目中都普遍适用的良好习惯。既然我懂得了如何利用这些习惯来克服困难,于是我决定将其作一些梳理并记录下来,作为本文的提要。

 这些笔记可以归纳为如下四条策略:

弥补缺乏面对面交流所带来的不便
 撰写更好的用例
 确保有效的测试
 支持市场工作

 这项别具风格的建议决不是包罗万象。我的目的并不是教授您如何构造软件,而是和您探讨一些对于项目成功与否至关重要的技术或非技术性的问题。有时,一个好项目和一个堪称经典的项目之间的差异就是由一些看起来无关紧要的因素造成的。我的建议所着眼的就是那些相对较小却很关键的部分,它们可以作为整个工程的代表。

弥补缺乏面对面交流所带来的不便

 人人都知道项目成功最关键的因素就是良好的交流与沟通。这是一个相当大的题目,在此我仅就其中一个确实能使项目之间产生出好与坏差别的方面加以论述。

面对面交流的好处

 整个团队能够在同处在一个地区是一件非常值得庆幸的事情。通常这种情况会发生在那些小规模的、刚刚起步的业务身上。几个理想坚定、雄心勃勃的人为共同的目标而奋斗,一同体验和经历着每一天中同样的细节。同样,一些更大规模的组织有效的使用灵活的方法在面对面交流的基础上建立它们的内部流程。当某一个团队同处在一座建筑物内时,其成员能够在午餐时、走廊内、下班后进行面对面的交流,这些非正式的会面通常比安排好日程的会议更具效率。我至今仍记得无数次这样的情形:当我在一个长时间的讨论之后从被写的满满当当的白板上面抄录下笔记之后,正是这些被大家分享观点和想法成为了新的方案的基础。

 然而,业务的成功和事业的发展通常会使得将一个高水准的团队固定在同一个地点变得越来越不现实。由于并购、合作项目以及外包开发的出现,要求我们能够在不同时区、不同文化之间成功地进行交流和沟通。在这样一种情况下,什么才是我们最好的选择呢?

分布式环境下的交流的开展

 第一个映入我们脑海的答案大概就是电子邮件了。我曾经觉得电子邮件确实是一种有效的沟通渠道,但它同时也是被滥用最甚的一种渠道。如果电子邮件的传送距离过长以至于人们没有时间去阅读它们,那还有什么用呢?根据我的经验,如果包含三条以上的信息,那么您就应当转而使用电话进行交流了。这个小小的规则帮助我节省了大量的时间,使得我不必去撰写那些关于Lotus Notes软件的无意义的文本。

 此外,还有其他的一些沟通渠道,尽管它们并不能够取代面对面会议的亲密性,但它们确实能够提高一个团队的合作能力和理解能力:

 项目主页。 在网络上建立一个主页,从而为项目领导者提供了一个极好的单向交流渠道(如果您使用wikis技术或者论坛/博客方式的话,也可以是双向的交流渠道)。主页上可以解释项目的具体内容是什么,确定所要达到的主要目标,以及介绍团队的成员。管理者同样可以应用这一页面来发布代码标准,“如何做”将帮助团队成员设置环境,凡此种种。


 在线聊天。 这种交流形式在团队成员之间创建了一个虚拟的合作环境,营造了一种轻松的交流思想的气氛。显然的,通过即时消息系统随时向同事寻求帮助要比通过电话交流要有效率的多。例如,IBM的系统,Lotus Notes SameTime系统,与Lotus Notes地址录结合在一起,因此您可以轻易地在您的组织内部找到正确的连接,并且看到那个人是否已经登录到SameTime。如果您看到指示器显示“忙”,您就可以判断出此人同样也没有时间接听您的电话。SameTime同样允许您邀请多人一同聊天,因此说这是一种进行合作讨论并且立刻做出决定的非常好的方法,并且它省去了为进行一次正式会议而作的准备。

 一些聊天程序还包括了其他一些有意思的功能,比如个性化可用性消息,为将来之用而保存副本的功能,等等。我之所以加亮了IBM SameTime是因为它提供了许多由于其与Lotus Notes电子邮件系统相结合而产生的附加功能。请记住,不同的聊天工具提供不同等级的安全性,并不是所有的聊天工具都能很好的适用于职业应用的。


 缺陷跟踪系统。 这是另外一种有效的沟通渠道。每一个软件开发项目都必须能够处理功能增进的需求以及程序缺陷报告。一个有效的缺陷跟踪系统,例如IBM Rational ClearQuest,能够帮助开发团队规范化这些需求和报告。特别地,通过Rational ClearQuest和IBM Rational ClearCase结合而获得的统一变化管理(UCM)的能力,将允许您将缺陷记录和源代码联系起来,这将大大提高在日常事务上的交流质量。例如,如果对于一个不能正常工作的组件我需要得到帮助,我就可以找到该组件在缺陷跟踪数据库中的入口,并且查明该组件是否在执行进一步的工作,以及谁在执行那项工作。


 “一杯咖啡。” 从另一个方面来说,每一种交流的工具都是人。当有人打电话给你仅仅是问候一下您最近在忙什么,特别是在您处在工作压力下的时候,难道这不是一件非常令人感到欣慰的事情么?尽管您的同事可能正处在地球的另一端,记得这些非正式的交谈对于巩固一个团队发挥着多么巨大的作用仍然是非常重要的。即使您使用的是最完善的管理和报告工具,有些时候与另一个人的交谈仍然是获得正确信息的唯一的方法。邀请您远方的同时共饮一杯咖啡如何?也许一个没有事先安排的电话会在一天工作结束之前的一小段时间内打来。请记住,如果您起初经常拨出这样的电话,那么您也将接到更多这样的电话。

回页首

撰写更好的用例

 从某个角度来看,我们可以认为用例也是交流沟通的一种形式。但是,它却远远不仅仅如此,所以我在这里将其单独处理。

 用例较之于其他系统设计技术有两个大的优点。首先,它们为每一个参与项目的人员提供了一个关于最终的用户需求的正确理解。其次,您可以在源代码的第一个原型出来的很长一段时间之前就对这些用例进行装配。弄清楚应用程序的关键原理以及用户的真正需求,一方面为今后同客户开展富有成效的合作开启了大门,另一方面也为在产品合成过程中不同角色和团队之间的合作奠定了基础。

 简单的说,用例就是描述下列两件事情之一的一个简单的文档:

 用户要求必须事先的关键功能(业务用例). 或者 用户(活动者)与业务系统之间的交互(系统用例)。

 也许您在想:“所以什么?那仅仅是另一个文档。”实际上,当我第一次面对要将需求和用户的期望写进文档之中,使之可以被不同的项目角色共享这一挑战之前,我也抱有同样的想法。在项目最初的阶段里,测试团队和文档团队就开始向我们询问一些关于我们将做什么以及各部分之间将如何协同工作等等细节。直到我发现用例之前,我的回答总是矛盾的、混乱的和非常耗费时间的。

 当然,一旦我发现使用用例来计划和回答这些问题是多么的有效,我便面临着另外一项挑战:学习如何更加有效的撰写用例。

了解用户

 在进入交互和特定情节之前,理解所有目标客户群并将其彼此区分开来,并且把他们的要求和需要列入清单是非常重要的。不同的用户群有着不同的业务用例。例如,一位负责确认遵循一套特定的全球性标准的测试人员的需求就在很多方面不同于一位拥有相似职责的开发者。开发者也许拥有知识、工具以及职权来修补那些错误的地方,但是测试者则是记录下这些缺陷然后等待开发者来作出改正。

 在设计应用程序时,除非您弄清了这两类用户的特定需要,否则您就有可能设计出一个两方面需求都不能得到满足的系统。

业务用例与系统用例

 取决于被讨论系统的不同,在业务用例和系统用例之间可能存在着巨大的差异。一个是描述用户的业务,而另一个描述的是用户同系统的交互活动。然而,这两种类型的用例之间的区别也可以变得模糊。例如,在一个软件开发项目中,系统就是业务。当您开发和测试一个特定的系统功能的时候,很容易就会忘记最终的用户很可能不会用您所采用的方法使用该系统,甚至都不会拥有同样的需要。

 为了理解业务用例和系统用例之间的区别,想象一下软件开发团队已经承担了一项软件应用程序开发任务,并且要保证其在全球各种不同地区的环境下都可以同样出色的运作。为了确保该应用程序达到这些要求,该团队就必须遵循一套最小化的全球规则。1 这些规则在一套规范中被严格定义,不能随意被更改。开发团队需要针对这些规则来审核自己的代码,目前这些工作必须由手工来完成。一位程序师(审核员)必须打开源文件来查找同指定规则相矛盾的地方。

 该组织收到一份执行决定,要建造一种能够使这些全球性规则(及其他规范)得到自动分析的工具,并且集合一支团队来开展这一项目。目标就是将业务用例中手工操作的那部分替换为软件应用程序(即系统)。这一手工过程非常耗费时间且容易出现错误。并不是所有的程序师都能够同样好的理解这一全球性的规则,许多人很可能没有注意到这之间存在的矛盾之处。另外,团队成员在持续的工作压力下变得越来越快的生产产品。一个可以核查全球化规则的自动化的系统将降低忽视某条规范的风险,并节省大量的时间。

 在这个特定情节中,业务用例“在核查之前复审每一份源文件”可以被看作:

 对于工作区内的每一份源文件:

打开源文件。
 逐行阅读代码(注:需要深入的代码知识)。
 如果您发现了一个可以的方法,就请参考包含这一规则的网页(注:非常耗费时间)。
 如果可能的话,通过修改代码解决该问题(对于开发者的业务用例)。
 对于测试者来说可选的流程:如果您不能正确地解决这个问题,就请将发现的问题记录在Word文档中并提交给开发人员。
 打开下一份源文件并重复上面的步骤。
 正如您所看到的,这是一套冗长的流程,但却是实现自动控制的一个非常好的候选方案。

系统用例的价值

 一旦您定义了用户的“就是这样”的流程和目标,您就能够指定那些用户活动的部分是一个自动控制的系统所能提供的。尽管它们仍然包含着用户的活动,系统用例却是以系统为中心的,来描述用户同系统交互的过程。然而,请注意系统用例应当在业务流程的背景下被定义。最终,我们的目标是帮助用户处理业务问题。

 这里就是在我们虚构的项目中,团队是如何定义基础系统用例的,假设用户就是团队的一个成员:

 前提:全球性的规则在IDE的复审特性的代码中被授权使用。
 在IDE中打开代码复审工具。
 (步骤之打开工具)。
 运行一个代码复审。
 主流程——点击按钮“Run”。
 (在新区域内列出可选流程的详细描述)。
 复审自动化复审的结果(发现的问题)。
 对于每一个发现的问题,解决之:
 主流程:提交缺陷。
 (在新区域内列出可选流程的详细描述)。
 如果您不能够修正这一代码,则提交缺陷。
 (步骤之缺陷提交)。

 一个包含以上这些步骤地简短的文档将提供充分的信息,使得读者了解到最终产品应该是什么样子,它将如何帮助客户处理他们的业务,等等。即使这一信息没有被明确的说清楚。

 下面是拥有系统用例而带来的一些显而易见的好处:

 即使没有一个代码被分类为“代码复审完毕,等待测试”,测试人员也能够针对上面描述的功能制定出一份测试方案。
另外,正是基于这一点,文档编写者可以针对代码复审创建并且(或者)添加文档中的结构。
开发管理者在此之后可以使开发进度更加优化,以便使得第一份开发构造将至少满足该用例的主要流程。
用例促进了项目的开发,并且使得全体团队成员在项目伊始就忙碌起来。如果您仍然没有将您的工作关注到用例上,那么请给它们一次机会。您所付出的努力将是值得的。

 确定系统用例适当的详细程度

 在每一个用例步骤中应该包含多少信息呢?

 我更偏爱于取得系统用例并将其根据业务用例分类,并且同样通过一组步骤将大量的用户交互活动分类。该组步骤解释了该步骤的目的,并且可以在某些细节在实现过程中改变的情况下保持不变。这种方法使得文档更加易懂,它将系统用例和业务用例联系起来,并且如果产品执行变化时它允许用例可以被容易的修正。

 例如,在上述系统用例中的简单的步骤“运行代码复审”中,向细心的读者传递了一个非常有价值的信息,包括:

代码复审被结合在IDE中。
 代码复审必须在使用中,或者“运行”。
 代码复审提供了一个关于违背某套有效性标准的问题清单。
 某些问题可以被迅速的修正。
 代码复审将获得迅速的修正。

回页首

确保有效的测试

 一旦用例被适当的设置并且开发团队就他们所扮演的角色达成共识,这些用例就成为方案中其他部分的基础。实际上,这是最好的利用它们所提供功能的方法。

 工程团队建造一个开发方案,其中至少要包括:一份将要被建造的组建的清单,以及每一个组建的时间期限。清楚的描绘主用例的特性需求和实际工作特性的组件必要性之间的关系是非常重要的。

 识别这些核心组件并且定义它们的用例是非常关键的步骤,它使得应用程序功能性的早期测试变成可能。如果该核心组件能够在开发周期的初期被完成,那么测试人员就能够开始为基本的规则集合撰写测试脚本并且确认该工具功能的有效性。

 在我们的例子中,系统用例“运行代码复审”使得测试人员能够为该核心功能制定能够测试计划,甚至可以在代码被编写出来之间就实现这一点。测试人员还可以为主流程和可选项目创建一套手工测试脚本。

测试类型

 最简单的测试形式,同时也是非常有效的一种测试形式,就是聚集一大批受过良好训练的用户来针对该应用程序的各种不同特性来进行测试和演练,并且将测试结果(发现的问题和缺陷)报告给代码开发团队。这种确认形式很简单:拥有越多的用户,就会检查出更多的缺陷。不同的用户群将用不同的方式使用该工具并且进一步增加被检查出来的问题的数量。然而,有一些与此相关的问题。直到该软件为用户使用做好准备的那一刻之前,我们都有可能没有足够的时间来开展广泛的测试计划了。不同的用户可能使用不同的产品。更重要的是,完全依靠人工是非常昂贵而且非常不可靠的。

 还有更多的事情需要考虑。如果没有一个清楚的测试计划,就不可能采取同样的测试方法来对不同版本的应用程序中的相同特性加以测试。如果没有测试工具的协助,对于每一次测试我们所采取的测试步骤将会大不相同。并且,我们将会疏漏一下很少用到的,但却是潜在的重要的情节。

手动测试和回归测试

 手动测试 是指以确定一个特定的系统相应为目标的一套动作。手动测试的另外一种选择就是自动测试。两者都属于功能测试的类型.自动测试意味着您使用一个专门的工具或者一批脚本来对一套应用程序组件进行测试,记录应用程序的反应,将其与想定值进行比较,从而决定测试是否成功。所有这些工作都没有人工干涉。自动操作使得您可以一遍又一遍的重复同一项测试,具有人工永远无法达到的精确性。自动操作功能测试的例子包括IBM Rational Robot以及IBM Rational Functional Tester。

 回归测试,用来衡量应用程序的质量,既可以手动处理也可以自动处理。您能够从自动功能性测试或者自动开发者测试(详见下文)中聚集一组回归测试组合工具。可靠的回归测试的关键因素就是景区的再现这些测试。因此,在被称作测试脚本的文档精确的定义测试步骤,并且在每一个回归测试中严格的按照这些步骤操作是非常必要的。在此之后,您就可以放心的使用这些测试结果,既不必担心有问题报告,也不必再去衡量其质量了。

 测试的成功与否同您在制定测试计划、文档化手动测试和自动测试上所投入的时间长短是有着密切的联系的。下面是一些实现有效测试的具体的建议:

 根据用例制定您的测试计划。首先开始测试主用例流程,然后扩展到可选流程。正如前面所描述的,关键是保持您的用例中的适当的粒度和模块性。

 通过测试计划来组织您的手动测试,通过第一批测试就开始采用一种统一的方法记录和分析测试结果。重复的、统一的操作(即使是手动的)也将会提高您工作的质量。

 自动测试首先具有相对简单可行的执行路径,但是每一次运行它都需要大量的入口数据。运用现成的数据池来完成测试脚本(例如,进行数据驱动测试)。

开发者测试

 将用例转换为有效的测试通常会遇到一个大的障碍:代码底层中的一大块部分直到开发周期的后期才能够提供给功能测试。因此,如果一些组件在被组装进正在运行的应用程序之前就被测试将是一件好的事情。而这正是开发者测试所符合的。

 开发者测试是一套关注于提高代码质量的活动,它经常被开发者使用。开发者测试包括两个主要方面:

 自动化单元和组件测试。包括代码评审,单元或组件测试,以及代码覆盖分析。
 手动测试和调试。包括运行跟踪,声明,内存泄漏检测和内存用法分析,性能评测,线程分析,等等。

 自动批处理测试可以使用例如JUnit工具——一种集成在IBM Rational应用程序开发器里的代码复审工具,也可以使用IBM Rational PurifyPlus提供的附加的方法来确保高质量的软件。在开发环境下找到并且修改缺陷就意味着在后来会出现更少的功能性错误。并且可以节省出更多的时间来编写代码和引介更多的自动控制。另外,拥有可靠的可重复性的自动单元测试和代码复审,可以使您收集到关于代码质量的有价值的方案,获得前面所描述的一样的好处。

 对于大多数组织,实现开发者测试的主要障碍就是对所需要工具的学习曲线。通常,个体的开发者测试工具注重于软件质量中某一个相对狭窄的方面。如果团队成员不具备自动开发者测试的经验,那么如何找到合适的工具和决定采用何种类型的测试就成为呈现在我们面前的巨大的挑战。因此,开发计划不应当仅仅将时间投入到开发和调试应用程序组件上,也应当将时间和资源投入到培训、设置、分析和报告有关执行自动开发测试方面。这一初期投资将会很快的带来回报,它将使得测试团队检测更少的功能性错误。它同样也会提高团队成员理解代码原理的水平。

 下面是一些关于以开发者测试为开始的建议:

 如果您即将进行单元测试,那么在运行单元测试的同时开始收集代码覆盖数据,从而对整套单元测试进行完全的评估。

 如果您即将开发C++应用程序,那么请您运行关键用例,并且通过工具对动态内存分配进行分析。内存恶化的问题是本地C++应用程序的一个关键的方面,也是造成许多意想不到的和难于再现的缺陷的根源。

 至少在每一个合成结构中的组件内收集执行的基线,并且随时监视执行的过程。

 如果您即将开发一个Java/J2EE应用程序,那么请您在一组基本测试中监视内存使用情况和内存中的对象类型。
 
 在开始时应用一把最重要的静态分析规则,将它们应用于每一个结构中,并且不断向您的代码底部添加更多的规则。这必将会减少运行结果中出现的错误。

 开发者测试并不会取代功能回归测试,手动的或者自动的。它只是通过在开发环境中检测问题,从而在整体上提高了测试的效率,因为在这时修改起来相对更加容易。

积极测试和消极测试

 积极的测试将关注点放在应用程序主流程的确认上,正如用例文档中所定义和区分出的优先次序那样。消极的测试则通常关注于那些应用程序性能极限的测试方面(例如,“破坏应用程序”)。

 在我看来,一份好的测试计划应当明确的关注于确认用例路径,而不是包括极限测试。通常,您可以通过数据驱动测试来对极限进行评估,数据驱动测试应用不同的数据集来对某个单一的实例进行测试,这是为了确定应用程序对于特定问题和异常而不是标准的参数集的反应。

下面我来谈我的最后一项策略。

回页首

支持市场工作

 在当今这个业务驱动的动态的环境中,充分理解软件市场的情况是项目成功的关键。实际上,一个组织对于市场的理解程度甚至比交流沟通、项目计划、质量以及测试更能影响它的成功。如果其产品未满足市场的需求或者定位于错误的消费群,那么即便是良好组织的、和谐的软件开发组织也会遭遇失败。

 那么如何使得那些从事工程技术的人员同从事市场营销的人员来共同合作,从而提高产品取得成功的机会呢?下面就是一些建议。

驱动beta程序和消费者参考信息

 对于软件团队来说,最有效的有助于营销一件新产品的方法就是从早期的客户那里获得积极的参考信息,并且通过他们这个组织的市场营销渠道来共享这些信息。不论您的营销人员具有多么熟练的技巧或者创造能力,他们都不可能在一夜之间收集到成功的经历。让消费者自己来熟悉新工具及其如何使用是需要一定的时间的。因此,为新项目制订计划应当将相当大量的时间和资源投入到早期的采用程序上。

 在项目的开端阶段,应当安排由市场营销团队、一些有代表性的人员,以及一位来自于您的目标客户群的消费者共同参加的关于新产品特性及其他一些需求的讨论。同那些提出要在您的产品中增加需求的关键的消费者建立联系,拿出一份测试版本程序的计划和时限,并且确保该计划包括了用户提到的需求并将其作为目标。通过事先交流和沟通这些需求信息,有助于您为程序设定一个正确的期望值,并且提高产品同时厂合拍的机会。通常,消费者必须通过一系列合法性检查和许可之后才能提供出一些有助于您突出新的解决方案的优势的参考信息。

早期协作

 还有一个好主意,那就是在项目中尽早开始同市场营销机构的合作,因为营销人员可以帮助您得到一些创建有效用例的必要信息。由于经常同那些对当前市场心中有数的分析师打交道,他们可以帮助您确定目标客户群和市场。同时,您为功能特性和产品发布确定目标所作的工作将产生出精心准备的文档,这些文档能够帮助营销机构较早的理解产品,并且使其能够描述和促进产品的正确性。关键词就是合作。

 聚集一个合作的项目团队来帮助其中的每一位成员理解那些事情需要去完成是一项非常好的措施。除了上面所提到的收集市场信息之外,协同工作的团队还应当做下列事情:

 认清关键的主办者并使他们在开发计划阶段能够聚在一起(复审目标,业务目标以及用例所描述的特定细节)。这些主办者可以是外部的投资者,潜在的消费者,或者甚至是您组织中的某一个团队。

 获得那些关于客户支持的要求信息,包括他们的专业水平和进行培训的需要。

  从销售团队那里获得渴望实现应用的日期,关键用户以及主要关注点等信息。

 收集陈述和介绍的材料来介绍本组织的其他部分介绍给该项目,从而他们可以开始一同参加工作。协作的团队成员应当在整个项目周期中夜以继日的加速实现项目的目标、计划和活动,从而他们能够继续培养和教育感兴趣的参与者。

“谈论”市场营销

 “谈论”市场营销就是指如何通过媒体传递技术性的功能。有时针对目标客户群的营销努力是非常技术性的,但是在更多的情况下,这样的努力由一些根本没有技术基础的业务决策者来执行。帮助您的营销机构将特性细节转换成有意思的信息以提供给一位非技术人员的顾客的最好的方法就是,充分理解该新产品所带来的好处和价值,并且准备好将其通俗的表达出来,例如以美元的数额。

 准备好为下列问题提供清楚地答案:

“为什么这个新产品或者增强版本很重要?”
 “它是如何在我们的业务策略中对关键的开端提供支持的?”
 “谁将从这项新性能中获益?”
 “该产品如何工作?”
 根据我的经验,即使是最复杂的技水性解决方案都可以通过一种相对简单的方式来加以解释,这种方式概括了解决方案及其好处后面的动机。挑战在于如何找到一个使得您的用户中的大多数人都能够理解的模型。

回页首

总结

 面对全球化所带来的复杂的业务和技术要求,当今的组织不得不关注非技术性的和技术性的资源,才能够创造出成功的产品并且在激烈的市场竞争中占有一席之地。尽管没有所谓的“银弹”来保护您的软件开发组织在项目开发期间免受可能出现的挑战,但是认清楚您的组织内部不同开发部门和功能之间同步的重要性,将会为您在今后的发展中所遇到的每一次挑战做出更好的准备。

注释

 1 代码编写标准可以是行业特定的,并且通常是强制性的需求。

参考资料

 您可以参阅本文在 developerWorks 全球站点上的 英文原文。


关于作者

 Goran Begic于1999年在荷兰加入Rational软件团队。从那时起,他曾先后从事IBM Rational PurifyPlus系列产品开发人员测试工具的技术支持、方法提供、产品管理以及销售工作。他同样拥有丰富的实现灵活开发的实践经验。1996年,他获得了萨格勒布大学的电机工程学学士学位。


版权所有:UML软件工程组织