UML软件工程组织

软件工程—需求的实践(下)
作者:林星 本文选自:IBM DW中国
文四 业务建模时期(上)


  内容:

  ·所有的项目都有业务建模时期

  ·建模原理

  ·关于作者

  在大规模的需求调研展开之前,有一个重要的工作要做。这项工作在项目中所占的时间跨度非常的小,但是却有非常重要的意义。不同的人、不同的方法对这项工作有不同的描述,在我们的文章中,根据UP的思想,称之为"业务建模"。

  所有的项目都有业务建模时期

  1. 业务建模是什么

  业务建模(Business Modeling),业务建模是一个复杂的过程,对其下一个准确的定义是困难的事情。在RUP的词汇表中将其解释为:

  "包含您可用来对业务进行可视化建模的所有建模方法。这些是您可用于执行业务工程的方法的子集。"

  从定义中可以看出,它是一种建模方法的集合,目的是对业务进行建模。这方面的工作可能包括了对业务流程建模,对业务组织建模,改进业务流程,领域建模等方面。

  2. 为什么要业务建模

  Brooks 大师说,三十多年来各式各样的应用系统(Application Programs AP)历经多次的修修改改,已经变得面目全非,如同一群的怪兽,难以驯服。

  Rogerson大师也说,The application is a rock in the river of change.(应用(系统)成为改变之潮流中的顽石)。

  对很多企业而言,有一个统合企业各部门的信息系统的心愿似乎已经成了一种奢望。企业中或多或少都会有一些应用系统在辅助企业的自动化运作,当企业信息主管希望能够对目前的信息系统进行整合,能够配合企业的发展的时候,他们失望了。大多数的应用缺乏一个统一的接口,难以进行整合。

  在我们进行项目开发的银行中,我们也同样发现了这个问题,不同部门的系统之间无法进行互联,跨部门的业务流程必须经过手工的处理。

  以前,应用程序的开发都是基于部门的功能的而建的。单纯只是为了解决目的而建立应用系统。所以这种方式建立的应用系统是针对特定的功能区域(Function Area)而建立的。至于如何使企业内的多个应用系统共同运作,就不在设计者的考虑之列了。随着企业的发展,就会发现企业需要变化以适应市场变化,业务发展的时候,原有的一系列应用系统却成了企业发展的拦路虎,这使得企业不得不回到手工的时代。

  针对这种情况,有没有相应的解决之道呢?解决的方法就是从业务建模入手,而不是从较低层次(部门级或以下)入手。通过用例分析技术,建立企业的业务模型,进行适当的切割,选取稳定的软件架构,分析出企业的业务实体(Business Entity 企业中微小不可分的事物,抽象或具体的,如帐户,契约等,又被称为Business Object),以此为基础,组装出组件(Component),落实到相应的三层结构,建立针对特定功能区域的应用系统。

  以这样的流程做出来的企业应用系统,不论规模是部门级的,还是企业级的,都有扩展的余地。以组件为基础的软件三层构架,也能够较好的配合企业的业务变化而变化(相应变化的代价较小)。而整个流程的第一步,就是业务建模。

  在前一段时间,中国很流行企业流程再造BPR(Business Process Re-engineering)这个名词。BPR这一名词中的R(Re-engineering)一词是由Dr. Hammer提出,说明企业必须推动四个层面的重新设计:Re-position、Re-organization、Re-system、Re-vitalizing之再造工程;名称中的P(Process),更是管理上由销售、采购到财务、生产各层次,力求降低成本、提高产出,所必须精密设计的企业管理流程或程序。这个词目前都是和ERP串联在一起,成了ERP的前置工程,更成为保证ERP能建立企业完美管理体系,以支持高绩效的最重要因素。实际上呢,这个BPR就是我们所谈到的业务建模。

  可以看出,业务建模在ERP工程中被着重强调,而且ERP中的BPR已经成为一门独立的学科。不仅如此,即便是在普通的信息系统中,业务建模也是非常重要的,所不同的,仅仅是它们的规模而已。这一点上,可能大家会不理解,如果你只是为企业的业务自动化建立应用,直接照搬企业模式不就行了吗。这里有两点原因,一是企业原有的业务模式在以人为主的环境中可能运行的很好,可是把这套模式原本不动的搬到计算机上就未必会适合了。人的能力和计算机的能力有很大的出入,所以流程必须经过调整以适应计算机;第二个原因是上面已经提到过的避免产生部门级的,部分功能区域的应用系统。

  在RUP中,业务建模被作为下游流程的输入重点强调:业务模型是需求工作流程的一种重要输入,用来了解对系统的需求。业务实体是分析设计工作流程的一种输入,用来确定设计模型中的实体类。(RUP)

  3. 需求和业务建模

  业务建模是需求工程中最初始的阶段,也是整个项目的初始阶段。需要指出的是,业务建模时间的跨度在不同的项目中有很大的差别的。在有些项目中,例如大型ERP系统,可能需要几个月的时间。而对于普通的项目,业务建模的时间可能仅仅需要几天的时间。

  需求是技术无关(technology independent)的。在需求阶段讨论技术是没有任何意义的。那只会让你的注意力分散。技术的实现细节是在后面的分析、设计阶段才需要考虑的事情。而在业务建模阶段,不但要保证需求的技术无关性,还要保证你的需求不要深入细节。因为在业务建模阶段,最重要的事情就是要了解业务的全貌,深入细节会浪费时间和精力。要知道,讨论一个企业里的业务细节,就算给你一个月的时间也没必能够结束。

  在实际中,这两点都是很难做到的。例如企业原先有一个系统,这就不得不由你讨论和新旧系统的兼容问题。这时候就要注意,如果你是讨论就有系统的架构的话,那还是属于技术无关的范畴,如果你一旦进而讨论各具体模块/组件的细节,那就非但不是技术无关,而且也深入细节了。在不深入细节的问题上,往往你很难禁止项目涉众(Stakeholder)①不去讨论一些相关的业务细节。这个时候你可以将这些细节记录下来,然后再回到业务建模上。

  ①A stakeholder is defined as anyone who is materially affected by the outcome of the project.

  涉众是所有会受到项目结果重大影响的人。

  4. 业务建模时期的主要任务

  项目涉众的共同愿景:要想项目成功,可离不开项目涉众的支持。在项目一开始,不论是项目涉众还是开发人员,对项目的任务、范围都是模糊不清的。但随着项目的深入,原来模糊的景象会慢慢清晰、立体起来。但是为了不浪费时间,我们有必要在项目射入之前,现在项目涉众中竖立一个共同的愿景。

  共同愿景的竖立可没有想象中的那么简单,因为每位涉众都关心自己的利益,都有自己的评判标准。你可以把大家的意见都列在白板上,然后逐项集中讨论,做出修正,直到大家的意见一致的时候为止。在共同远景的竖立过程中,其实有两件事情也已经同时做了,项目范围(scope)和高阶(high-level)需求。

  项目范围:项目该做什么,不该做什么,需要在一开始就有明确的定义。对于项目范围内的需求,一个也不要放过,而项目之外的,一个也不要去关心。虽然有的时候,范围的变化会有利于项目本身,例如客户的合理要求或是市场目标客户的变化,但是这种变化应该要在"资源能够支持"和"得到审批"的前提下进行。

  项目范围的描述可以通过陈述和图示来进行。我建议大家使用图示。因为陈述语句比较含糊不清。例如常常听到有客户说。"我要建立我公司的电子商务系统。"这句话就是含糊不清的,你的电子商务系统是销售什么产品?面向什么客户?是否要支持在线支付?根据这些疑问,这个陈述句可以做进一步的修改,"建立在线订货系统,针对当前的目标客户销售公司的目前产品。"这样就清楚许多了。不过图示的方法会更好一些,在图的选择上,你可以使用DFD图或是用例图。根据经验,DFD图比较容易为客户所接受。

  高阶需求:这个部分我们在下面会详细讨论。既然是高阶需求,就不能讨论过多的细节。在讨论高阶需求的时候,尽量保证快速的讨论出系统的概貌,建立需求模型,得到项目涉众的一致通过。

  取得支持:为了保证需求计划的顺利进行,取得项目涉众的支持至关重要。你可以选择在这个时候告诉项目涉众他们的权利和义务,以及开发人员的权利和义务。在这个方面,具体的我不想多说,大家可以参考『软件需求』的第二章。主要的就是"涉众有改变需求的权利,同时要承担向开发人员讲解需求的义务。"开发人员的权利和义务正好和涉众相反。

  业务建模会议:所有的这一切都通过业务建模会议进行,和其它会议不同的是,这个会议需要所有的项目涉众参加,如果不能获取所有项目涉众的意见,那就不是完美的。会议中最重要的工具就是白板,一位出色的速记员也是必须的。

  建模原理

  5. 业务建模中的用例

  在上一篇中我们讨论了很多用例的知识,可是落实到企业中的时候,我们往往会感觉难以把握企业的用例,这一点我们在用例的误区中也有提到。在实际的情况中,你可能会对角色的归类,用例的划分,粒度的把握等很细节的方面都没有底,偏偏这些实际的东西对你的项目有非常大的影响。

  RUP中,有多种的概念来支持用例的实现:业务主角(Business Actor)、业务实体(Business Entity)、业务用例(Business Use Case)、业务角色(Business Worker)、业务用例实例(Business Use-Case Instance)。为了能够比较清楚的展示出业务建模,我们采用了UP方法的代表――RUP。但在实际中,要视大家具体的情况而定,这里所讲到的概念,都是为了帮助大家理解建模过程,并不是让大家生搬硬套。

  在我们对系统还丝毫不了解的时候,我们就会把系统看成一个很大很大的黑盒,这个大黑盒子我们会叫他业务域(Business Domain),把它的外部看成一个业务环境(business environment)。而那些在业务环境中和业务域有关系的人(也可能是物)就被称为业务主角(Business Actor)。在实际的例子中,我们可能会把信贷业务(注意不是信贷业务系统,这里是业务建模,系统还不存在。)称为业务域,我们经过调查,发现平时和信贷业务打交道的有客户,人民银行,外汇管理局,其他银行,信贷部门使用的其他系统,银行内部的其他部门。所以这些人(物)就是业务主角。业务主角的实例一般包括了客户、供应商、合作伙伴、潜在客户("市场")、当地政府、在业务中未建模部分工作的同事等。必须注意的是,业务主角表示的特定类型的用户,而不是某一个具体的用户。一个角色可能会有很多实际用户担任,一个实际的用户也可能会担任很多的角色。

  业务用例以及业务用例实例在RUP中的定义如下:

  A business use-case instance is a sequence of actions performed in a business that produces a result of observable value to an individual actor of the business. A business use case defines a set of business use-case instances. A business use case has a name.

  业务用例实例是在业务中执行的一系列动作,这些动作为业务的个体主角产生具有可见价值的结果。业务用例定义了一组业务用例实例。业务用例具有名称。

  刚开始大家可能会对业务用例以及业务用例实例有所疑问。其实可以把他们看成基类和子类的关系。在一个企业中,具体的工作流程可能有很多很多,比如你去麦当劳的时候,点汉堡和点薯条的工作流程就不一样。众多的流程给需求的调查工作造成了一定的难度。即使是最古老的哲学也告诉我们,表面现象是复杂的,本质是简单的。为了简化需求工作,我们就把点汉堡和点薯条归纳为点餐。这样,点餐就是一个业务用例,而点汉堡、点薯条就是相对应的业务用例实例。



  业务用例

  业务角色和业务主角的概念也很容易让人摸不着头脑。其实看它们的英文愿意会更容易理解它们的区别:Business Worker,Business Actor。Worker有工人的意思,而Actor有参与者的意思。所以它们的区别就是一个在内部,一个在外部。业务角色是实现业务用例的人,业务主角是和业务有关的人。例如,对银行的押汇业务而言,客户就是业务主角,他和业务有关。而押汇人员就是业务角色,因为他们是实现业务用例的人。在RUP中,二者定义如下:

  A business worker represents a role or set of roles in the business. A business worker interacts with other workers and manipulates business entities while participating in business use-case realizations.

  业务角色代表业务中的一个或一组角色。参与业务用例实现时,一个业务角色和其他角色进行交互,并操纵业务实体

  A business actor represents a role played in relation to the business by someone or something in the business environment.

  业务主角代表了与业务有关的角色,此角色由业务环境中的某个人或物来担任。



  业务角色



  业务主角

  分辨业务角色和业务主角要看环境而定。当你开发企业的ERP系统时,部门的员工都属于业务角色,而你开发一个部门级的应用时,其他部门的员工可能属于业务主角。

  业务实体,在一些文章中被称为商业对象(Business Object)。不论怎么叫,所表示的意义都是一样的。例如在银行信贷这个例子中,我们就涉及到很多业务实体:契约、单笔贷款、客户等。所以业务实体就是企业中那些很基本的要素。如果觉得银行押汇的例子不好理解。可以想象餐厅中的菜单、汉堡等都是业务实体。在RUP中,业务实体被定义为:

  A business entity represents a "thing" handled or used by business workers.

  业务实体代表业务角色处理或使用的"事物"。



  业务实体

  在很早以前,我们讨论过需求易变性。相对于需求的不断变化,可是业务实体对象在一段相当长的时间内都存在。航空公司今天打折,明天又不打,还有明折、暗折。可是机票从来没见有什么大的变化,从来也只有那几样属性:价格、航班、出发地、目的地。所以业务实体是比较稳定的。这对于我们是有很大的意义的:

  "一个业务实体经常代表某个对多个业务用例或用例实例有价值的事物,因此,业务实体对象的生存期相当长。一般而言,一个好的业务实体不包含关于其使用主体和使用方法的信息。"(RUP)

  由业务实体组成的业务用例会稳定很多。在以前,开发方式采用模块为基础的方法,需求变化的时候,只好改写模块。如果采用稳定的业务实体来实现业务用例的话,业务用例的改变只需要对业务实体进行重新的组合。当然,这里还需要很多的技术来实现,并没有那么简单。要知道,四个现代化可不是一天就能够实现的。

  还有一个使用业务实体的重要原因:业务实体的特性决定它具有天生的重用性。就像麦当劳的销售系统中有汉堡实体,生产系统中也有,供应链系统中也有。天哪,这世界真是美好!

  使用业务实体一个很大的困惑是应该把它做为类还是属性。这个取决于业务环境对这个实体的重视程度。一个客户在银行信贷部门是一个很重要的类,而在押汇部门就只是信用证实例的一个属性。这个问题非常的重要。设计时的失误可能会导致今后系统改进的极大痛苦。例如本该设计为类的业务实体设计成了属性,在今后增加属性的时候不得不面对着数据库的调整和系统的修改。

  6. 建立业务用例模型

  业务用例模型(business use-case model),在RUP中定义为:

  The business use-case model is a model of the business intended functions. The business use-case model is used as an essential input to identify roles and deliverables in the organization.

  业务用例模型是说明业务预期功能的模型。作为一个核心输入模型,业务用例模型用于确定组织的各个角色和可交付工件。

  从业务用例模型的定义可以看出,它是企业最核心,最概括的业务说明。它主要是由业务用例和业务主角构成的,其主要目的是说明客户和合作伙伴是如何开展业务的,它描述业务的主要方式是通过业务用例的方式。下图为RUP中业务用例模型的图示。



  业务用例模型

  从图中我们也可以很清楚的看出业务用例模型包括一组的业务用例。这是因为企业中的业务通常都会由多个的业务用例的多个实例构成。这些业务用例形成的企业工作流程可能会由业务主角所引发,也可能会由业务规则②所引发。

  ②业务规则(Business Rules):业务规则是必须遵守的政策或条件的声明。(Business Rules are declarations of policy or conditions that must be satisfied.)

  业务用例模型实际上就是企业经营业务的一种描述,为了建立完整、准确的企业用例模型,应该将注意力专注于企业的业务做了些什么事情,而不应该集中于如何做。虽然这样可能会产生一些业务用例相冲突,相重复的情况,但是RUP的思想在于迭代,这项工作完全可以在接下去的迭代周期内完善。

  业务用例模型是和企业业务最贴近的计算机模型。它的很多思想和企业日常经营如出一辙。在企业的日常活动中,业务的种类可能有很多种。在一些讲述ERP思想的文章中,通常会强调三类:

  一种是和主营业务密切相关的工作,例如银行的营业部、信贷部、押汇部等。这种工作通过人的劳动,将一种资源转变为另一种资源,产生价值。

  一种是管理型的工作,例如公司的管理层,财务部门等。这种工作本身并不产生价值,但是它通过指导、管理、检测第一种工作,加大第一种工作的产出价值。

  还有一种称为支持工作,例如系统管理、安全等。它并不是很重要,具有支持其他工作的性质。

  业务模型同样可以使用这种分类。通过这种分类,可以更好的把握核心业务用例,为下一步的工作打好基础。

  有很多业务用例是由业务主角触发的,RUP中也把和业务主角有关联关系的业务用例称为核心业务用例(Core Business Use Case)。这强调了构建业务模型的目的是为了提供以用户为中心的服务。这也是我们建立业务用例的时候应该注意的。

  当然,有时候业务用例的触发是为了产生用户需要的结果。例如企业的市场调查行为就不是由业务主角触发,而是企业积累了大量用户请求的结果。而对于管理型、支持型的,不直接和业务主角的客户类发生联系,但是也有其特定的业务主角,如管理型的业务用例需要和董事会为发生联系,支持型的业务用例可能和供应商发生联系。

  在建立了基本的业务用例模型之后,对此模型进行精化是非常有必要的,这时候,在上一章中我们介绍的用例的扩展关系和使用关系就有了用武之地。除了这两种关系,还有一种新的关系。

  7. 在业务建模中使用关系

  泛化关系(Generalization):根据我的理解,可以把它看作我们比较熟悉的继承关系很相似的一种关系。Generalization一词含有一般化、概括的意思。它是一个相对抽象的词。虽然它和继承关系非常相似,但是它们在使用环境和产生目的方面都有相异之处。下图描述了四个业务实体之间的泛化关系:



  当你去麦当劳的时候(不要误会,我并不是很经常去的),会选择麦香鸡汉堡、麦香鱼汉堡或是吉士汉堡。但是分别对这三种汉堡建立业务实体就非常没有意义。所以可以将它们概括为汉堡这个业务实体。同样的道理,企业的业务流程中也可以概括出一些共有的属性和行为。为了避免多次说明同一个工作流程,您可以将共有的行为放在一个单独的业务用例中。称为父用例,执行子用例的用例实例将遵循父用例的事件流,同时插入附加行为或修改在子用例事件流中定义的行为。

  8. 方法的选择

  以上的原理我采用了UP的方法。但是除了UP方法,还有XP、FDD等方法。所以在做业务建模的时候,也要根据不同的方法选择适当的工件。例如素材和功能。方法的好坏并不是我们这片文章讨论的重点,我会在另一篇文章中讨论方法。再一次需要强调的是,上面讨论的RUP的工件只是为了学习,所以才定义了比较复杂的工件,区分了它们之间的区别。但是在实际中,并不需要这么多的工件,那只会使你的项目涉众和开发人员糊涂。这些工件的区别只要在你心中就可以了。至于具体的实践,我们会在下一篇文章中讨论。
