我们应当怎样做需求分析:行动图和状态图
前面,我们耗费了大量的篇幅来讨论用例分析及用例图。用例图,无疑是功能分析、角色分析,以及流程分析的利器,它将我们要开发的系统,清晰而详尽地描述出来。但是,正如任何事物都有两面性,用例图也不例外,也有自己不利的一面。在我看来,这集中体现在两个方面:只见树木不见森林、不生动形象。
什么叫“只见树木不见森林”呢?就是说,用例说明中对业务流程的描述,过早地将系统的整体流程,分散到了各个用例中了,丢失了对业务流程的整体描述。不生动形象,则是说用例说明中对流程的描述都是用枯燥无味的文字来表述的,缺乏生动形象的图形表示。针对这些不足,UML的另外两种视图,可以有效地弥补用例图的缺陷。它们就是行动图与状态图。
行动图(Active Diagram),比较类似于我们过去绘制的流程图,是UML中描述流程与分支的视图。在行动图中,往往是从一个实心圆的起始节点开始的。最频繁使用的则是活动节点了,它表示的是业务流程中的一项活动。活动节点可以表述为一个活动短语(如下订单),可以表述为一个表达式(如len=a.length+x),还可以表述为一个消息(如send(msg))。同时,将各个活动节点连接起来的一个个实线箭头,表明了各种活动之间的流转顺序。
在各种业务流程中,毫无疑问会有许多的分支。在行动图中,分支用一个菱形来表示。一个指向菱形的箭头,表示流程进入分支,另外两个或多个从菱形伸出的箭头,则表示不同条件下的分支流。而菱形本身,则表示为一个条件判断语句。
另外,业务中的各个流程还会分岔与汇合的情况。分岔,表示在某个时间点上,同时开始两个业务流程,这两个业务流程是同步进行的。分岔用一个入箭头,一根横杠,与两个出箭头表示。汇合,则表示,只有在两个流程都完成的情况下,才会进入下一流程,否则只能等待。
汇合则用两个入箭头,一根横杠,与一个出箭头表示。
最后,用一个或多个带环的实心圆,表示的是活动图的终止节点,代表了业务流程的终结。以上这些元素,就组成了一个基本的活动图。然而,基本的活动图还不能完整的反映我们的业务流程,因此我们还需要在基本活动图的基础上增加元素。现在我们来看看泳道与业务对象流。
如图就是一个带泳道的活动图,图中每个泳道代表一个参与者的业务操作,而整个图形表述了多个参与者间的协作过程。起初我比较爱绘制这样的活动图,但后来常常感到绘制泳道是一件比较繁琐的事情。既然如此,我们就改改吧。
这张图才是我最爱使用的行动图。图中,将参与者由繁琐的泳道改为了用例图中的小人。同时,在这张图中还增加了对象流与对象。图中,自动考核结果、申辩申请单、调整后考核结果,都是数据对象,是该流程中相关环节操作的结果。从活动节点指向对象的虚线箭头,则表示了一个对象流,如“申辩申请”活动指向“申辩申请单”的虚线箭头,表示了申辩申请活动的最终结果是产生申辩申请单;从“调整后考核结果”指向“过错追究”的虚线箭头,表示过错追究活动读取了调整后考核结果。
当然,活动图还有其它的元素,但我个人认为其实并不实用,使用以上元素就足以表述我们的业务流程了。活动图打破了子系统与子系统的壁垒、用例与用例的壁垒,使我们能够从整体上了解整个系统的流程,因此常常使用在对整个系统的概述、对整个子系统的概述,以及对整个功能模块的概述中。同时,与其它视图一样,活动图也应当有它的文字说明,以便对图中的每个活动节点、分支进行描述。但对于一些流程相对简单,甚至没有什么流程的查询报表类功能模块,绘制它们的活动图则显得有些牵强附会,因此我们要灵活掌握。
除了活动图,我们似乎对需求的描述还缺少点儿什么,那就是对关键对象中流程中状态变化的描述,在这种情况下,我们的状态图就上场了。
在使用状态图时,一个非常关键的概念就是,一定是对某个关键对象的状态变化的描述,而这些状态变化一定是在某个业务流程的大背景下进行的。下图是一个疑点数据整个生命周期的状态变化图。图中,与行动图一样,一个实心圆点代表的是流程的开始,圆边的方框代表的是对象生命周期中的各个状态,状态节点间的实线箭头代表的是状态的切换,箭头的文字描述是触发状态切换的事件。与行动图一样,状态图可以有分支、分岔、汇合,并最后以一个或多个带环的实心圆结束,代表对象生命周期的终结。
在需求分析中,状态图并不是必须的,它仅仅出现在你认为需要对某个对象的状态进行说明的时候。
我们应当怎样做需求分析:业务领域分析
在需求分析工作中,最后一项分析工作就是业务领域分析啦。业务领域分析,就是对需求分析中涉及到的业务实体,以及它们相互之间关联关系的分析。前面我们谈到了功能角色分析,或者说用例分析,它是从整体的角度对整个系统人机交互的分析与整理。随后我们谈到了业务流程分析,它是在对系统人机交互的分析与整理的基础上,更加细致的去分析和整理那些业务流程,以及组成这些流程的一个个业务操作。业务流程分析是对系统进行的一种动态的分析,分析的是那些行为,那些操作。但是,所有的行为,所有的操作,最终施与的对象都是那些实体。这句话怎么理解呢?比如,我们执行填写操作,施与的对象必然是那些表单,最终产生的结果必然是形成一份完整的表单,表单就是那个行为施与的对象。再比如,我们执行查询操作,施与的对象必然是一个报表,最终产生的结果必然是查看到了这个报表的结果。这里的表单、报表,都是存在于系统的静态实体,它们中的大多数也最终以数据结构的形式持久化保存于系统的数据库中。因此,系统中应当有哪些实体,这些实体都有哪些属性,被赋予了哪些行为,它们之间的相互关系是怎样的,就成为了业务领域分析的重要内容,而业务领域分析也就成为了对系统进行的一种静态分析。
我们的软件系统,毫不夸张地说,就是对现实世界的真实模拟。现实世界中的事物,在软件世界中就被模拟成一个对象。该事物在现实世界中赋予什么职责,在软件世界中就赋予什么职责;在现实世界中拥有什么特性,在软件世界中就拥有什么属性;在现实世界中拥有什么行为,在软件世界中就拥有什么函数;在现实世界中与哪些事物存在怎样的关系,在软件世界中就应当与它们发生怎样的关联。这正是面向对象编程的核心思想。
我们进行业务领域分析,就是基于这样一个思想进行的。什么叫业务领域,就是客户所在的知识领域,譬如财务人员所在的是财务领域,税务人员所在的是税务领域,营销人员所在的是销售领域。不同的知识领域拥有各自不同的领域知识,需求分析人员就应该通过客户中的领域专家去学习这些知识、掌握这些要点,并最终体现在我们的需求分析中。然而,这必然是一个长期的过程。从这个角度说,业务领域分析不仅出现在需求分析阶段,还应当贯穿与设计阶段、开发阶段、测试阶段,甚至延续到后期的维护与升级。从另一个角度讲,现在的软件研发概念,已经不再是一锤子的买卖,而是延续到数年的不断升级完善中了。而软件的升级完善,从本质上说就是对业务领域不断深入的认识。我们对业务领域的认识深入一点儿,我们的软件系统就完善一分,再深入一点儿,就再完善一分。这就是世界级软件分析大师Eric Evans提出的领域驱动设计的核心思想。
因此,我们进行业务领域分析,就是通过与用户进行交流,掌握领域知识,然后绘制成业务领域模型,去指导我们软件开发的过程。日后我们去设计开发系统时,应当设计哪些类,类中都应当有什么属性和行为,以及怎样去设计数据库,都是以这个领域模型为基础的,虽然有时并不完全与领域模型完全一致。过去,没有一个切实可行的方法来指导我们的业务领域分析,而现在,我们可以通过两种分析方法一步步进行:原文分析法与领域驱动设计。随后,我们将就这两种方式进行详细分析。
我们应当怎样做需求分析:原文分析法
原文分析法(Textual Analysis),是在用例说明与流程分析的基础上进行的业务领域分析,是一项在需求研讨会后整理和分析需求的工作。当我们完成了用例图的绘制,为每个用例编写出用例说明以后,原文分析的工作就可以开始了。要讲解原文分析,我们还是用一个实例更简单明了:
这是一个实际项目的用例说明。在进行原文分析的时候,我们首先要做的事情就是对用例说明中事件流部分的文字描述,提取其中的名词。在这个实例中都有些什么名词呢?这些名词我在用例中用蓝色标注了出来,经过整理就是这些:触发器、考核指标(简称指标)、执法行为、指标定义、过错标准(过错判断标准)、过错行为、考核结果、年度、月份、机关、分子数、分母数、过错数、正确率。
领域模型中的实体,往往就在我们通过原文分析提取出来的这些名词中,但需要我们进行进一步分析。并不是所有名词都可以成为实体,那么哪些可以呢,而哪些又不能呢?首先,系统外的参与者不能。系统外的参与者是触发本系统某个事件的人或者物,但它本身存在于系统之外,比如用户使用鼠标点击了一个按钮,而领域模型是描述系统之内的事物,因此系统外的参与者应当被排除。本例中的触发器就是系统外的参与者(参见《功能角色分析与用例图》),它应当被排除。
其次,系统之内的事物转化到领域模型中,可能会变成两种东西:实体与实体中的属性。什么变成实体而什么变成实体中的属性呢?自身有自己的属性,可以成为系统中行为的执行者或施与者的,才是实体。比如考核指标就是实体,因为它有它的考核标准、过错行为、分子数、分母数、过错数、正确率等属性,它在系统中会去执行考核,所以是实体;分子数是不是实体呢?它仅仅是一个数据,没有自己的属性和方法。另一个判断是实体还是属性的方法就是判断它将如何持久化。如果一个事物被持久化到数据库中时是一个表,则是一个实体;如果仅仅是表中的一个字段,则是一个属性。
然而,是实体还是属性并不是那么绝对,关键看系统对这个事物进行怎样的处理。比如过错标准是一个实体还是一个属性呢?如果我们在系统中仅仅是一个文字描述则是考核指标中的一个属性,如果需要对它进行分解,有它的判断公式,需要让它去执行判断,则应当是一个实体。在需求分析的初期,可以先将其设计成一个属性,待日后的细化阶段再进行调整。
另外一个非常重要、值得我们着重关注的地方是名词的多义性。在本例中,我们考察一下“过错行为”这个名词。“一种过错行为”与“一个过错行为”显然不是一个概念。“一种过错行为”代表的是一种类型,有它的过错定义与判断标准;“一个过错行为”则代表的是一个实例,一个执法行为中的某个错误的行为。正因为它们概念上的差异,我们在领域模型中将其分为“过错类型”与“过错行为”。
经过一番分析,我们绘制出了一个基本的领域模型。毫无疑问,这个领域模型使用的是一个类图,实体在图中就是一个个的类。同时,我们将各个类之间的关系标注出来:一对一、一对多、多对多、聚集、组合、继承,等等。为了提高模型的可读性,我们在必要时可以标注关系的名称。如考核指标与执法行为之间是类型与实例的关系,等等。
现在,让我们重新回到原文分析。这次要分析的不是用例说明中的名词,而是动词,在本例中我用红色标注出来。最后,我们整理出这些动词:触发、执行考核、预警、采集、判断、是过错、是正确、打分、统计。
对用例说明中的动词分析,是为了定义各个实体之间的各种行为。同样,并不是所有动词都是实体的行为。参与者的行为显然不是实体的行为,应该被排除掉,如:实例中的“触发”。还有一些动词是某个行为的一个细节,如:“是过错”、“是正确”,被合并到“过错判断”中。最后,将行为添加到行为的执行者中。最后绘制出这样一个领域模型:
领域模型有别于后期的分析模型,其中最关键的就是目的,它的目的仅仅是分析需求,因此在很多地方会比较模糊而不考虑技术实现,比如本例中的“指标定义”、“过错标准”。另外一个比较关键的地方就是,系统中的行为到底由谁来执行,这个标准常常是说起来容易做起来难。我给大家的建议是参考GRASP中的“信息专家”模式。
GRASP是一种职责驱动设计的系统分析方法,它的“信息专家”模式是这样描述的:应当将系统中的行为交给信息专家去执行,而信息专家就是掌握着执行该行为所需数据的实体。在本例中,由于考核指标掌握着指标的定义,还有那些执法行为,所以它可以执行考核,而过错类型则掌握着过错标准,因此可以执行过错的判断。注意,这里的“执行”什么行为,是软件意义上的概念,即一个类可以拥有什么行为,而非现实世界的概念。要知道现实世界中的事物是不可能有主动执行什么操作的能力的。
过去我们拿到需求不知道该怎样去业务领域分析。有了原文分析方法,给了我们一个简单可行、易于操作的方法,让我们准确而高效地完成业务领域分析。
我们应当怎样做需求分析:领域驱动设计
2007年,世界级的软件分析大师Eric Evans发表了他的经典著作《领域驱动设计》,进而形成了一套独特的软件分析与设计方法,简称为DDD(Domain-Driven Design)。在领域驱动设计思想中,有许多是涉及到需求分析领域的先进方法,我把它归纳为有效建模、统一语言和持续学习。
有人说:大师所站的高度实在太高了,是生活在太空里的,所以我们要追随大师就只有因为缺氧而死掉。我认为这句话说得非常生动,学习大师真的不是一件容易的事,把大师的思想落实到我们的工作中更难,常常还伴随着一些不小的风险,学习伊大师也是一样的。
伊大师一上来就提出了要有效建模的思想,我当时立马就晕菜了。按照这个思想,我们应当在业务研讨会上,与客户讨论业务需求的时候就开始现场建模了。这!怎么可能呢?客户看得懂那些专业的、抽象的模型吗?我们能拿着模型与客户交流吗?这是不是在浪费时间?
的确,伊大师提出了有效建模思想,与其它很多诸如在会后分析整理时进行的原文分析方法大相径庭。同时,这个思想认为,我们应当与客户代表形成一种统一的语言,一种混合语言。这种语言,既有软件技术中的元素,又有业务领域中的术语,同时,它又是技术人员与业务人员都能理解的语言。使用这个语言,技术人员与业务人员就是在用同一语言在沟通与讨论问题,这种沟通的障碍就得以消除。
道理简单实践难,什么是有效的建模,什么是统一的语言呢?经过无数的实践与尝试,我逐渐开始明白了。首先,什么是有效的建模呢?当我们作为非专业人员去看一个建筑设计师绘制的图纸时,我们一看就明白这是一栋楼房,那是一座桥梁,为什么?因为图纸形象生动,没有那么多专业术语,我们一看就明白了。软件中的设计图也是一样的道理。
当我们站在技术人员的视角去绘制设计图时,客户必然看不懂,因为图中使用的都是专业的术语、专业的符号,表达的都是专业的设计思想。反过来,如果我们站在业务人员的视角去绘制设计图时,情况就不一样了。如果一个用例图,图中的功能都是客户日常经常做的业务操作,并且命名都是业务人员能够理解的业务术语,试问客户会不理解吗?同样,在领域模型中,我们按照客户的思路,运用客户的术语,去绘制一个一个的对象,按照他们的思路去描绘对象间的关系,描绘对象间的操作,他们真的就会看不明白吗?这说得似乎有一些抽象,我们举一个实际的例子吧。
有一次,我与客户在讨论一个考核系统,首先客户描述着他们的需求:
客户:我们这个考核系统是由许多个考核指标组成的,每个考核指标就标志着我们的某项工作的完成情况。每个考核指标中有一个分母数,标志某段时间所有应当完成的工作数量,有一个分子数,标志这段时间正确完成的工作数量,最后还有一个过错数,标志那些错误的,或者没有按时完成的工作数量。
需求人员:为什么是分子分母?
客户:因为最后要计算正确率,用正确率来考核一个单位完成工作的情况。
这样,我们在纸上绘制出一个考核指标,在属性中写下分母数、分子数、过错数、正确率。
需求人员:那么每个考核指标都有一个过错判断标准了?
客户:当然啦,每个考核指标都有它的过错判断标准。一个考核指标可能会有多个过错行为,每一个过错行为都有各自的过错判断标准,任何一个过错了,这个执法行为就算过错啦。
需求人员:先等等,你刚才提到执法行为了。执法行为和考核指标是什么关系?
客户:哦,执法行为嘛,就是执法人员对某个用户执行的一次业务操作。考核指标中的分母数就是所有执法行为的个数;分子数就是正确的执法个数;过错数就是错误的执法个数。
这样,我们就绘制出这样一个草图:
客户看了这个草图有些不同明白:过错类型是什么东西?
需求人员:过错类型就是某种类型的过错行为呀,它定义了某种过错行为,有它的过错判断标准。下面这个过错行为就是那些具体的过错,比如张三今天犯了什么错,李四明天犯了什么错。
客户:哦,明白。这两个箭头怎么跟其它箭头不一样,后面还跟了个菱形框?
需求人员:哦,这代表的是包含关系,表示一个考核指标包含了多个类型的过错行为呀。
经过一番交流,我们已经明白客户的意思了,客户也明白我们画的图了。大家对彼此的交流都比较满意。
所有的爱情都是以浪漫开始的,需求分析也不如此。随着需求分析的不断深入,我们发现问题了。在这张图中,我们把执法行为与过错行为仅仅描述为一对多的包含关系,似乎没有什么特别的。但对大量考核指标具体需求的分析,我们才发现其实不是这样简单。当考核指标只有一种过错行为的时候,那非常简单,这个过错行为对就是对,错就是错。但当考核指标存在多种过错行为的时候,情况就复杂了,必须分成三种情况:
1. 一个执法行为同时包含多种过错行为,每个过错行为就是一个考核点,任意一个考核点错了整个就判错,只有所有考核点都正确才判正确。这种情况就像填一个表单,所有数据项都填对了才算对,任意一个错了就算错,然后画出这样一个对象图:
2. 虽然一个考核指标定义了多个过错行为,但它把所有执法行为分为多个类型,每个类型的执法行为只对应一个过错行为,这个过错行为对就是对,错就是错:
3. 最后一种就是那些限期完成的考核指标,正确的行为只有一个:按时完成的行为,过错行为却有两个:逾期完成与逾期未完成。
虽然图形有些复杂,但这正是代表了现实世界业务的复杂性。我们拿着这些图与客户进行了简单的描述,由于图中的所有元素都是用客户熟悉的术语描述的,因此他们很快就能够理解。同时,开发人员拿到这样一个图,很快就制订了四套不同的方案,来分别解决四种不同的情况。
随后,在对这四种情况更加深入的分析时,我们发现第一种情况在计算过错数时似乎有一些问题。在第一种情况中,一个执法行为包含了多个过错行为,如果出现了过错,过错数算几?假如一个执法行为包含三个过错行为,如果都做对了,分子数算1;但假如有2个过错行为错了,过错数算2?还有那一个正确的行为呢?这似乎有些矛盾!当我们向业务人员提出这个问题时,他也有些懵了,这样的结果似乎是我们双方都没有预料到的。经过反复的思考与讨论,最后我们做出这样的决定:将原有的过错数拆分成过错户与过错数。在以上情况中,如果一个执法行为有2个过错行为错了,过错户为1,过错数为2。试想,如果不对需求进行如此深入分析与理解,能发现这样的问题吗?如果不及早发现这样的问题,是否会给项目后期带来巨大的风险?
应该说,从最初的粗浅认识,深入到后来对四种情况的认识,正是体现了DDD的另一个思想:持续学习。需求人员在开始一个新的管理系统的分析工作时,都有可能面临着一个全新的业务领域。在这个领域中,他们不可能一夜成为专家,也不必要成为专家。他们需要时间去学习领域知识,但这并不意味着学习所有的领域知识,而是与软件相关的领域知识。做财务软件,你不必考财务师,但你必须要学会与财务软件相关的财务知识。你对领域模型的认识被延伸到了整个软件生命周期中,包括之后一次一次的升级完善。你每认识深入一点儿,就可能会体现到你的分析设计中,并最终体现在开发的软件中。你对领域知识认识再深入一点儿,软件就再完善一分。
我们应当怎样做需求分析:非功能需求
我曾经看过许多关于需求分析的书籍,老外写的,国人写的,都有。但我总体就是一个感觉:累。各种各样的分析、各种各样的视图,让人眼花缭乱。为什么会这样呢?不得不说,需求分析是一个太宽泛的概念了,不同的行业(商业的、管理的、游戏的),不同类型的软件(底层的、桌面的、网络应用的),不同的设计方式(面向过程的、面向对象的),需求分析的过程都存在着巨大的差异。要制订放之四海而皆准的方法谈何容易。即使同一类型的软件,它们也存在着各自的特点,有的问题大多数软件都不用考虑,而它必须考虑。正因为如此,许多关于需求分析的方法和书籍描述得挺复杂的。
但我要说,我们做需求分析应当化繁为简,不必去拘泥于那些过程。怎样化繁为简?寻找适合自己的,避免做过度分析和设计,这种思想也是敏捷开发的精髓。比如我所从事的管理软件的研发,关注业务流程、关注业务实体、关注规则约束,功能方面的需求就分析完成了大半。然后再关注查询报表、关注外部接口、关注打印导出等细小功能,功能方面就差不多了。
但是,我不得不说,需求分析人员最容易忽略的部分就是非功能需求。非功能需求更加靠近的是技术,是设计,是实现,是架构师关注的内容,是需求人员最不擅长的方面,这也是非功能需求为什么常常被忽略的重要原因。正因为如此,架构师应当尽早参与到项目中,参与到需求分析中,尽早分析需求的技术可行性,尽早考虑性能、安全性、可靠性等非功能需求,尽早开始架构设计。
在非功能需求分析中另一个非常常见的错误,就是将非功能需求仅仅归结为一些放之四海而皆准的原则,比如专门拿出一章来描述报表查询效率要怎样、系统易用性要怎样。诚然,这些原则性的东西是十分必要的,但许多非功能需求不能仅仅停留在这些基本原则上,要落实到对一个一个功能的分析中。
说这么多虚的,咱们还是上实例吧。还是这个考核系统,每天在上班后1小时内,将有90%的用户会上线查看自己的考核结果。因此,在进行考核结果查询功能的分析中,我们写下了这样的话:查询必须高效(预计查询数据量:xxx),并且支持高并发操作(预计并发用户峰值:xxx)。有了这些描述,设计和开发人员会着重注意该功能的性能问题,测试人员也可以着重进行该部分的性能测试。
在另一个项目中,用户需要对大量的数据进行选择,进而完成制作清册、下派、回退等操作。在前期的需求分析中,需求人员没有仔细分析这些操作的易用性,没有提供给用户批量选择等功能,直到试运行时才发现。当时系统到各基层试运行时,激起了巨大的民怨,给项目带来了巨大的负面影响。多亏我们及时发现问题,加班加点完成了相关操作的批处理功能,才使项目得以顺利推行。如此看来,非功能需求对于一个软件项目是多么重要。因此,我建议,在需求分析的细化阶段,需求分析人员应当与架构师一起,一项一项地去分析每个功能的非功能需求,并在用例说明中记录下有特殊非功能需求的功能,使我们对非功能需求的分析落到实处。
那么哪些是非功能需求呢?我们可以简单归纳为“URPS+”,即可用性(Usability)、可靠性(Reliability)、性能(Performance)、可支持性(Supportability)以及其它(+)。而这5部分我们可以进一步细化。
可用性是一个非常宽泛的概念,它泛指那些能让用户顺利使用系统的指标,包括易用性(易操作、易理解)、准确性、安全性(权限体系、访问限制)、兼容性(服务器、客户端的兼容度),等等。
可靠性就是系统可以可靠运行,包括系统成熟度(数据吞吐量、并发用户量、连续不停机性能等)、数据容错度、系统易恢复性,等等。
性能,我认为是需求分析阶段最主要的分析内容。用户对性能的要求没有止境,但现实却是残酷的。性能受到许多因素的影响,包括业务需求、软件设计、数据库设计、系统部署方式,等等。其中,业务需求和部署方式,对性能的影响是最大的,我们必须在需求分析阶段就想清楚,解决掉。有一次,客户提出了一个数据导出的功能,这看似一个非常普通的功能。但是经过仔细地分析我们发现,客户在执行数据导出前的查询时,如果选择时间跨度数年,查出的数据量可能达到数十万。要将数十万数据一次性地导入到一个excel文件中,这不论从运行效率、系统稳定性,还是技术可行性分析都是不可取的。最后,我们经过与客户的协商,一次性导出数据最大不超过2万,同时提供了分页导出的功能,可以让他们选择导出从第几页到第几页的数据。这样,如果数据量大,客户可以经过多次将数据导出,数据导出的性能得以保证。
系统部署架构对性能的影响也是巨大的。一个管理系统,是市级集中,还是省级集中,甚至全国集中,对性能的考量是不一样的。市级集中不会过于担心性能的问题;省级集中就必须要考量并发访问量,是否要建立集群;全国集中就必须考量是否使用消息队列,所有流程是否有性能瓶颈,以及采用什么技术架构更适于并发访问等等。而这一切都是系统架构师应当考量的内容。
最后一个内容,也是最容易被忽略的一个内容,就是可支持性。可支持性,就是软件的可维护性、易变更性。可支持性对于客户是透明的,不可见的,因此客户通常不关心这个。由于时间紧、人员素质参差不齐,这部分也常常为管理者所忽略。但试问,谁没有维护糟糕系统的痛苦经历?谁们的系统维护了数年经过数次升级后还能维护?在需求分析与设计阶段,可支持性实际上体现在,我们是否能有效识别系统可变的需求,并能够提供合理的方案。这体现的也是架构师的功底。一次分析和设计ERP软件的时候,我发现应付单需要生成凭证,随后又发现应收单、采购单、***都要生成凭证。既然这么多单据需要生成凭证,是否还有其它我们还不知道的单据也要生成凭证,是否可以有一个统一的接口。果不其然,核销单、工资单、固定资产核定都需要生成凭证。最后我们设计成了一个统一的生成凭证接口。还有一次,我们发现客户报表在查询SQL、过滤条件、显示列等部分经常变,因此设计成一套可配置的报表系统,大大提高了系统可维护性。
需求分析是一个撒大网的过程,而不是姜太公钓鱼的过程。功能需求固然重要,非功能需求同样重要。我们在进行非功能需求的分析时,除了制订整体的原则以外,还要落实到各个具体的功能中,将这些功能所潜在的、特殊的非功能需求挖掘出来,提前进行分析设计,对于可行性不高的应及时与客户商讨,才能有效地避免日后存在的这些方面的风险。
我们应当怎样做需求确认:需求列表
需求分析是一个我们与客户不断沟通的过程,这个过程就如同我们与老板的一次对话。老板把你叫去,给你交待了一大堆任务。我们首先是仔细聆听任务的内容,然后整理个一二三四。然后我们复述一遍老板的意思:“老板,我复述一遍,您看看我理解得对不对。首先,您要求我×××,然后×××,最后×××。”老板:“恩,就是这意思,你照着办吧。”之后,我们开始了我们的工作。这个复述的步骤相当重要,因为人与人的沟通最大的问题就是失真。由于人在知识水平、观点看法、性格特质的不同,听者常常会误解对方的意思。有了复述的步骤,误解就会立即被纠正,沟通得以顺畅。在需求分析中,这个复述的步骤就是需求确认。
但与一次简单的沟通不同,需求分析是一系列复杂的沟通过程,它涉及到许多人,谈论的是许多的事物。因此,一次简单的口头复述不足以满足需求分析的需要。因此,需求确认是一系列的确认过程,每次确认都可能需要与不同的人,在不同层次的确认。最终应当形成到纸面,形成文档性的东西,双方签字确认。这个过程中可以采用的一个好的方法就是原型法,最终产物应当是需求列表与需求规格说明书,最后结束于一场需求评审会,或者签字确认会。
当我对无数失败项目的分析总结之后,得出的一个重要的结论就是我们的项目需要对需求的跟踪。大家想想,当一个项目持续数月,经过数轮的需求分析与设计,再经过数轮的需求确认与变更。用户、需求分析员、系统架构师、设计人员、开发人员,甚至测试,一个一个的角色像走马灯一样加入进来。需求开始变得模糊不清,软件设计的初衷开始偏离。开发人员不知道依据哪个标准开发,测试人员不知道依据哪个标准测试,甚至一些需求被人所遗忘。最终,等到软件交付的时候,客户说这不是他们所需要的,项目走向了失败。问题出在哪里呢?问题就出在,不论我们如何分析与设计,我们都要如实记录原始的需求,并以此来验证我们最终的软件。这个如实记录原始需求的文档,就是需求列表。
需求列表,又称之为需求跟踪表,是最原始的、用户对业务需求的描述。它不掺杂任何需求分析人员对业务需求的分析与设计,而是以简短扼要的语句,以业务人员的口吻表述的,今后要开发的这个系统应当提供给他们的各项功能。
首先,需求列表不掺杂我们对业务需求的任何分析与设计,这是需求列表的核心,也是它存在的意义。从用例模型到领域模型我们不难发现,它是一个分析与设计的过程。需求分析员对业务需求进行捕获、认识、理解以后,需要结合软件专业知识进行分析设计,还要听取系统架构师和设计师对需求可行性的分析,最后才整理和编写出用例模型。在这样一个过程中,随着业务需求复杂度的提高,以及各种技术分析的掺杂,最终的结果很有可能偏离原有的业务需求。这种偏离常常表现为对业务需求正确性与完整性的偏离,即需求已经变味儿了,或者某些需求项目缺失。需求列表就是那个最开初的、最完整的、正确的业务需求。用这样一个列表来开始我们的分析,最后用它来验证我们的设计,使之成为我们的分析设计之旅树立的一个正确的航标。有了这样一个航标,就可以使我们最终能够到达一个正确的彼岸。
其次,需求列表应当是站在业务人员的视角,对业务需求的简明扼要的描述。一个纷繁复杂的、业务庞大的管理系统,经过整理以后,被分解成一个一个的需求项目。每个需求项目是一句简明扼要的话。简明扼要意味着清晰易懂;分解成需求项目意味着分解复杂问题为简单问题。每一次与业务人员讨论完业务需求以后,我们就整理成这样一个需求列表,使我们与客户的讨论都有一个清晰明了的讨论结果。当下一次与业务人员讨论时,我们拿出我们上一次讨论的需求列表,又使下一次的讨论有一个基点,使业务讨论能以演进的方式推进下去,提高我们的工作效率。
然而,需求列表中应当剔除那些客户对系统设计的内容。前面我们提到,客户,特别是那些对信息化建设有一定经验的客户,容易提一些对系统设计的期望,比如什么功能应当做成什么样子,功能界面是怎样的。客户提的这些意见,也许不是最佳的,我们经过深入的分析设计以后,可能会提出一些更加合理的方案。因此,这样内容不能成为我们验证系统功能的基石,因而不应当写入需求列表中。需求列表描述的更应当是客户对软件功能的意图,即客户使用这个功能所达到的目的,而不是功能的具体实现。这一点我们在后面通过具体实例详细说明。
最后,需求列表也不是一步到位的,而是经过由粗到细逐渐整理形成的。一个大的需求项目可以分解为多个细的需求项目,进而形成一个树状的需求列表。需求列表应当细分到什么程度呢?将系统需求描述清楚为宜。简单需求不需过多的细分,而复杂需求则需要尽量写细一些。同时,需求列表也是一个不断变化的过程,日后的每一次升级维护都需要不断增添和修改需求列表,使其与实际系统保持一致。
我们应当怎样做需求确认:一个需求列表的实例
现在我举一个具体实例来看看需求列表是怎样编写的吧。这是一个公司内部的评审系统,它分为制订评审计划、执行评审、制作评审报告与问题跟踪四部分。经过初次与评审人员的业务讨论以后,我们整理出这样一个需求列表:
1.评审发起人填写一份评审计划,详细记录评审时间、评审内容、评审者、评审地点,制订评审组长,并预计评审工作量,发起一个评审任务。
2.评审者在收到邮件后,进入评审任务中,对评审内容进行评审,同时填写并提交各自的评审意见。
3.评审组长汇总所有的评审意见,并在评审会上依次过所有的评审意见,对评审意见进行修改或删除,填写问题跟踪,形成此次评审会上最终的评审意见及问题跟踪表。
4.评审组长制作评审报告,并形成评审结论,以邮件的形式通知所有评审者。
5.所有评审者对评审报告进行回复意见,如果都选择同意,评审组长关闭此次评审。
6.评审组长跟踪所有问题,并可以依次关闭每个问题。
当然,在这个需求列表中,客户提出了一些名词,比如评审计划、评审意见、评审组长等。我们在整理需求列表的同时,应当注意整理这些名称,弄清它的内涵外延,以及它们相互之间的关系、作用。这将为我们后面的领域模型分析提供素材。毫无疑问,这样的需求列表过于粗略。因而在后面的业务讨论中,我们逐项对它们进行了细化:
1.评审发起人填写一份评审计划,详细记录评审时间、评审内容、评审者、评审地点,制订评审组长,并预计评审工作量,发起一个评审任务。
1.1 评审时间应当分为数个阶段分别制订时间计划,如评审准备、评审会议、评审报告;
1.2 评审内容应当可以上传数个文件,分别描述文件的内容、作者、编写日期、版本号,供评审者下载与查看;
1.3 填写评审者时,选择一个评审者为评审组长,评审发起人不能是评审组长;
1.4 评审地点与预计评审工作量只需直接填写;
在我们后面的用例分析中,我们对这段需求列表进行了大量的分析设计。但这些都是设计与实现,它们会出现在后面的用例分析及其模型中,却不应出现在需求列表中。在后来的升级开发中,客户又提出了发邮件通知的功能。将该功能描述出来,并添加到需求列表中:
1.5 评审计划提交以后,以邮件的形式发送给每个评审者,通知该评审任务。
有了这样的需求列表,当需求分析工作完成时,我们将一项一项检查用例模型是否满足需求列表的内容;当软件开发完成时,我们将一项一项检查软件功能是否满足需求列表的内容;当用户验收时,我们同样使用需求列表,一项一项检查我们的软件是否满足用户需求。
我们应当怎样做需求确认:快速原型法
常常听到许多朋友跟我埋怨,需求分析之难,就在于用户自身就常常弄不清楚自己的需求。起初在需求确认的时候说得好好的,一到软件上线的时候就不是那么回事了,这可没法整。但我们只要坐下来仔细分析就会发现,在需求分析的时候我们跟用户是在空对空地讨论问题。用户不是专业人士,他也搞不清楚软件到底会做成啥样,所以你跟他确认的时候他就点头了。但是,用户不是傻子,当你软件上线时,他拿到了实物了,知道软件做成啥样了,一旦不满意他就开始提变更了。所以,需求分析的症结就在与这个实物。
既然症结在此,毫无疑问,我们就应当在需求分析阶段拿出实物,用实物与用户确认需求,这就是快速原型法的基本思想。快速原型法,简称原型法(Prototyping),是20世纪80年代提出的一种从设计思想、工具、手段都全新的系统开发方法。它摒弃了那种一步步周密细致地调查分析,然后逐步整理出文字档案,设计开发,最后才能让用户看到软件结果的繁琐作法。当我们捕获了一批业务需求以后,就立即使用快速可视化工具开发出一个原型,交给用户去试用、补充和修改。再提出一些新的需求以后,再开发一版新的原型。原型法的关键就是这个快速开发。不用考虑性能、美观、可靠,原型的目的就是模拟客户的需求,与客户进行确认的。整个需求分析的过程就是“捕获需求->原型开发->确认需求->再捕获需求”的过程。
原型开发的快速与模拟到什么程度,是一对矛盾,我们要去把握。要快速开发,必然不可能和最终交付的软件系统一模一样,许多复杂问题被简化,非关键性流程被忽略,这就是所谓的模拟。因此,模拟到什么程度是关键,既能说明问题,又不耽误时间。根据我的经验,一般能拿出界面,并可以走通关键性流程就可以了。一些快速开发平台为快速原型法提供了可能。
当用户拿到原型可以自己操作时,需求研讨的气氛立即变得不太一样了。当用户享受原型给他们带来体验的快感时,需求被源源不断地被提出来。这时候的需求,就不再是枯燥无味的文字游戏,而是生动形象的图形界面。日后,如果项目采用迭×××发,让用户看着软件一点儿一点儿地成长,这又是多么美妙的体验啊。与此同时,你与用户的信任也在一步一步建立起来,软件风险在降低,项目将朝着正确方向前进。
快速原型法是美妙的,它给你与用户带来了从未有过的体验。但美妙的同时,也会带来一些的尴尬,不必要的误会,我们一定要注意。最常见的误会就是让用户将原型误以为最终交付的系统。开发一个系统需要持续数月,但你倒好,几天就搞定了,为什么还要在这个系统上投入大量资金呢?如果对方领导开始有这样的想法时,双方就开发费用进行的谈判就有一些不妙了。所以在给用户看到原型前,一定要跟用户解释清楚。
既然是原型,必要的校验、非正常操作的处理通通都被忽略。因此,当演示原型出错时,用户你可千万不要较真哟!这丑话可得说在前头,否则用户跟你较起真来,你在用户心目中的形象可就要大打折扣了。
总之,根据实际情况灵活运用原型法,可以更加顺畅地与用户确认需求。甚至在最后编写需求规格说明书的时候,都可以将原型的截图放进去。都是与用户确认好的东西,又能提高需求规格说明书的准确与生动,何乐而不为呢?
我们应当怎样做需求确认:需求规格说明书
曾经有项目组拿着用户编写的原始需求就开始开发,随后状况不断,一次令人崩溃的研发过程。拿着用户编写的原始需求,编写我们自己的需求规格说明书,之所以重要,就在于用户编写的原始需求,是脱离了技术实现,编写的一份十分理想的业务需求。理想与现实总是有差距,我们之所以要编写自己的需求规格说明书,就是要本着实事求是、切实可行的态度,去描述用户的业务需求。那些不可行的需求被摒弃,或者换成更加可行的解决方案。这就是需求规格说明书的重要作用。
从理论上讲,需求规格说明书(Requirement Specification)分为用户需求规格说明书和产品需求规格说明书。用户需求规格说明书是站在用户角度描述的系统业务需求,是用于与用户签字确认业务需求;产品需求规格说明书是站在开发人员角度描述的系统业务需求,是指导开发人员完成设计与开发的技术性文档。但是,我认为,用户需求规格说明书与产品需求规格说明书的差别并不大。领域驱动设计所提倡的就是要让用户、需求分析员、开发人员站在一个平台,使用统一的语言(一种混合语言),来表达大家都清楚明白的概念。从这个角度将,需求规格说明书就应当是一个,不区分用户需求规格说明书和产品需求规格说明书。
那么需求规格说明书怎么写呢?不同的公司、不同的人、不同的项目,特别是在需求分析中采用不同的方法,写出来的需求规格说明书格式都是不一样的。在这里,我给大家一个,采用RUP统一建模的方式分析需求,编写需求规格说明书的模板,供大家参考。
1.引言
1.1 编写目的
如题,描述你编写这篇文档的目的和作用。但最关键的是,详细说明哪些人可以使用这篇文档,做什么。需求规格说明书是用来做什么的?毫无疑问,首先供用户与开发公司确认软件开发的业务需求、功能范围。其次呢,当然就是指导设计与开发人员设计开发系统。当然,还包括测试人员设计测试,技服人员编写用户手册,以及其它相关人员熟悉系统。描述这些,可以帮助读者确定,阅读这篇文档是否可以从中获得帮助。
1.2 业务背景
描述业务背景,是为了读者了解与该文档相关的人与事。你可以罗列与文档相关的各种事件,也可以描写与项目相关的企业现状、问题分析与解决思路,以及触发开发该项目的大背景、政策法规,等等。
1.3 项目目标(或任务概述)
就是项目能为用户带来什么利益,解决用户什么问题,或者说怎样才算项目成功。前面提到过,这部分对项目成功作用巨大。
1.4 参考资料
参考资料的名称、作者、版本、编写日期。
1.5 名词定义
没啥可说的,就是文档中可能使用的各种术语或名词的定义与约定,大家可以根据需要删减。
2.整体概述
这部分是对系统整体框架性地进行描述。
2.1 整体流程分析
绘制的整体行动图,及其对它的说明。
2.2 整体用例分析
绘制的整体用例图,以及对每个用例的用例说明。如果项目比较大,存在多个子系统,可以将用例图改为构件图,详细描述每个子系统及其相互的接口调用。
2.3 角色分析
一个用例图,描述系统中所有的角色及其相互关系。在随后的说明中,详细说明每个角色的定义及其作用。
这部分还可以根据项目需要编写其它的内容,如部署方案、网络设备、功能结构、软件架构、关键点难点技术方案,等等。
3.功能需求
3.1 功能模块(子系统)
一个一个描述系统中的每个功能模块(或子系统),即整体用例分析中的每个用例。这部分是需求规格说明书最主要的部分。
3.1.1 用例图
绘制该模块的用例图(详见《功能角色分析与用例图》)。
3.1.2 用例说明
对用例图中的每个用例编写用例说明(详见《用例说明》)。
3.1.3 领域模型
为用例绘制领域模型,并编写领域模型说明,对每个实体进行说明。对实体的说明包括对实体的定义、属性说明、行为说明、实体关系说明等等。如果实体间关系复杂,还要使用对象图说明实体关系的所有情况(如《领域驱动设计》中的描述)。
4.非功能需求
这里描述的是软件对非功能需求的一般要求,即整体设计原则。那些与具体功能相关的非功能需求应该放在用例说明的“非功能需求”部分(详见《非功能需求》)。
5.接口需求
如果项目涉及到与外部系统的接口,则编写这部分需求。
5.1 接口方案
详细描述采用什么体系结构与外部系统的接口。
5.2 接口定义
接口的中文名、英文名、功能描述、参数、返回值、使用者、使用频率,等等。
我们应当怎样做需求确认:评审与签字确认会
时间过得真快,经过一系列需求研讨、需求分析和整理确认,我们整理出了需求列表,编写出了需求规格说明书,一切似乎该到结束需求分析阶段的时候了。但是,敏捷大师的一句话让我们彻底心凉到了骨头里。敏捷大师说了,我们不可能在需求分析阶段完成所有的需求分析工作,它将延续到设计、开发,甚至测试阶段。
一直以来,我对这句话非常困惑。既然需求分析阶段不能完成所有的需求分析工作,那么完成多少才算结束呢?80%?60%?或者更少?大师没有给出一个标准。大师就是大师,生活在太空里的,我们慢慢理解吧。经过多年的实践,我慢慢理解了。我们说这种需求分析工作不可能完全完成,或者说日后用户的需求会变,其实并不是毫无规律可循的。通常,用户对需求的变更只发生在某些固定的范围内,弄清楚了这些范围,我们的问题就迎刃而解了。
1. 整体需求不变,具体细节变化。我们说需求是分层次的,整体框架、功能模块、每个操作的细节。如果用户变更到了将整个框架都推翻了,这个项目就别做了。所以整体框架是必须在需求分析阶段完成的,是日后不可能改变的。功能模块可能要变,但通常是某个部分在变,而更多的是那些具体操作的细节在变。
2. 界面风格与操作易用性是最容易发生变更的。我们说用户看到软件以后不满意,其实主要是对界面风格与操作性不满意,而不是软件功能。界面不够美观,操作不方便,不符合用户的操作习惯,都是造成用户不满意的地方。
3. 增加其它功能。软件是对现实的模拟,而现实也是复杂多变的。我们与用户在进行业务流程分析时,也许一些流程没有考虑到,或者还有特殊情况需要处理。这些是客户要求增加功能的主要动因。
经过以上分析,需求分析阶段要做到什么程度就可以清楚了:整体框架与功能模块必须确定下来,至于各个功能模块下的具体操作,尽量做,能到什么程度先到什么程度。至于界面风格与操作性,我们可以在日后迭×××发的每个迭代期,拿出样品以后再与用户确认。
OK,万事俱备只欠东风,当所有工作都完备以后,我们的需求分析工作开始进入最后收尾的阶段。我们说,需求分析阶段的产出物是需求列表与需求规格说明书,而最终结束的里程碑无疑就是需求评审会了,或者说与用户的签字确认会。
需求评审会的主要目的就是确认需求,以便以此开始我们的设计开发工作。从理论上说,需求评审会应当由用户代表,与项目经理、需求分析员、系统架构师、设计人员、测试人员、QA经理,还有公司相关领导参加。但实际上,让如此多不同角色的人聚集在一起开会是不现实的。因此,我们可以将需求评审会分为内部评审会与外部评审会两部分来开比较现实。
处理外部问题,必先要从内部统一思想。先召开一个内部评审会,听听系统架构师、设计人员、测试人员、QA经理对需求分析工作的意见,然后由领导讲讲话,布置一下后面的工作,是十分有必要的。按照我的经验,系统架构师这时的作用相当重要,他应当仔细阅读需求,仔细思考技术是否可行,以及预测该系统是否能够达到用户方领导对该项目制订的目标。如果答案是否定,立即进行调整。
最后就是与用户的外部需求评审会了。外部需求评审会,也可称为签字确认会议,就是与用户就需求规格说明书进行评审,最后签字确认。用户签过字的东西,不可能完全抑制住用户的变更,但至少从很大程度上抑制住了用户的大改。然而,在召开外部需求评审会之前,我们建议大家就需求规格说明书,先与各个单位或部门的用户代表讨论并确定下来,避免在最终的签字确认会上出现分歧,影响工作进度。毕竟大家都不容易,工作一大堆,聚在一起不容易。
经过数月的分析讨论,最终在一片和谐的气氛中,双方领导在需求规格说明书上签字,项目开始进入一个新的轮回。在这个轮回中,是焦头烂额、不胜其苦,还是如履薄冰、最终顺利交付,是与许多因素有关的。但我想说,一份高质量的需求分析必定起到决定性的作用,必定为日后的软件开发扫清了许多许多的地雷。
完结。
转自:http://fangang.iteye.com/blog/1345099
转载于:https://blog.51cto.com/jamesyu/1584331