文五 业务建模时期(下)


  内容:

  ·原则(Principle)

  ·实践(Practice)

  和上一篇的理论不同,这一篇文章更注重于实际,举出了在业务建模简短需要注意的一些原则和实践,每一条都来自于实践之中,也都有理论的支持。其中的很多内容更是经过多次的失败才总结出来的。相信大家如果能够理解这些原则和实践的某些方面,至少能够避免重蹈覆辙。

  原则(Principle)

  1. 谁才是"上帝"

  我们说客户是上帝,是因为客户的重要性,客户占有决定性的地位。可是在软件开发中,到底是谁有决定权呢?是出资方,还是项目经历,或是程序员?

  职责不清,是业务建模失败的主要原因之一。我们可以很容易的看见客户把自己的要求用几句话高度浓缩之后扔给开发人员,或是开发人员按照自己的意思开发程序。难道说,客户和开发人员之间真的是"心有灵犀",完全不用沟通的吗。

  我在前文中已经提到过项目涉众和开发人员的权利和义务,我想这里还有必要再次强调。Scott W. Ambler说:

  it is the role of project stakeholders to provide requirements, it is the role of developers to understand and implement them.

  在我一次开发过程中,遇到过一个很有意思的涉众,他在他的需求分析中这样写:"总之,要实现那种能够想到就能做到功能。"我想,这位涉众对我们的计算机工业有着非常远大的抱负。但我不得不客气的告诉他目前实现是不太现实的。

  大家听了可能会觉得好笑,但是在我自己和客户打交道的生涯中,这种客户不在少数。现实就是这样,你要怎么做?是一笑之后,弃之不顾吗?我想大多数人会这样做。因为他的要求太荒唐了嘛。可是,你有没有花时间去了解一下,他这句荒唐的话背后代表了他的什么意思呢?我觉得,软件开发人员负有教育涉众的义务,你需要引导你的涉众,让他们说出自己的心声。我在看到这位涉众的这句话后,就花了一些时间去了解,其实呢,事情很简单,他就是想要一个能够定制报表模板的功能。而在项目结束后,我和这位涉众有幸再一次的合作,这时候,他已经成为了一个出色的客户方的项目领导者了。

  这个例子说明了什么呢?涉众往往都是领域专家,对自己的工作有很深的认识,可是由于对软件开发的不了解,涉众往往表达不清,甚至表达不出自己的需求。这时候,就是体现你的功力的时候了。记住,象对待上帝一样对待你的客户。

  2. 耐心是首要的

  明白了谁是"上帝",那就要耐心的对待上帝。学理工科的人,一般在逻辑思维上会比较好,可是对于涉众来说,可不一定是这样。我就遇到过一位做档案工作的涉众,在了解需求的时候,扯东扯西,含糊不清。明明一分钟前才否定的方法,下一分钟又提出来了。我觉得我的脾气应该是不错的,可到最后也几乎发飚。所幸,最后我终于撑了下来。我想,在经历过这件事情之后,我的耐心指数又会有一个很大的提高了吧。

  我有一位同事的耐性是我所佩服的,在一个网站项目中,他负责系统分析。他整整花了三天的时间,和网站项目的负责人住在一起。最后系统分析出来之后,他的精神还不错,可是那位负责人已经快不行了。

  当然,这只是个笑话,并不是去鼓励大家拼命。劳逸结合还是很重要的,身体是革命的本钱嘛。但是这告诉我们,如果缺少耐心,需求是很难成功的。例如在业务建模的讨论会上,你虽然规定了这次的会议讨论的是高阶需求,可是与会者总会时不时的争辩一些芝麻绿豆的小事儿。你怎么办?我相信这种情况是很普遍的。

  耐心最后会仍会体现为沟通,只有耐心的沟通,你才能揭开需求的重重面纱。人的行为总是会受到思想的指导,如果你解不开涉众的心结,你就不可能了解他真正需要的。

  我的一位项目涉众的表现很奇怪,她总是在不停的说一件事情:"她要实现报表自动生成。"她的需求讲来讲去好像总脱不出这个范围,可是我从她那里几乎听不到别的东西了。这时候,我决定放弃了,我想从她哪里可能已经没有更多的资料了。但在我了解到她的工作中报表处理占用了她大量的时间之后,我改变了想法。在我花了一些时间帮她理清了报表处理的思路之后,她还在其他方面给了我很大的帮助。

  3. 参与是重要的

  XP方法的一个重要实践,就是提倡"现场客户"(on-site customer)。也就是说,客户应该随时和开发人员在一起,随时提供资料和做出决策。而这个客户,也必须领域专家,而且能够有权做出决策。

  这种现场客户相信国内的软件组织多半还做不到。但是一定要往这方面努力。我认为,这种现场客户有两种人:一种是项目涉众,还有一种是行业专家。其实很多软件公司都会配备一些管理咨询人员,这些人就是行业专家。有数据统计说,目前广东省软件公司中的咨询人员和开发人员的比例达到了3:1。我觉得这是好事。项目涉众往往对自己的工作中的事务性部分有很深的认识,但是很难将之提升到一个理论的水平。这时候就需要一些行业专家来帮助了。让行业专家和项目涉众共同探讨,还能够激发项目涉众的灵感,想到原来他想不到的方面。这就是"潜在需求"的开发。

  另一方面,参与还意味着需要项目涉众全身心的投入到业务建模的过程中来,要能够调动他们的积极性。因此呢,太复杂的流程会阻碍涉众的参与。所以,使用一些简单的、能够为客户所接受的工件(Artifact)来进行业务建模是很有必要的。我说过前面讨论的那些"主角"啊,"用例"啊,那是理论,是给开发人员看的,让开发人员心里有个底。你给涉众看这些,他们能懂吗?等他们了解了这套机制,恐怕黄花菜都凉了吧。

  素材(User Story)、特性(Feature)、CRC卡片这些都是很不错的工件,既简单,又能够满足需要。

  知识点:素材和特性都表述了用户的一个简单的要求,它能够在较短的时间内完成。素材是XP方法中的工件,特性是FDD方法中的工件。CRC是class、 responsibility、collaborator的缩写,它是一张分为三个部分的卡片,分别标记了类名,类的责任,以及类之间的合作关系。非常的贴近客户,甚至可以在做游戏的过程中完成卡片的填写,能带来很强的客户参与度。

  4. 拥抱变化

  我想这一点会遭到开发人员点一致指责。毕竟,需求变化是开发人员最讨厌的一件事了。不错,我也讨厌。可是,就像我们常说"哭不能解决问题"一样,讨厌能解决问题吗?拒绝客户的变更要求,要求客户在需求规格说明书上签字。这些做法只能是适得其反。没有任何正面的、积极的意义。

  必要的需求变更管理是重要的。因为无休止、无控制的变化必然会造成资源的极大浪费。但从另一方面说,需求变更被接受的评判标准应该是"是否合理",而不是"是否易于实现"。

  需求变更要求我们的开发工作要迭代式进行,包括需求、设计、实现等阶段。这样才能将变更风险减到最小。这一点我们在讨论具体需求建模的时候会进一步讨论。

  拥抱变化的更高一个层次是提前预估变化。制定一个可能的变化清单来记录可能出现的变化。最简单的例子就是一个企业在开发了进销存系统之后又希望能够开发财会系统与之相连。如果你能够预先留下伏笔,相信能够省不少力气。预估变化的另一种做法是通过使用模式。但是切记,模式的使用也不能过头。这些是题外话,如果有机会我会在其他的文章中集中讨论这方面的问题。

  实践(Practice)

  5. 建模会议

  会议是业务建模最重要的手段。尽管会议在中国总是背负着一些骂名,但是只要组织得好,它是一种相当有效的沟通(Communication)手段。建模会议是一种大范围的会议,换句话说,所有的相关人员都应该参加会议。因为在业务建模时期,主要的目的就是建立对系统的高阶需求,这就要求众多项目涉众的共同参与,以保证需求的广泛性。所以呢,建模会议的规模是相当大的。出资方、高级经理、经理、直接用户、开发人员,各方各面的人都应该参加或是派代表参加建模会议。

  如果大家有过参加大型会议的经验都知道,越是大型的会议,它的决策效率就越低。这是正常的。因为一个人的时候,不需要沟通,决策效率最高。等到两个人的时候,他们需要沟通的时间来进行决策。等到三个人的时候,这个沟通并达成一致的时间就更长。如果人数到了四个人、五个人甚至一二十个人,那么大部分的时间都会花在沟通上。更何况,人和人之间还有观念不同、利益之争。所以呢,为了保证会议的效率和效果,应该遵循一定的规则:

  ·做好准备:如果你要开会,与会者连内容都不清楚,那你会怎么办。你必须首先花很多的时间来说明你开会的目的,是不是。要事先将会议的主题、议程连同会议通知发送给与会者,让他们先有个准备,会议开始时就能够迅速进入正题。

  ·尽量邀请最多的人:我已经说过,如果建模会议不能够听取最广泛的意见,它就不是一个成功的会议。可是在现实中,这点往往难以做到。因为目标组织做为客户,往往都很"拽",在没有充分认识会议的重要性之前,要做到全部到场简直就是不可能。而客观上也会有出差、休假、有要事等原因做不到这一点。这里,一方面你需要向目标组织的决策者阐明利害,让他们重视。另一方面,你也需要积极主动的邀请项目涉众参与。因为邀请所有的人是不可能的,所以就尽可能的多吧。

  ·分出与会者的级别:我很喜欢那种有一个内圈、一个外圈的会议室。因为我邀请所有人是件无法做到的事情,所以我首先要保证核心人员能够全部到场,坐在内圈,然后才是次要的人员,坐在外圈。核心人员是和你的项目息息相关的那种人。比如,财务系统,财务主管就是核心人员。要保证核心人员全员到场,至于次要人员,越全越好。

  ·从底层开始:中国人有个比较不好的习惯,就是老板说一的时候,他决不会说二。所以要先让底层先说话,然后才轮到中层,再到上层。开发人员是不说话的,他们要么听,要么引导大家说话。如果我们一开始就先让领导来训话一番,那底层的人也就不用再说什么了。

  ·列举所有涉众的所有观点:首先要让大家能够对新的系统畅所欲言,然后把所有的观点都罗列在白板上。这里头可能会有一些观点会是非常荒唐的,但没有关系,尽管写上去。这是一个脑力激荡的过程,很容易产生出新的idea。主持的开发人员的主要工作就是引导和鼓励大家说出更多的想法,并记录下来。这里我们稍微离题一下,有人说中国人在会议上大都不愿意发表意见,我看在这种建模会议上不必过于担心此事。为什么呢,因为项目涉众不需要为他们的发言担任何的责任,说了,白说,白说谁不说。

  ·将观点分类:想必你的项目涉众已经有些累了,创意也差不多了,你的白板估计也满了。但是你看看白板上的观点,有很多是重复的,有很多是类似的。所以你需要用逻辑的观念将这些观点归类整理。这个工作也可以由你引导大家去做。

  ·确定优先级:对观点排出优先级也是非常重要的,它能够帮助你识别出重大的风险,并为你在制定迭代计划时提供指导。同样,这项工作也应该由项目涉众来确定。

  ·调查主要业务逻辑:什么叫主要业务逻辑?包括了企业的主要业务流程、主要的业务规则、重大的算法。这些都是需要在一开始就十分明确的资料,需要在建模会议上了解清楚。当然,你不能对你的项目涉众说,"这个,接下来,大家谈一谈主要的业务逻辑吧。"下面的涉众一定摸不着头脑。你还是应该引导涉众,从涉众的话语中捕捉你需要的信息。

  ·注意会议时间:人不是机器,是会累的。所以控制好会议的长度很关键。一般,这种会议会有四五个小时,根据统计,两个小时内的会议不会让人产生疲劳感。所以应该把会议分成几小段。另外,你还可以根据会议的进展来决定每小段会议参与的人数。因为,会议越往后,一些与会者就不太重要了。

  ·避免细节:建模会议主要的目标是建立高阶需求。如果把过多的时间花在讨论鸡毛蒜皮的小事,那就会浪费大家的时间。而在此时调查需求细节是没有很大的意义的。因为你对很多的事情都还不了解,需要进一步的深入。这时候的细节对你并没有太多的帮助。

  ·回避技术:我在一次建模会议的时候,遇到一位负责技术的涉众,他总是不停的询问系统的技术架构,推销他的设计理念。使得我不得不好几次重申,"技术问题我们会单独找时间谈。"我想,那位技术人员应该是有比较好的理念,也很希望能够表现一把,这点无可厚非。但是这个时候还不是讨论技术的时候,需求尚未明确,讨论技术实现不是本末倒置么?

  ·做好记录:俗话说,好记性不如烂笔头。所以在会议上做好记录是非常关键的。因为这种会议的代价相当高昂,你的项目涉众不可能每天不干活,陪你开会的,就算他们肯,他们的老板也不肯。所以要充分利用好会议的成果,所以一个优秀的速记员绝对是必要的。另外,根据研究显示,如果使用录音机的话,会使得与会者心存芥蒂而不愿开口,所以,不要使用录音机。

  6. 测试

  在需求的初始阶段提到测试可能会觉得有些奇怪。凡是项目,总会有一个标准来考核是否成功。这里的测试指的是考核软件项目是否成功的一个"执行性目标"。

  这个目标将会是软件开发最终要满足的条件,软件成功与否的判定标准。很多企业在信息化建设的时候没有一个比较明确的目标。所以在被问道这方面的问题时,他的答案往往是我的目标是建成企业的ERP系统,建设企业的信息化平台等空洞的话。这样的软件怎么开发?连结束的标准都没有。是费用用完结束呢,还是决策者说停就停了呢。目标应该有一个可以量化的标准。例如,开发物流系统的目的是为了缩短产品周转周期,降低库存;开发供应链系统是为了加强和供应商的联系,降低库存。这些和具体业务有关的指标都是可以通过细化,用多种分指标来度量的,所以是可以做到的。

  我们把这种目标称为测试就是要提醒开发人员,要把满足这种目标当作最终的测试。你的软件做得再好,不是涉众想要的,又有什么用?这是很浅显的道理,可是在实际中,涉众方和开发方往往因为一些具体的因素看不到这一点。其实,这个目标在上一篇中我们也讲过,那时我们是把它叫做愿景、范围。在本质上是一样的。

  这种"可执行性目标"可以使用一些因素来衡量:

  7. 业务实体

  业务实体(business entity)是企业中的一些起到关键作用的类别。客户、供应商、员工、订单、凭证,这种业务实体的例子可以举出很多很多。业务实体往往会成为一个很关键的因素,因为在系统中,角色操作业务实体的行为往往会分配给业务实体,例如"根据订单计算价格"会成为订单的一个行为。这样,工作流程的实现往往是多个业务实体相互合作完成的。所以业务实体设计的好坏会对系统有很大的影响作用。

  业务实体设计的主要工作包括找出业务实体,确定业务实体的属性和行为。

  要确定业务实体,首先必须确定角色,并从角色的行为找出业务实体。角色需要我们对目标组织进行讨论。以我个人的经验,寻找业务角色一般比较简单,但是要记住,一个人可能担任好几个的业务角色,这是经常发生的情况。从业务角色的行为,我们可以找出业务角色所处理的事物,这些就是我们所需要的业务实体。业务实体是一个单独的业务实体还是业务实体的一个属性是值得研究的。一个本该是属性的事物被判断成业务实体只是会带来一些开销,可是一个本该单独列出的业务实体却只是被判定为其它业务实体的一个属性就有可能会带来灾难性的后果,最大的可能是系统难以扩展。

  在一个人力资源管理系统中,员工类可能是非常重要的一个业务实体,它可能有非常多的属性。而在其它的系统中,例如进销存,员工类只是起到一个记录、权限管理的作用罢了。再比如,在一些企业内部的自动化处理系统中,客户可能只是其它一些实体的属性,而以客户为中心的设计大行其道的现在,这种设计就有它的致命缺陷。

  要确定业务实体的属性和行为,主要是要确定每个类(业务实体)要做的事情,属性则是为了能够更好的描述类和类要做的事情。利用CRC卡片是一个不错的办法。

  CRC是"类"(class),"责任"(responsibility)及"辅助者"(collaborator)三者的简称,这些资料常呈现在一张卡片上。

    类名称

    责任1 责任1的辅助者1

    责任2 责任2的辅助者2

     …   …

  通过制作这样的CRC卡片,可以比较容易的找出每个业务实体的行为(责任)和属性(辅助者)。您可能会问,为什么不直接找出属性和行为,而要多此一举呢。这个问题是我们一直在强调的。在建模阶段,我们面对的是可能对计算机技术完全不懂的涉众,所以,采用大家易于接受的方法,可以够保证需求的完整和正确。

  8. 准备计划

  目前在软件开发中,关于计划有两个极端的误解。

  在有些软件组织中,一般不做计划,或是做一些笼统的、没什么用处的计划。一些开发人员认为,"做计划是虚的,还不如做些实际的事。"对于项目经理,或是对这种情况没有办法,或是发布的计划开发人员阳奉阴违,让计划成为一纸空文。项目执行中随意性极大,偏离方向的事情时有发生。

  而在另外一些组织中,计划被视为重中之重,需要花费大量的时间、人力,做出来的计划可谓事无巨细,算无遗策。而写的出这种计划的项目经理也被视为高级人才。开发人员叹口气说,"写程序的不如写文档的。"可是在执行的时候,原来精密的计划往往漏洞百出,项目的进度一拖再拖。

  我们所有人都知道那句明言:在软件开发中,要花90%的时间完成90%的项目,然后再用90%的时间完成剩下的10%的项目。为什么呢?计划不科学。

  在管理学中,计划,也有叫规划的,定义是"为组织确定目标、实现目标的战略与手段、步骤、程序的过程。"打个比方说,我想要把一个箱子推倒一个地方,这个地方就是我的目的,我为了到达那里,我是不是要估计一下按什么路线推,要推多快。然后我就开始推,还要不时的和原先的计划比较比较,需不需要调整路线和速度。这个估计就是计划。

  计划的目标不是消除错误,而是让所有错误变成一堆经过细心规划后的小错误。研究四种设计方式后,最终放弃三种,最多不过是三个小错误而已,但因没有做好设计而将程序重写三遍,却可能造成三个大错误。

  然而为什么会出现上面提到的两个极端呢?第一种情况其实是软件行业最早期的一种形态,没有计划,资源分配混乱,软件的开发过程处于混沌、无序、自发的状态。项目的成功全凭运气和项目成员的个人能力。而第二种情况其实一个前进了的形态,最典型的代表就是我们之前提到过的瀑布模型。那这种考虑周密的计划为什么也容易失败呢?很简单,你认为你考虑周密,可是实际上却不一定。我就见过标榜自己考虑周详的计划中排出的时间表是一周7天的。看来他一开始就没打算让开发人员休息了。计划是对未来的一种估计,哪一个人能够准确的说出6个月后的情况,恐怕没人能行吧。9月11号之前,有几个人能料到那天会发生这么大的事情?那你凭什么推算出半年,甚至一年后的事情呢?另外,你是不是真的非常了解你的开发人员,以至于有信心代替他们制定计划呢?

  有人说,计划没有变化快。这句话说得很对,它提醒我们,没有计划是不行的,不具备可执行性的计划也是不行的。计划不是拿来炫耀的,是要用来执行的。我们定计划的时候,可以没有华丽的词藻,美好的构想。但是我们不能没有一些要素:

  ·什么(WHAT):按顺序列出达到目标所需完成的工作;

  ·何时(WHEN):完成工作所需要的时间;

  ·做到的程度(HOW-WELL):要完成的工作以何标准来度量;

  ·资源(RESOURCES):完成工作需要的人员/资金等;

  ·谁(WHO):由谁负责完成任务。

  但是我们仍然逃不开现实和计划的背离的问题。我们虽然对预计一年后的事情把握不大,对把握开发人员在想什么把握也不大。但是如果你自己想想自己两个星期后的事情应该还是能够猜的八九不离十吧。这就引出了迭代的概念。一个项目由几个甚至几十个的迭代周期组成,每个迭代周期都是比较容易估算并制定计划的。这就是迭代的思想,也是软件工程技术的一个大飞跃。说到这里,我又要吊大家的胃口了。关于具体制定迭代计划的讨论,我们会留到下一章节讨论细节需求建模的时候再谈。

  9. 培训

  我很难想象一个项目没有培训该如何进行。兵书有云,"三军未动,粮草先行。"我们可以理解为事先做好充分的准备。项目也是一样,在一开始就要指定好培训的计划,留出培训的时间。我想,除非是一个非常完美的团队,否则他的成员一定也还是有不懂的东西吧,如果没有培训计划,把学习的任务推倒个人头上,项目的风险就会变得难以控制。

  说起培训,大家可能就会认为是大家正儿八经的坐在那里,听一位老师上课。并不是这样的,这里说的培训是一个广义范围的培训,达到一组课程、一次会议,小到一次讨论、一次交流,都可以是培训。而其目的,就是为了让团队成员拥有足够的知识和技能,来完成项目。
文六 细节需求时期(上)


  内容:

  1、细节需求时期和业务建模时期是不同的。

  2、迭代

  3、需求迭代的特殊性

  4、迭代的代价

  5、和其它阶段的关系

  从这一篇开始,我们开始进入细节需求时期。和业务建模时期注重于软件概貌不同的是,细节需求时期讲究充分挖掘涉众的需求,并作为其它的活动的输入。细节需求时期和业务建模时期有着不同的做法,迭代、小版本发布的思想是非常重要的。

  1、细节需求时期和业务建模时期是不同的。

  前面的章节谈了很多业务建模的知识,可以看到整个过程基本上是串在一起的,严格按照软件生命周期模型来说是属于瀑布模型。这里就有问题了,我们在讨论瀑布模型的时候已经用了很多的篇幅来鞭笞它了,这里我们又用回了这个模型,这是不是有点…。这样做的一个很大的原因是业务建模有它的特性。在一些小的项目中,业务建模在软件生命周期中所占比例一般不大,多半是为了了解业务环境的,其中BPA的成分会多一些,BPR的部分通常很少。所以其中如果发生了一些失误的地方,可以在需求阶段弥补。如果是那些诸如ERP的项目,那么业务建模和BPR会有很重要的位置,这个时候,一般要根据具体的情况来制定战略,很难说是采用何种周期模型。而且业务建模一般需要的人手不多,也会安排在项目的早期。所以只要有审查,业务建模采用何种生命周期模型并不是特别重要的。不过这是对于那些特定的项目而言的,对于市场化的产品来说,应该有另外的过程,但这并不在我们的讨论范围内,以后有机会的话再和大家讨论。

  再说需求,需求的生命周期绝对不能按照瀑布模型的来。对程序员来说,最痛恨的一件事情就是需求改变。所以呢,大家想出一种需求凝固的办法,在分析完了需求后,就把它固定起来,写成文档,让客户签字。以后再有需求的增加或改变的话,就拿出这张纸说,"看吧,当时的要求可没有这一项啊。"这种做法的恶果是显而易见的。不过,有些企业则会反驳说,"没有啊,我向来都是视客户为上帝,这种事情我是不会做的,我会让程序员增加这个功能。"可惜的是,这种纵容顾客,伤害程序员的做法更糟。还记得我在听管理学课程的时候的一句话:"员工是最重要的,客户次之。"这是很有道理的,如果你的员工不满意,那么员工直接服务的客户又怎会满意?所以无论是哪一种做法,都只能暂时解决问题,对未来造成的危害却更大。

  需求改变的危害很大,可是不变的需求从来就没有存在过。如果说,过去的社会中,企业的需求能够在一段相对长的时间内保持不变。那么,在现在这个全球化趋势愈来愈明显的社会中,一个不会变化的企业就只有死路一条。

  曾经是大陆霸主的恐龙为什么会灭亡,而当时弱小的哺乳动物却能够存活下来,最大的原因就是面对着瞬息万变的自然环境,恐龙没有办法改变自身来适应环境,而哺乳动物则可以。现在的社会也是一样的。如果你的软件企业所服务的客户一家家歇菜,那你的下场也就可想而知了。所以,很明显的,需求和变化几乎就是同义词。

  2、迭代

  一方面是要求不变,一方面是要求改变。在这种矛盾的环境下,如何才能达到一个平衡点呢。

  在已往的软件开发过程中,多半都要求对未来作出预测。例如,需求要有前瞻性,设计要有可延展性。可是这种做法往往难以实现。现实中的变化何止千万种,你都能做到算无遗策吗?如果你说你在做计划书的时候,可以估算到9月11号可能会发生灾难,那我就没话可说了。

  一个中型以上的项目往往都需要数十人的团队工作半年以上才可能完成。这时候的计划还要加进人这个最不确定的因素。这样,正确的估计简直就是比登天还难。有很多自称考虑周详的计划书,在进度安排时连假期都没有考虑在内。这种计划,定与不定又有什么差别呢?

  我最早接触迭代这个词是从一个朋友那里。他对我说:"自然界中的物体从来就没有以直线形式存在的,螺旋状的物体才是符合规律的,例如DNA。"他这话虽然听起来很玄。但是却很适合放在需求过程中。直线条的需求过程显得干涩,孤立,易断。而有螺旋的(迭代的,增量的)需求过程不论从那一个切面去看,都能够形成比较稳定的形状。

  其实这个道理是很简单的。在我还是个写程序的菜鸟的时候,为了不至于编译时出现一大堆的Error,于是就采用稳扎稳打的方法,写一小段程序除一次bug。而迭代也是这样,是把以前需要一年才能看到结果的过程分成多个小过程,每隔一小段时间就可以看到一定的改进。体现在需求上,以前要一口气做完的需求往往会划分为多个的阶段,每个阶段完成一些功能。这样做有什么好处呢?

  1/人们对较长的未来比较难以估计,但是却可以大致估计出短时间内的未来。这就好比我说不出两年后我是什么样,可如果是两个星期,我就有把握得多。

  2/把一个大目标分割为多个小目标,这样人们能够不断的看到一个个目标被实现,这比长时间的等待大目标的实现要好的多。

  3/客户总是说,我想看看软件才能提出更多的需求。这符合人的本性,应该予以满足。

  4/不断的改进有利与开发人员和客户的合作程度的提高。

  5/迭代的过程可以一定程度上消除原来品保人员等开发人员,开发人员等品保人员的瓶颈现象。

  3、需求迭代的特殊性

  迭代式的需求开发并不是意味着需求开发平均分到各个迭代周期来进行。在理论上,应该是先做完需求分析(还有构架设计),再着手进行各阶段的开发工作。可是实际情况中,需求要保持不变可太难了。根据自身的经验,一个项目,在一开始往往可以完成的需求开发可以占全部需求开发任务的80%(估算的数字)。但是在随后的软件开发中浮现出来的需求(新增或改动)又会有20%。可是这20%的需求是极不稳定的,可能分布在项目中期,也可能分布在项目晚期,甚至可能会在项目在部署阶段才会呈现出来,这些都取决于团队的能力。这样的项目的风险其实是很高的,有些较晚才浮现出来的需求可能会花费大量的资源来实现,如果这需求又对软件架构有影响的话,那后果更是灾难性的。

  在XP中,一个迭代周期会包括多张素材卡片(Story Card),一张素材卡片都代表了系统的一项功能(functionality),这些素材卡片由项目负责人和客户、领域专家按照一定的规则,共同从需求集中抽取,决定在本次迭代中实现。一次迭代经过计划、准备素材卡片、分析、编码实现、测试、构建等步骤,呈现在用户面前的将是一个可以运行(can work)的软件。用户可以清晰的看到软件的界面,软件的使用手册,软件的输出结果。一切都是一览无遗的,不需要任何的叙述性的语句来描述软件,因为用户会自己去感受。接下来,用户的反馈意见被收集,分析,处理,必要的需求改变被安排在随后的某个迭代周期中实现。

  单独的迭代可能是线性的,但是从整体上来看,多个迭代周期形成了一个流水线般的生产方式:

迭代示例
迭代1 迭代2 迭代3 迭代4
准备迭代2 | 构建迭代1 准备迭代3 | 构建迭代2 | 交付迭代1 准备迭代4 | 构建迭代3 | 交付迭代2 准备迭代5 | 构建迭代4 | 交付迭代3


  所以呢,需求迭代的特殊性在于需求的出现并非是迭代的,但是需求的分析和实现则是迭代的。

  4、迭代的代价

  就和计算机中任何的算法都必须寻求空间和时间的平衡一样,迭代方法虽然有其优势,但是同样需要付出代价。

  由于要不断的对软件进行调整,所以软件的架构(Architecture)需要比较稳定,经得起变动。这一点可能在过去比较难,现在的软件架构都相当成熟,都能胜任这种工作。例如J2EE就是一个非常出色的架构。除了架构,系统的框架(Framework)也是非常的重要,框架要足够"软",这个方面虽然没有现成的框架可以利用,但是业界有很多关于这方面的资料,例如设计模式、分析模式。这些都是告诉你一些经验之谈。都是可以参考和采用的。

  多个的发布版本要求开发团队有控制版本的能力。多个的开发版本如果不加控制到最后必然如同洪水猛兽一般可怕,开发人员的时间都浪费在各个版本的统一上。关于版本控制,有很多的软件都能够完成这一工作。对于比较小的团队来说,简单的目录控制可能就足够了。

  上面画出的迭代示意图虽然好看,要实现可没有那么简单,如果功力不足,画虎不成反似犬,原来安排的迭代计划没有严格执行,结果是更加混乱。这时候就要求团队的项目经理有足够的计划能力,以及团队的配合。

  需求变更,并不是所有的需求都一概接受。对于时间所剩无几的项目,一个简单的需求变更都可能是骆驼身上的最后一根稻草。这就要求团队能够有需求变更的管理能力。

  5、和其它阶段的关系

  在进入细节需求之前,千万要先确定系统的架构。国内的程序员很少会专门去思考这个问题,但是会自发的去做这件事情。比如,你是选用微软的DNA,还是J2EE。这就是架构决策的一种。但是我们并没有重视架构的设计。架构方面的欠考虑,会使得架构的涉众蒙受重大的损失。想想看,一家企业想要改变原有的架构,那是需要多大的成本啊。

  由于我们文章的主题是需求,所以架构方面的问题并不在讨论范围之内。但是,请记住,先决定架构,再进入细节需求阶段。当然,这并不是说,进入细节需求阶段就不能改变原先的架构了。原因很简单,亡羊补牢嘛!

  由于细节需求是迭代进行的,所以每一次迭代就像是一个小型的瀑布模型,要经历需求、分析、设计、编码、接受测试、交付等阶段。这样,细节需求实际上是和软件开发过程中的其它阶段紧密相连,其中可能并没有很明显的界限。在下一章中,我们其实可以发现,探究需求活动和其它的活动都是同步进行的。
文七 细节需求时期(下)


  内容:

  ·1、"和其它阶段的关系"的再思考。

  ·2、架构

  ·3、模式

  ·4、简单设计

  ·5、如何统一

  ·6、测试

  ·7、分解

  ·8、客户如何参与

  ·9、小结

  和业务建模时期不同的是,我不再花费笔墨讨论需求要如何做,因为做法、注意点和业务建模时期并没有什么太大的区别。而在完整的流程上,像RUP、XP之类的方法学可比我讲的要好的多。因此,我会把焦点集中在我在实际工作中的一些困惑,以及一些思考。

  1、"和其它阶段的关系"的再思考。

  上一篇的末尾我们简单的讨论了细节需求阶段和其它阶段的关系。对于软件过程的各个阶段,不同之处只是注重的焦点不同而已。在业务建模阶段,我们关注于系统的整体需求;在细节需求阶段,我们更关注于需求的细节部分。其它的阶段也是一样,架构阶段,所关注的当然是如何设计出一个合适的架构;到了设计阶段,注意力就转移到了如何设计方面。

  当然,焦点的不同,导致了各个阶段所需要的技能和工具也不尽相同。业务建模阶段需要你有整体的把握能力,你可以使用简单的用例图,基本的用户素材等工具。细节需求阶段则要求你能够充分的挖掘需求和进行良好的沟通。相应的,在架构、分析、设计等阶段,也会有不同的需要。

  各个阶段的实质就是注重点的不同,这对于大多数的软件开发而言都是一样的。不论你采用的过程是传统的,还是迭代的。

  2、架构

  Martin Fowler在他的ISA中写到:

  I'm using architecture to mean the important design decisions, the ones that shape most aspects of a software system. These are often the harder decisions to change later on in the project (although often not as hard as people think). As a result these are ones where it's useful to start in the right direction, and thus knowing about architecture is a valuable skill for any software developer.

  架构并不神秘,无非是一个决策而已,只是这项决策对软件特别重要就是了。软件开发人员可能根本没有主动的进行架构设计,但是他的行为,已经潜移默化的进行了;而还有一些人,总在谈论着架构,但是并不了解这个词的含义。

  春运就要到了,学生也要赶着回家。如何选择回家的交通工具就是一个重要的决策。路程的远近、不同交通工具的价格都是显式的,比较容易知道的。而以往的经验也告诉你,火车票比较便宜,但是比较紧张,花费时间较长,整个过程也不舒服;飞机票比较贵,但是容易买到,花费时间少,整个过程很舒服。这时候你就要做出正确的决策,为回家选择一个正确的架构。你可能考虑的因素有哪一些?以下就列出了一些可能的因素:

    ·拥挤程度,大家都知道春运时那种情况;

    ·购买票的难易程度,火车票需要很早就要预定了;

    ·是否有额外的渠道,比如你能够买到飞机的学生票;

    ·经济实力,经过了一个学期的花销之后,现在还剩多少生活费;

  根据这些因素,以及这些因素对你的影响程度,即优先级,你可以自己估算出一个或几个可能的架构方案。而这种架构的选择,直接影响到你之后的行为,也影响到行为的结果。

  开发软件和买票回家又能有什么区别呢?一样要考虑成本、结果、时间。所不同的只是复杂了:需要专业技能,有很多不确定的因素。

  那么我这里谈论架构的问题,和需求有什么关系呢?在上面的例子中,大家可以看到架构是根据什么决定的?是因素。因素的本质是什么?就是需求。因素,就是需求。所以,需求决定架构。上一篇中,我谈到说,在进行细节需求之前,一定要定出架构。当然,这时的架构可能只是一张草图。为什么?因为我们已经进行了业务建模,对项目有了一定的认识,对用户的需求也有一定的把握,成本、范围、时间等要素也都清楚了(如果你还不了解这些,请你回到业务建模阶段,你的工作还没有结束)。这个时候,决定架构的因素已经形成了,可以进行架构的设计了。

  需求能够决定架构,架构反过来也能够影响需求。最明显的一个例子就是用户界面的设计。虽然用户界面主要来自于需求,但是不同的架构对用户界面也会有影响,例如基于浏览器的客户端,和基于Windows界面客户端能够提供的界面就不同。

  在XP中,这种的架构设计,被称为Architecture Spike。为什么叫做Spike呢?就是说你需要专研,解决一些主要的问题,但你并不是提供一个完整的解决方案。例如,在项目的初期,如果你对新近的服务器和操作系统不了解,你肯定会花时间去了解,去试用,去测试;如果对数据库不了解,你也肯定会试着使用看看。这种行为,就是Spike。所以呢,架构的设计只是很初步的设计,而不是一个完善、定型了的设计。这一点要注意。

  架构的选择和开发人员的经验和能力非常有关系。一般来说,它需要开发人员具有相关的经验。提供架构的厂商多如牛毛,如何选择,也是一项学问。比如,数据仓库的平台,选择的品种就很多;而Web Server的选择也是五花八门;操作系统也是一样。这些又都是和架构息息相关的。

  3、模式

  武功有招式,下棋有棋谱。不论是招式,还是棋谱,都是针对某一种问题的特定解决方案。在软件开发领域,这种解决方案就被称为模式。

  "每一个模式描述了一个在我们周围不断重复发生的问题,以及该问题的解决方案的核心,这样,你就能一次又一次的使用该方案而不必做重复的劳动"[AIS,77]

  这句话源自模式的鼻祖――Christopher Alexander。而在软件开发领域,最值得一提的著作,就是GoF写的『设计模式』一书。在该书中,作者描述了23种的设计模式,可以说,这些模式奠定了面向对象设计的基础。而另一本值得阅读的著作,就是Martin Fowler所著的『分析模式』。

  在软件设计中,我们遇到各种各样的问题,我们可能缺乏经验,或能力有限。这非常的正常。但是现实是,我们生产出的代码由于设计方面的缺陷,往往不够清晰,容易出错,难以扩展。相信只要是开发过软件的人,都遇到过这种问题。于是,我们就希望能够看看其他人,是如何处理这种问题的。这里的"其他人"指的可能是技术专家,也可能是经历过同种问题的人,他们对你遇到的问题有能力,有经验来解决。他们提出的解决方案往往是非常成熟的,能够解决你目前遇到的问题,也能够解决你目前尚未遇到的问题。

  这对你的吸引力是很大的。那么,我们谈论模式,模式来源于何处呢。注意,模式是针对某一类的问题的解。这里的问题,所指的就是需求。比如说,客户希望能够在软件中实现不同的税率计算方法,那么,我们很自然的就可以想到Strategy模式;当客户的产品有一个很复杂的单位换算机制的之后,我们也能够很自然的想到Quantity模式。使用模式,能够使我们迅速的把握需求的解决方法。另一方面,模式往往告诉我们比目前的问题更多的方面,因为模式都是大家的经验沉淀。如上所说,它还可以解决你目前没有遇到的问题。因此,我们还可以从模式中发现出更深的需求。

  另外一点也很重要,虽然它和需求的关系不大。模式往往都有一个模式名称。这就形成了一种沟通的语言。比如我们在下象棋的时候,只要说"马后炮",谁都知道这是什么意思,绝对不需要呢详细的解说每一步棋子的走法。对于软件开发也是一样的。我和我的同伴会心的一笑,说:"Factory Method。"两个人都能够理解这是什么意思,因为这是一种共通的语言,它代表了背后隐藏的各种类的关系和代码实现。这在软件开发中非常的重要。当然,这有个前提,大家都对模式有一个通透的了解。

  4、简单设计

  模式属于设计的一环,所以前面我们讨论的其实就是设计和需求的关系。这一小节我们还是讨论这个话题。但是侧重点有所不同。XP中有一个原则:KISS。不是kiss哦。它是Keep it simple and stupid的缩写。除了XP,其它的敏捷方法都提倡简单设计,反对过分设计(over build)。也就是说,针对目前的需求,设计目前的软件。

  很多的软件人员都是完美主义者,他们喜欢完美的设计,然后把这种设计提供给用户。这种思想就是过分设计的开始。不必要的功能浪费了客户的投资。我们在做需求的时候,很经常发现开发人员随意的向客户推销一些新功能,或是在设计时,过多的考虑未来可能出现的需求变动。

  所以,简单设计的意思,就是要针对目前客户提出的需求进行设计,不要过多的考虑目前没有提到的功能。

  5、如何统一

  细心的读者看到这里可能已经是疑窦丛生了。一边是鼓励使用、设计最完美的方案;另一方面,又强调简单。似乎是自我矛盾。不错这其中是由矛盾的地方,但也有一致的地方。因此,在使用先进的模式和保持设计的简单性之间,我们需要权衡。

  一次,我们看到了一个关于权限设置的模式,我们觉得这个模式非常的好,它提供了类似于UNIX操作系统那样的权限控制,可以很随意的增加组、用户,并能够在文件级别上设置权限。我们如获至宝,觉得这是一个非常有用的模式。于是,我们花了一些时间将之实现,并打算应用于新的软件中。

  在实际中,我们发现没有一个用户需要如此强大的功能,他们所需要的可能仅是密码控制,或是简单的用户管理。如此复杂的功能对他们来说没有任何的意义。完美的模式在现实中遭到了冷遇。

  实际上,用户目前不需要这项功能,并不意味着他以后不需要这项功能。用户的计算机程度提高的很快,我们估计,再过那么一两年,用户可能就非常需要这项功能来管理他那日益庞大的员工队伍了。但是目前,这项功能对用户来说,设置复杂,所以他们并不愿意接受这个"有价值"的功能。

  最后,我们想到了一个解决的办法,我们为这一项功能定义了一个通用的接口。通过这个接口,你可以实现复杂的功能,也可以实现简单的功能。总之,你只要是实现了接口的方法就行了。接口的方法很多,但是在目前的简单的实现中,可能就仅仅是一个返回语句,并没有很多的实现。相应的,用户的也仅仅需要使用简单的方法,诸如addUser(),updatePasswd()等。界面也做了简化的处理。

  通过这种方法,我们可以在用户需要的时候,替换掉权限模块,对其它的应用并不影响。当然,其中有很多的细节需要注意。在完成之后,我们还发现了另一个副产品:整个的权限控制模块是高内聚,低耦合的。

  模式,就好比螺帽的设计图纸,它规定了螺帽的技术规格,但是没有规定具体的尺寸。对应于不同的需要,我们可以设计出不同大小的螺帽以供使用。图纸只需要一份就可以了,并不需要为每一种尺寸的螺帽画一张图纸。

  因此呢,一个经历了实践检验的模式,往往功能强大。但是它可以有多种不同的实现。有哪一条法律规定你必须完全的实现一种模式呢。在实际使用中,你需要权衡模式使用的成本和效益。你会发现,在很多情况下,你还是实现了模式,但只是模式的一个框架,或一部分,但是这在目前就够用了。而当需求变动,或新的需求出现的时候,你可以很方便的在原有搭起的框架上添砖加瓦。一切都是那么的自然。比如,在一个进销存的软件中,存在一个运输选择算法,目前的运输途径就一种,但是很有可能会增加新的途径。这时候,你就决定采用Strategy模式。但是你只是实现了一个简单的框架,只有一个具体子类,来实现目前的算法。当新的运输途径出现时,你需要增加一个算法,你就可以再增加一个子类,只要实现的接口相同,改动是不会影响到系统其它的部分的。

  6、测试

  测试是非常重要的,是软件成败的关键。但是目前国内对测试并不关注,或是假装关注。这样就无法保证软件的质量。测试有很多种,我们这里要说的是和需求息息相关的测试,就是接收测试(Acceptance Test)(关于这个词,可能不同的文章会有不同的译法)。

  Surely you aren't going to assume you're getting what you need. Prove that it works! Acceptance tests allow the customer to know when the system works, and tell the programmers what needs to be done.

  上面这段话摘自『XPInstalled』。接收测试有两个作用:首先是让客户明白系统能够做什么,然后是让程序员明白该让系统做些什么。

  有一种测试的方法是把测试留到最后才做,让客户去发现错误。千万别这么做。原先花费1块钱就可以改正的错误,到了这个时候,可能需要花费1000块钱才能解决。这是软件开发的放大效应。因为很多的工作已经基于这个错误建立了,开发人员也已经对这个错误没有映像了。

  XP中有一个很重要的价值,叫做反馈(Feedback)。Kent Beck在Extreme Programming Explained中有句话讲得非常好:"乐观是编程的职业病,反馈则是其处方。"从需求的识别,到根据需求构建的系统交付给客户,客户提出意见。这就是一个反馈过程。反馈过程所花费的时间越少越好。接受测试就是解决客户反馈的一个有效的手段。客户编写可重复的测试脚本,开发人员开发出的软件要经受这个测试脚本的考验。这种的反馈速度是很高的,能够有效的解决反馈的问题。

  因此,客户在要求实现需求时,同时也有义务提供相关的接收测试:

  if it's worth having the programmers build it, it's worth knowing that they got it right.

  一个有价值的功能一定是可测试的,如果不是,那么这个功能要么是没有价值,要么是尚未描述清楚。

  要注意,这个测试必须是可重复的。这是因为需求的易变性。需求在不断变化,这就意味着代码在不断的变化。因此,原先已经用接收测试证明过了的代码还需要再次证明。这就要求测试是可以重复的。

  大量的测试,甚至重复的测试引出了一个新的问题:全凭手工进行测试会浪费大量的时间。因此,易变的需求对测试提出了一个新的要求:自动化测试。只有自动化的进行测试,才可以完成如此大量的测试工作。目前,最好的自动化测试工具,应该就是Xunit系列。关于这方面的问题,大家可以参考相关的资料,这里我们不作深入的讨论。

  接收测试最可能的一种形式就是自然语言的说明,外带一组的测试数据。需要强调的一点是,这个测试数据一定要包括输入和输出。这样才可以做出比较。如果只有输入没有输出。测试很可能就是白费劲。所以,计算这个输出是手工计算的,它也是必要的。

  除了接收测试,还有一个很重要的概念就是单元测试(Unit Test)。但是单元测试和设计的关系比较大,和需求没有过多的关系,我们这里就只是点一下。大家如有兴趣,可以参考相关的资料。

  7、分解    

  对于需求来说,需要用到的最多的技能可能就是分解的技能了。可以说软件科学最重要的思想就是"分而治之"的思想。不是吗?面向对象是不是一种分解的思想。类、组件、包,这种层级结构不正是体现了"分而治之"吗?当然我这里可能把包和组件弄混淆了。但我的主要目的是要指出这种分解的方法在软件开发中是无处不在的。对于需求也是一样。我们最早做的业务建模就是为了得到一个系统的概貌图。然后到了细节需求阶段,我们会把这张图放大,细分,一直到我们有把握处理为止。

  如何把100块砖累起来呢?如果一块一块的累,那很容易就倒了。一种比较好的做法,就是先10块10块的打包,这样,100块砖就变成了10个砖包,再把它们累起来就容易的多了。面向对象其实就是这么做的,当然,面向对象的实现比累砖要难多了。

  我们看看XP中是如何处理分解的。XP中最大的周期叫做发布版(release),一个发布版需要一个月或几个月的时间,一般不超过6个月。发布版的末期,需要向客户提供一个可以运行的软件的发布版。然后,XP还定义了次级的周期,称为迭代(iteration),一次的迭代大概需要一周或几周的时间。每一次的迭代都是一个"伪发布版"(pretend release),就是说,迭代的最后也必需要提供一个可以工作的软件,这个软件随时都可以发布。为了定义一次迭代中要处理的事情,XP还定义了素材(story),一份素材代表了客户希望在软件中出现的一项功能(feature),一份素材是很小的,它只需要花费一个开发人员几天或几周的时间。素材已经很小了,但是还需要细分到任务(task),一项任务只需要1到4天的工作量。这并不是最小的单位,XP还把任务划分到测试(test),但这已经到个人级别上了。

  我们看到,XP从客户到每一个开发人员,定义了5级的单位,并把时间精确到了天、小时。所以我有时候听人说,XP好像对开发人员的要求不严格。错了,XP可以说是目前要求最为严格的方法,这种分类方法可见一斑。这种分类有什么好处呢?

  首先,我们来看发布版,发布版的最短时间是一个月,也就是说,最频繁是一个月向客户交付一次软件。这样,就在很大程度上保证了反馈的迅速进行。避免了传统的开发方法中最后客户发现问题时已经太迟了的现象。

  再看迭代,迭代之所以被称为伪发布版,就是因为它的产出物的性质和发布版是一样的。都是可以交付的产品,但是迭代的功能比较少,没有必要交付给客户。我们知道,在传统的软件开发中,整合是一个大问题。整合必然会出现问题,但是没人知道问题在哪儿。所以呢,XP通过不间断的整合,避免了这个问题。

  但是,迭代的周期如此之短,能够做些什么呢。这就是素材出现的原因。素材由客户提出,由客户决定优先级,由客户决定放在哪一次的发布版和迭代中。同时,如上面我们谈到的,客户需要为素材制定接收测试。

  一份素材的周期是几天或几周,而一次迭代的时间也就几周。这说明素材对迭代而言,单位过大了。所以要把素材再次分解为任务。每一个任务都需要一个开发人员认领,签字。在分解素材的过程中,我们可以发现有一些任务是多个素材共享的,这个概念和用例中的使用的概念是一致的。开发人员会估计自己的任务所需要的时间。从而得出一个迭代周期的总时间。这个时间的估计是基于以往的经验的,因此随着项目的进行,这个估计往往会越发的准确。

  我们这里讲XP的分解哲学,并不是要求大家也依样画葫芦,你真要那样做也不行。因为XP的各项实践都是一体的,只有实现了所有的实践,才能体现其威力。我们这样断章取义是行不通的。但是其中的思想我们是可以借用的。分解、归类、排序、估计。这种分析问题的方法,也是我们值得借鉴的。这里有几点要注意:

  ·最早的分解依据往往是客户要求的时间。例如,客户希望在3个月内看到什么什么。在客户和开发放商议之后,决定制定两次的发布版。这个决定虽然开发方可以提供参考意见,但是决定权在客户方;

  ·素材的提出,素材的优先级,素材的安排,这些都是客户的权利。客户也有权利取消、增加、修改素材,或是改变其优先级;

  ·客户投入多少,就能够看到多少的软件。客户也可以取消目前的项目,而且,先前的投资也会有相应部分的软件产出;

  ·对于开发时间的估计是开发人员的权力,其它任何强加于开发人员的时间安排都是不对的;

  ·任务的选择也是出于开发人员自愿的原则;

  ·如果开发人员估计出的总的时间和迭代的预计的时间有出入,绝对不能牺牲开发人员的额外时间换取迭代在限定时间内完成。这种做法无异于饮鸩止渴。比较好的做法是去掉一些任务。

  8、客户如何参与

  这是一个纯粹的补充问题。一次,一位读者写信来问我,中国的客户素质比较低,对计算机不了解,XP强调的现场客户现实中根本做不到。

  XP要求开发人员在开发软件的过程中随时予以支持。诚然,要做到这一点是很难的。我自己也遇到过这种难题,知道问题的棘手程度。我想,这个问题可以分为两个方面。

  一种是定制的软件。对于这种项目,你需要解决用户的参与问题,往往客户方的老总愿意投入资金,但是却不愿意投入支持的人力。我也曾见过客户方专门招了一个应届生来对付需求的情况。遇到这种情况,如果你没有能力克服它,那么这个项目绝对是失败的。即便项目最后成功了,申请了什么"重大攻关"之类的奖项,你我都很清楚,这只不过是表面功夫而已。造成这种问题的原因有很多,你需要分析它们,列举出最深层的原因,并且保证列出的这些原因之间并不会相互影响。然后再试着来解决它。一般而言,如果客户方是真正愿意实现这个软件的话,事情并不是不可解决的。

  另一种是产品化的软件。我们可以把这种软件的客户分为三类:市场人员、领域专家、最终用户。市场人员往往对软件有最初的认识,但是这种认识往往不够深入。所以,在开发产品化的软件时,一定要配备专门的市场人员,他们对客户的需求最了解,是需求的第一手来源。既然你的老板想要开发这个软件,说明对软件的未来市场有期待,市场人员加入的要求应该是可以得到满足的。其次是领域专家,现在很多的软件公司都配备有领域专家,他们的作用可不小,和市场人员相比,他们也同样熟悉需求,因为他们自己就是资深的用户,并且他们还熟悉理论,能够为软件开发出大力气。最后是最终用户,前面的两类人的参与还不够,如果最终用户不认可软件,那还是没有用。所以,要求市场人员找寻可能的目标客户,试用软件,提出意见,是非常重要的。我们常说的Beta测试也就是这样做的。

  9、结语

  最早这片文章的想法是来自于一个信贷系统(以文章的观点来看,这个系统是一个失败的案例)。除此之外,还加上了一些以前的项目的经验,以及朋友的一些经验。最后综合成了这一篇文章。

  这个系列的文章的写作时间的跨度很长。在这个期间,我的思想也经历一个很大的转变,所以在写作中也出现过对已经完稿的部分大肆删修的情况。这篇文章虽名为『需求的实践』,但所提到的各种想法、方法,都有理论的依据。当然也是参考了很多的资料。而我个人的能力又极为有限,所以有些时候是心有余而力不足。在这样的情形下,文章难免会出现很多的错误。还希望能得到读者们的谅解和指正。

  在写作的过程中,也有很多的热心人写来信件,其中好些还成为了好朋友。曾经想把里面的问题整理出来,但是由于疏忽,其中的一部分已经找不到了。希望还能有机会做这件事情。



参考资料:


  Karl Wieger:《Software Requirements》

  Scott W. Ambler: AgileModeling: http://www.agilemodeling.com

  Scott W. Ambler: The Object Primer 2nd Edition

  Jacobson, I., Booch, G., and Rumbaugh, J. (1999). The Unified Software Development Process

  GOF:《Design Patterns: Elements of Reusable Object Oriented Software》

  Eric Gamma, Kent Beck: Junit: http://www.junit.org

  Kent Beck,Martin Fowler:《Planning Extreme Programming》



作者简介:


  林星,辰讯软件工作室项目管理组资深项目经理,有多年项目实施经验。辰讯软件工作室致力于先进软件思想、软件技术的应用,主要的研究方向在于软件过程思想、Linux集群技术、OO技术和软件工厂模式。您可以通过电子邮件 iamlinx@21cn.com 和他联系。

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