显示标签为“SoftwareTalking”的博文。显示所有博文
显示标签为“SoftwareTalking”的博文。显示所有博文

2008年3月29日星期六

用例浅谈

用例(use case)是现代软件工程中用来采集需求和软件设计的一个常用工具。那么用例到底是什么东西?什么时候用这个工具?如何使用这个工具呢?本文就结合本人在日常工作中的实践经验来做一个简单的介绍。

用例的定义有很多,几乎每一本书的作者都有自己的理解。但是用例的本质不变,系统的使用者对系统发出的一次请求,用例描述系统完成这个目标的过程的一种方法。因此我们可以用4个词来概括用例;他们是:角色,请求,步骤和目标。 有的书上说是三个要素。一个是参与者,也就是我这里的角色。一个是用例只描述单独的任务,也就是我这里的请求和步骤;最后一个是用例必须产生一个对用户有意义的结果,也就是我这里的目标。

系统的主要角色(可能是最终用户,也可能是其他系统)启动了一个交互,他有一个用户目标(user goal)。由于用户请求的上下文不同,前提条件不同,因此这个交互可能产生多个场景。一个UC会把目标相同的场景集合起来。


用例的格式

一般来说,用例可以以多种形式编写,但是大多数情况下都是用于和非专业人员交流,因此,用纯文本方式比较好。同时可以节约时间。

对于用例的格式,很多书上面都有不同的定义,但是我个人认为,用例没有特别的格式。只要意思清晰明了即可。每个人编写的用例都是不同的。UC写作有简化版本和完全格式版本,可以根据项目规模大小选用。

使用用例来发现需求

当编写一个新系统的用例时,一般先写黑盒,然后设计人员细化时变成白盒。黑盒UC的作用主要用来引发讨论,一般由PD或者RE来写,写好之后和Dev和Test以及客户进行讨论。因此UC常常被用作是头脑风暴的工具。UC本身的功能就是捕捉已知的功能性需求并为之建模,这样可以完成高质量的需求报告,相对来说比一般方法要可靠,完全的多。

但是用UC来找出需求时需要注意两点:
1. 它是真正的需求,不是行为或者过程,应该要正确的写出系统必须做的事情,而不是如何做事情。
2. 它不是所有的需求,它们不包括外部接口,数据格式、业务逻辑以及复杂的公式等。他们组成了所有需求中的一部分。不过虽然只有一部分,但是是最重要的一部分。


用例的价值

UC很流行大抵上是因为他们一致、连贵的说明了这个系统是如何使用的。在早期提出完备的UC,系统的使用者就知道该系统可以做什么了。他们可以及早的做反馈、进行调整或者拒绝该UC。不管采用何种设计方法,需求分析阶段的用例建模工作都能发挥极其重要的作用。

有一些公司是不是用用例方法的。他们使用的是Feature。首先获取用户需求,然后由PM大致写出该系统的Feature,当然要包括所有的用户需求,然后通过头脑风暴完善Feature List。最后为每个Feature添加Function List。

事实上,系统级的黑盒UC就可以看作是Feature。每一个步骤就是这个Feature下面的功能。

UC的价值最早产生于当这个用户目标(user goal)创建,并把它们放入到系统的特性列表中去时。这个列表说明了系统可以做的事情,规定了系统的范围。

这个List会由用户代表,PM,公司专家,行业专家代表等人检查。他们会用这个Feature List估算成本和系统实现复杂度,由此确定系统的起始点。这个列表可以联系到复杂性、风险管理、成本、时间和状态检查。

第2个价值体现在UC的作者用头脑风暴的方式把主成功路线上一切可能的错误列举出来的时候。这时候,他可能会发现一些令人惊讶的事情,或者是客户没有想到的事情。这些事情可能导致新的使用者,新的UC的出现。

第三,用例可以帮助我们划分软件的开发周期,评估研发工作量。对于优先级较高的用例会在早期的迭代周期中实现,优先级较低的用例则安排在后续的迭代中完成。

用例模型在整个开发过程中都扮演着非常重要的角色。它用来驱动软件的分析和设计逐步细化。

最后,软件项目中的功能性测试用例,基本上都是根据用例模型来确定的。

用例建模

用例建模是通过分析用户的功能性需求,得到用例模型的工作过程。一般包括下面几个步骤:

  1. 确定系统边界
  2. 确定参与者
  3. 找出所有用例
  4. 确定每个用例的级别
  5. 用例描述
  6. 画出以整个系统为对象的顺序图
编写用例

不要一开始就写出所有的细节,这是违反事物发展规律的,就像荒谬地要求把需求全部搞清才能做设计一样。用例的细化一般有4个阶段。
1. Actor & Goals
列出所有参与者以及他们的用户

2. Use case brief or main success scenario
选出主要的一些UC,写出触发条件和一个大致的轮廓,也就是主成功场景。保证该系统的功能真的是Stakeholder们感兴趣的。

3. Failure conditions
完成主成功场景后,用头脑风暴的方式找出所有可能的失败,首先把它们全部列出,而不是直接就讨论系统的应对之策。

4. Failure handling
写下系统是如何处理每一个错误的。这时候,常常会有一些原本不明显的问题被渐渐暴露出来或者错误处理会突然引入新的用户或者新的用户目标。

大多数项目时间紧张,人员精力有限,在项目前该确定要工作到何种细致程度,因此我强烈建议按照上面4个顺序来。

2008年3月20日星期四

到底什么是需求?

《HFOOAD》给了一个我觉得很简单,又很好的答案。单独拿出来做个笔记。
首先我借用一下里面的图片来说明问题。


那些黑色高亮的词是需求的几个特点。

specific thing
一个需求往往是一件单独的,可测的事情。因为只有可测,才能保证你完成了客户的需求。

system
系统指一个完整的应用,或者是项目程序。因为客户只能看到这个。

do
系统做的事情,或者说是行为。

work correctly
一个系统是否正确是由客户说了算的。为了使最后系统能够正确运行,我们不能漏了任何一个需求,即使客户当时忘了,我们也不能忘。要从客户那里找出潜在的,忘记了的需求。才能使系统正确工作。


给出一个比较正规的定义:
需求就是一个单一的要求,该要求详细规定了指定的系统或者服务的特征和行为。

2008年3月19日星期三

好书推荐《HFOOAD》

为了不把标题弄得过长,我用了缩写,本书全称为《HEAD FIRST OBJECT-ORIENTED ANALYSIS & DESIGN》中文译名《深入浅出面向对象分析和设计》。



这本书是O'Reilly的Head First系列丛书中的一本。本书为什么好,我觉得有这几个方面。

一、本书对OOAD的讲解由浅入深
OOAD发展到现在也有10几个年头了,现在大多数人都在名义上采用OOAD在开发。但是有多少人真正懂OOAD呢?很少!国外少,国内更少!OOAD不是UML,OOAD 不是需求分析,OOAD不是Design Pattern。OOAD是一整套分析与设计的架构,它包含很多东西。市面上不乏好书,比如《Applying UML and Patterns An Introduction to Object-Oriented Analysis and Design and Iterative Development, 3rd Ed - Craig Larman》,或者《AGILE SOFTWARE DEVELOPMENT: PRINCIPLES, PATTERNS, AND PRACTICES》。但是在看这两本书的时候,我总是有摸不着边的感觉。看书的时候以为自己懂了,可是真正写UC或者做领域模型设计的时候又发现自己无从下手。后来我发现这是我自己水平未到。而且我喜欢的是简单的,真正能让我模仿的例子。《HFOOAD》做到了,它写的很浅,由浅入深。从一开始的分析客户需求到后面的健壮、可重用的设计,重构和设计模式,以及在设计时候遇到问题时功能和效率,成本与维护的平衡的选择,这么多OOAD的步骤和技术被作者抽丝剥茧,一步一步放在我面前。

我相信,一个希望自己变得更专业的软件从业人员都会喜欢这本书的。对我自己来说,我觉得虽然我进入这个行业有4,5个年头了,而且还有着计算机科学与技术的教育背景,但是我还是要很羞愧的说一句:我还不是专业的。

专业的人员是怎么样的?一句话,人家用正规的方式做软件,人家有方法学的支持。现阶段,主流的方法学就是OOAD。需求分析用什么?用例、场景、故事板,原型等等。怎么过渡到设计?领域模型、E-R关系模型、接口设计,类图等等。详细设计怎么做?UML主打,敏捷和迭代随行,设计模式长伴左右,测试驱动护驾。人家知道在什么时候用什么方法来解决问题。

所以要成为专业的人员,我以为有三个阶段:
第一阶段:学习理论基础,知道有哪些方法,有哪些阶段;
第二阶段:知道在什么阶段该用什么方法;
第三阶段:知道如何有效率地使用方法以及该得到什么样的结果。并且保持知识更新。
我认为《HFOOAD》这本书可以让我进入第二个阶段。而第三个阶段需要自己不断实践和摸索。

二、Head First系列独特的学习风格
我不知道这种学习风格是不是适合所有人,但是我觉得很合我胃口。
首先它不像其他的书,首先扔出一大堆定义把人砸晕,然后给出零零碎碎的例子,没有连贯性,实用性。它的教学方法是通过给出真实的场景,图片,对话等各种刺激大脑的方法来促进学习的效果。让人身临其境肯定要比单纯的文字要让人感兴趣的多,不是么?但是这需要看书的人主动参与,用自己的想像力带自己进入文中的场景,和里面的人一起动脑筋,一起动手做。面对如此好书,还用以前囫囵吞枣的方式看书,那还不如不看。

我还没有看完本书,有谁原意和我交流学习心得,欢迎来信。

补充:
2008-3-19
1.有人认为学习OOAD需要学习UP,RUP等开发过程。我觉得这个不是必须的。UP只是一个被定义了的开发过程,是个成品,大家可以直接使用。但是作为产品,就肯定有用户群。有用户群也就有非用户群。很不幸,大多数企业都有自己的一套做法,这时候生搬硬套某一种开发过程反而会起反作用。 因此我们学习OOAD就是学习OOAD的各个组成部分,既将他们独立开来,又让它们保持一定的联系,然后选择合适的应用到我们自己的企业中。慢慢的形成以OOAD为基础的自己的一套流程。

2.最近被人关注的比较多的是《Head First Design Pattern》。我自己个人认为,Design Pattern是具体技术,做软件应该由大及小,自上而下,先把握整体,再考虑细节。同时DP是需要有大量的经验支持的,掌握DP需要顿悟,我自认没有10年功底,我即使学了DP,也无法灵活应用。就像一个小孩拿着一把倚天剑,却无法发挥其作用一样。而OOAD则相反,这是基础,能早学一定要早学,打好基础。

2008年1月17日星期四

作坊式的开发

什么是作坊式的开发方式?

需求只有短短的几句话,不能构成场景。
SPEC和需求完全对不上。一旦开发,就再也没有更新过SPEC。
TEST人员在开发后期介入,TEST CASE和SPEC毫无联系,凭自己想像写。
Bug描述就是短短的一句话的描述。没有过程,没有环境,没有对应的SPEC号。
测试人员和开发人员分开工作。
开发人员没有SPEC,只有需求,针对需求直接进行开发。

这就是作坊式的开发。而我们公司就是这样!

2008年1月14日星期一

软件开发方法浅谈(三)

最近生了一场大病,浅谈的整理断了几天。我已经好几年没有生病了,没想到这次一下子来的这么猛。我整整吊了4天盐水,现在还没有恢复,但是班还是要上的,否则没钱看病了。现在自己觉得身体越来越差,希望和我一样做IT的朋友要注意自己身体了,每天至少要有半小时的锻炼,吃一些善存之类的维生素片,弥补饮食结构带来的隐患。好了,闲话不多说,继续。

浅谈(二)里面已经整理了一些需求获取的方法。那么这里就可以说说从需求到设计的过程了。软件设计是大家研究的最多的东西,至今为止有可以说无数中设计方法。从以前学校里面学的自上而下、模块化到现在主流的面向对象(OO)的设计方法。我现在主要使用模块化和OO这两种方法。前者用于设计小型的工具软件,后者用于设计公司的软件产品。但是从需求到设计的过渡,关注的人就少很多了。下面就仔细说说从需求到设计的过程,或者说--需求工程。因为据我的经验来说,这部分是最难的。Frederick Brooks在《没有银弹》中也充分说明了需求工程在软件项目中扮演的重要角色。这部分过了之后,再细分就是水到渠成的事情。就算小部分出错,也不会影响到系统全局。

1. 需求的层次
“最为困难的概念性工作便是编写出详细技术需求,这包括所有面向用户、面向机器和其它软件系统的接口”。这句话充分说明这个过渡阶段的重要性。

一般来说,需求有两种:用户需求和软件需求[1]。这两种分类也是两种层次。前者就是我在浅谈(二)中所指的从用户那里搜集过来经过简单加工的关于系统行为和反应的要求。用户需求往往包含着两个目的。

  • 我要完成一项工作
  • 这项工作的流程和结果要符合业务规则
软件需求(或者说技术需求)就是为了达到这两个目的而对软件系统提出的要求。这种要求分为两类:功能性的要求和非功能性的要求。
  • 功能性需求规定了系统要实现的功能,使得用户可以完成他们的工作,并且符合业务规则。
  • 非功能性需求则指明了为了要使用户完成目标而需要满足的除了功能以外的要求。这些要求往往是涉及系统的性能、可靠性,安全性,可维护性等方面的要求。

2. 需求的粒度
需求获取到什么程度可以进行设计,这个度的把握不容易。如果无法获得足够的信息,就没法过渡到设计。如果要获得足够多的信息,时间却不允许。那么如何掌握这个度呢?我认为,能把用户的一个目标实现从输入到输出串得起来就可以了,也就是说得通,细节部分不用太关注,要关注得是搞清用户目标,以及现存的支持系统。

我相信实践出真知,检验知识也要靠实践,因此这里开始用一个贯穿全文的例子来说明如何精化需求的。

例子是这样的:我们刚刚获得了一个项目,这个项目是要为牛逼公司打造一个报表系统。首先从NB公司那里获得的需求。他们的要求很简单,“我们要一个报表系统,我们经理每天早上一上班就要看到报表打印出来放在他的办工桌上面。”。然后经过一连串的需求挖掘。我们整理出了初步的需求如下:

牛逼公司的生产部经理牛魔王每天早上需要看报表。报表的内容是前一天公司生产车间所有设备的生产计划、实际生产结果、运行情况、维修明细、产量、故障情况、员工生产率和库存情况。
是的,听起来很简单,但是我们很快会发现一些问题。比如数据从哪里来、有哪些种类的数据等等。然后继续获取需求。然后我们扩充了这个需求(通过上一篇文章中的方法)。

牛逼公司的生产部经理牛魔王每天早上需要看报表。报表的内容是前一天公司生产车间所有设备的生产计划、实际生产结果、运行情况、维修明细、产量、故障情况、员工生产率和库存情况。他要求每一种分类单独一张报表,然后把他们合起来打印成一张大报表(B3),使他能看得方便,快速。

数据来源于各个设备。设备每过一段时间会自动产生这段时间内的运行状况的数据。如果出现紧急问题,设备会直接发送事件。如果断线,设备在连接恢复之后自动上传断线期间的数据。

车间主任负责制定生产计划,核查实际生产结果,核对库存情况。他需要将这些数据记录下来,以备核查。

到了这个程度,所有的过程听起来似乎已经比较合理了。车间主任制定生产计划,然后工人使用设备进行生产。设备定时产生数据,我们只要获取这些数据,加上车间主任制定的计划,就可以自动产生报表。当然,把报表放到牛魔王经理的桌上这种工作还需要小秘玉面狐狸来做。

3.从需求过渡到设计
需求过渡到设计的最终目的就是完成可用的软件需求和设计。告诉开发人员该怎么开发,才能完成客户的要求。所以这一阶段需要和开发人员,测试人员进行讨论,一并决定如何设计。这在很多公司都不受到重视,甚至无视,这是一种完全错误的做法。这些公司的做法是由一个较为资深的人单独决定什么该做,什么不该做,该怎么做。听起来不错,但是实际上资深的人往往并不如表面上那么“资深”,他在做决定的时候往往对可行性,可测性考虑太少。说到底,资深的人考虑的是上层抽象,“资浅”的人考虑的是实现细节,两方面合起来,达到的效果才能最好。

实际的过渡方法有很多种,现在流行的是OO方法通过编写用例,转化为领域模型,然后设计E-R模型,然后用UML中的静态视图,活动视图,交互视图等方法来完成初步的设计。但是有一点要清楚,UML是工具,真正的产出是我们的设计思想。我们一步一步把需求转化为设计的思想才是我们真正要追求的。

这里是我自己以及和同事,同学讨论的一个简单的方法的总结。

第一步我们有了类似上面那段话一样的需求。这样的需求常常被称为场景(Scenario),或者有时候还不构成场景。但是最起码我们知道了要做一件什么事情。于是我们可以把用户做这件事情的步骤一步一步写下来,这就是所谓的用例(Use Case)。但是很多人常常犯一个错误,总是把UC写成软件规格说明,常常写系统第一步做什么,第二步做什么,最后输出什么等等。我到现在还会不由自主的犯这种错误。记住:用例和场景都是用户从系统外部使用系统的过程以及系统给出的反馈。所有用例的总和就是该系统需要完成的所有任务。

第二步我们需要把用例转化为软件规格说明,但是并不是一下子转过去的。在这里,有两种方法。第一种是首先把UC转化为粗粒度的领域模型,这时候领域模型中的各个元素都是系统的各个组件(物理或者逻辑),这些组件相互作用完成系统的所有任务。然后对各个组件的相互作用进行分析,设计出系统接口,也是功能需求,最后对各个组件内部进行细分,自上而下的分析,最后形成细粒度的软件设计。第二种则是在UC和场景的基础上,对软件进行全面的评估,然后写出特性列表(Feature List)。每个特性都由一到多个功能提供实现。然后对每个功能都写一个Func Spec描述这个功能的软件规格说明。

第三步,就是把软件规格说明变成软件详细设计。这一步的花样就很多了,可以用UML大展拳脚,也可以用传统的伪代码模块化实现,也可以把一个一个函数的实现写出来。反正这一部分对于程序员来说是最亲切的。

总得来说,需求分析中最复杂的还是第一步,这一步做好了,后面的事情就是按部就班,逐步细化。并没有太多的技巧。而需求分析却需要很多技巧和经验,需要想记者一样不停地挖掘客户的真正想法。

系列文章:
软件开发方法浅谈(一)--软件开发过程
软件开发方法浅谈(二)--需求工程之需求获取


[1] 有些分法是把需求分为业务需求,用户需求和软件需求三种。还有更甚者增加系统需求。但是在我看来,业务需求应该包括在用户需求里面。在真正做软件的时候,当然可以把一些很独立的,成体系的行业规范单独列出。但在需求工程中,这部分往往已经包含在用户需求之中。

2008年1月3日星期四

软件开发方法浅谈(二)

上一篇文章浅谈(一)已经整理了我接触到的4种主要开发过程。这一篇文章就来仔细的整理一下软件开发中最重要的部分--需求获取和分析。

老实说,自己公司在这方面做的不是很好,大多数的实践方法是我从别的公司那里学来的,还有一些是自己看书和在网上与人讨论得来的知识。经过实践,祛除了一些我认为不是很好用的方法,改进了一些方法的实践步骤。

需求在很多人的眼里虽然重要,但是还是没有重要到能够和产出或者代码相提并论。但我觉得在整个开发环节中,需求是最重要的。我可以毫无疑问的说,需求是软件开发项目成功的首要条件。我们在开发过程中会遇到很多问题,比如最明显的就是不知道哪些要做,哪些不要做;做出东西之后客户不认可,性能没有达到要求,在部署之后客户发现软件和自己想要的完全不是一个东西等等,所有这些,都是没有搞清楚客户到底要什么所造成的。

那么,通过简单的询问就能得到客户的需求么?客户告诉你的就是他要的么?客户一天一个想法,哪个想法才是他真正想要的呢?这些问题不容易回答,我自己经验尚浅,但是经过了几个大型项目的锻炼,我也总结出一些粗糙的方法,这些方法在某种程度上可以解答这些问题。

1.从什么地方获取需求
首先可以从技术合同中获取需求。但是经验表明,那样的需求粒度太粗,只能用于提纲挈领,无法直接转换为软件需求。但是有了这些需求,就可以一条一条去确认,去核对,去细化。

通过和最终用户沟通获取需求。这里的最终用户一定要搞清楚,比如我们做地铁项目的,最终用户就是那些自动售票机的售票员,而不是地铁公司的领导。

通过和销售、售后人员沟通获得需求。对于产品项目,就会有销售,他们会告诉你客户想要什么,或者什么样的软件特性是卖点。售后人员会告诉你上一版的软件有什么问题,这一版需要改经等等。

通过分发试用版本获得需求。beta版的产品就可以分发给用户进行试用了。他们的反馈是非常珍贵的实际需求。

以上都是一些大分类,另外还有一些途径比如产品论坛,内部其他项目人员,技术支持等等。但是有些需求是会遗漏的,那就是来自自己老板的需求。这些需求大多和盈利指标挂钩,这些可是非常重要的。

2. 什么是真正的需求
“客户往往不知道自己要什么”,这句话一定要牢牢记住。一般来说,第一次和客户谈,他给出的信息都不是最终需求。为什么呢,因为他也没有经验,他没有使用过。所以他只能大概的说一些。而第一次,我们需要的也就是大概的东西。然后如果使用敏捷法,那就可以开始干活了,然后再让客户使用,获得正确的反馈。但是在一般开发过程下,我们需要做一些东西,比如原型系统、Storyboard等等,给用户一个能够使用的环境,让他切身体会一下。但是,一定要有场景。只有在某个通用的场景下面的试用活动才能挖出真正的需求。客户会兴致勃勃的把自己代入那个最终场景,然后你就能清清楚楚的知道他怎么来做的,他想怎么做。不要怕麻烦,这种方法绝对可以让你省去后面一大堆麻烦。

谈话的技巧很重要,我们时间有限,不能跟客户胡侃,必须要在有限的时间内尽量引导客户谈正题。因此在找客户谈之前,了解客户行业背景,做准备,列问题就很重要。实际上,这个时候我们就和一些谈话节目的主持人一样。因此对于需求分析工程师来说,学习行业知识远比技术知识重要得多。

尽量找行业经验丰富的客户了解需求。比如我们去一家公司为其定做一套软件,那我会找怎么样的人来了解需求呢?我不能直接跟对方客户说,我要找一个经验丰富的人。我会虚拟一类人,把他代入这个软件的使用者,给他尽量真实的生活经历和工作经历,然后向对方要最符合的一个人。

注意大量隐藏的需求。比如我们地铁行业,一条线路的客户只会考虑本线路的要求,但是多条线路会共同运营,乘客会换乘,我们就需要考虑一些客户没有考虑到的问题。另外比如我们观察到北京地铁使用自动售票机的最终用户都是年纪比较大的大妈,大婶级人物,那么一个隐藏的需求就是字体要大些,对比度高些,能让他们看得清楚。这些往往是生活常识,因此不太可能从别人嘴里得来,要靠自己的观察。

不要光靠自己。一个人的力量永远是渺小的。在获得需求的时候,可以使用头脑风暴之类的方法,让客户和己方不同人员共同参与,各抒己见,这样往往能获得很多需求,但是筛选也是个麻烦事。

并不是所有需求都接受!在谈需求之前,我们要记住项目的范畴,客户往往会认为自己是甲方,所以漫天开价,什么都想要,对于不在范畴里面的需求,可以拒绝。但有时候为了打开市场等目的,对于无理等要求也只能接受。对于有些需求,本身在范围之内,但是和开发与测试讨论后发现这个需求开发时间非常长,或者根本无法测试的,这些需求也要和客户商量修改。

3.怎么样确定需求
一个需求分析到什么程度能够算行。这是仁者见仁,智者见智的问题。但是一般来说,如果一个需求能够写出一个用例(use case),那么这个需求也差不多可以了。用例需要有进入条件,退出条件(结果)和核心价值。进入条件指这个case是怎么触发的。结果就是这个case是怎么结束的,这两个都很好理解。那么核心价值是什么?核心价值是指该用例满足了用户哪个明确的需求。

需求就是我们要开发的东西。这个开发涉及到很多人,不光是需求分析人员的事情。很多公司上层人员获得需求,但是却不让开发和测试人员知道,这些上层人员以为自己同意就行了,这种做法是错误的。因为真正开发的人是开发和测试人员,只有他们认可的、知道的需求才有意义。当然,上层人员可以命令他们做,但是告诉别人怎么做和自己知道怎么做,要做什么将会产生完全不同的结果。因此,在需求定下来之前,要一条一条获得开发与测试人员的同意。每个需求要和开发、测试人员要提出对这条需求的看法,是否能开发,是否可测等等。对于不能开发或者不能测试的需求,一律拒绝或者修改。一旦同意,则他们就要签字,这样也能形成连带责任。

需求的获取也有迭代,一开始的几次迭代只要把一部分核心功能的需求搞清楚即可,对于这部分的需求描述,粒度要细;而对于后面几次迭代的需求只要大致知道有这几个需求即可。那么,粒度要细到什么程度呢?简单的说,一个需求一个用例,一个到多个用例合起来形成一个用户场景即可。在写用例的时候,不涉及任何技术或者系统内部的表现,只有系统外部的表现和给用户的反馈。

比如说,用户在线买本书。用户看到了一本要买的书,然后点击加入购物车,然后去网上支付,完成交易。这是一个完整的场景,而核心价值就是用户买到了书。因此无须写多个用例。一个用例即可。同时在用例里面加入可能的分支情节,比如用户未登录等等。

再举个例子,用户进入地铁站。那用户首先要去买票,他可以在自动售票机那里买,也可以在人工售票机那里买。然后他在闸机那里刷卡进入车站。那这种情况下,就是一个场景多个用例了。买票是就有两个用例,然后进站整个是一个用例。两个买票的用例从属与进站这个用例。但是对于客户来说,因为他最终目的是为了进站,所以买到票在进站是一个完整的需求。

总结一下,需求分析的目的就是要获得客户真正想要的东西,也是我们能够真正开发的要求。很多项目的失败都是因为没有搞清楚这点。做出来的东西和别人要的不一样,别人当然不肯给钱。然后再进行修改,变更,成本也随之上升。千里之行,始于脚下。眼睛不要看得太远,而忽略了身边的事情。

2008年1月2日星期三

软件开发方法浅谈(一)

很久没用中文写文章了,这篇就用中文吧。

做事情要有方法论指导,否则就是瞎做,乱做。在软件行业,有着别其他行业更多的方法论。在过去的几年中,我接触了一些,实践了一些,对各种软件开发方法有了一定的了解。正值岁末,我就来简单地整理一下,首先说说软件开发过程。

首先了解一下概念,一个软件的开发要经过的一系列的环节,一般的开发主要包括分析,设计,编码,测试和发布(或部署)这几个环节,在这个行业的人都知道。但是如何区分这几个环节呢?这几个环节每个环节的输入是什么?输出是什么?

为了回答这些问题,人们开始制定一些标准或准则,用来规定各个环节的工作以及产出。毕竟,一个软件的开发是为了赚钱,如果没有产出,如何赚钱呢?这种标准就是软件工程中说的软件开发过程。也有人称之为软件生民周期。但是这两个概念还是有所不同。前者着重一个东西从无到有的过程,后者着重时间的发展。但我这里还是把两个概念并成一个,主要介绍过程,因为过程也包括了时间的发展。

很显然的,这个过程设计的好坏会直接影响到东西的质量,更会影响到这个东西能带来的利益好坏。因此,很早以前,国外很多公司就成立了QA部门,定义一些自己的过程来确保质量。有一些过程名声显赫,最终成为了一个时代的标准。

1. 瀑布模型(Waterfall Model)

这个名字软件行业的人耳熟能详,但现在已经成为了贬义词。如果你公司使用瀑布模型,估计会遭人白眼。为什么,因为使用瀑布模型而失败的项目不计其数。但是,要知道,这是第一个把软件生命周期明确定义出来的模型,现在的很多开发过程,只不过是把这几个阶段拆分,打散,拉长,缩短来适应需求而已。再把眼睛往后看30年,那个时候的软件远远没有这么复杂,需求简单而明确,因此瀑布模型还是很适合的。但是,现在的世界发展太快,人类的知识面和想像力都无限膨胀,对软件开发商的要求越来越多了,很好,这才是真正的产业。因此瀑布模型的缺点就出来了---简单的说,就是不能应付需求变更,或者更准确地说,应付需求变更的成本太大。瀑布模型中要求需求全部弄清楚之后才开始设计和开发,但是现在的软件大多数规模庞大,跨地域工作又提高了沟通成本,导致需求很难在一开始就全部弄清楚,但是时间不等人啊,根据瀑布模型就开始工作,到了后期,需求变更对于已经设计差不多完成的软件来说无疑是个灾难。很自然的,人们开始想到螺旋模型。

2. 螺旋模型(Spiral Model)
这个模型很简单,就是把一个大的瀑布模型拆分成多个小的瀑布模型。这很符合需求导向的软件开发实际情况。比如一开始掌握了20%左右的关键需求就开始了第一个瀑布模型,完成这个阶段之后再开始后面的20%或者30%需求。很明显,这样提高了质量,减少了需求变更的成本。而且在每个阶段也不需要投入非常多的人力了。试想一下,原本三个月做100%需求可能需要6个人,现在1个月做20%的需求可能只要1个人了。这是多大的节省啊。老板们开始期待软件项目的成功了。可是,他们很无奈的发现,螺旋模型也有缺点--每个周期结束没有明确的输出,这可能导致后面的周期无法正常开始,最后的集成往往产生很大问题。往往螺旋模型一开始很顺利,到后面越来越难转下去,就想一个陀螺一样。我一开始就说过,开发过程是一些准则和标准。因此,人们决定要把螺旋模型改造一下,定义其开始标志和结束标志(输入和输出)。于是,迭代模型产生了。

3. 迭代模型(Iteration Model)
迭代模型是一个很有意义的进步,他每个阶段的设计都非常灵活。通常来说,每个公司都有自己的迭代模型,但是有一点不会变,就是迭代模型明确规定了各个阶段的开始标志,输入条件,输出内容和结束标志。当然,其中最重要的还是输入的内容和结束标志。每个阶段的结束都称为Milestone。迭代是很灵活的,对于小规模的开发,迭代是线性的,也就是一个迭代完成再进入下一个迭代。而对于大规模开发,可能就是并行的。各个子系统并行迭代,每个子系统内部再进行线性迭代。




然后每个迭代也不能就这么叫迭代了。对于一个软件项目,总归会有需求分析阶段,设计阶段,开发阶段,验证阶段和发布阶段。这些阶段都不是纯粹的做单一的工作,比如需求分析阶段,不是单纯的做需求分析,也有一些少量的开发,同时一些测试用例也开始设计起来。但是这个阶段主要还是做需求分析,因此就叫做需求分析阶段。类似的,开发阶段的主要工作还是开发,但是也有一定量的需求分析工作。简单的说,就是谁占主导地位,就叫谁的名。对于阶段的名称,每个公司都不同,每种开发过程也都不同,不用去特别的记忆,因为背后做的事情就是这些。但是对于大的项目,往往每个大阶段里面还有小的迭代。比如一个需求分析阶段就会有1~2个迭代,开发有2~3个迭代等等。这要根据实际情况来。

那么每个迭代干什么事情呢?其实每个迭代也犹如一个小的软件生命周期,基本上都包括了需求分析,开发,测试等阶段。但是每个阶段时间很短。因为实践证明,一个迭代不要超过4~6周,因此在开发阶段往往是2~3天分析这个迭代要做的事情,1~2周进行开发,1周进行测试,然后几天进行发布。但是再需求分析阶段,需求才是最重要的事情。因此在该阶段的迭代的特征是需求往往占据80%以上的迭代时间,剩下的是一些原型开发,不带测试和发布的迭代。

迭代的内容和内部时间比例是灵活的。但是输出却是固定的。在设计迭代的时候就已经定义好,每个迭代的输出是什么。这个标准在很多公司被称为迭代的退出条件(Exit Criteria)。达到这个条件,迭代就可以退出,向下面一个前进。比如在需求阶段,第一个迭代做了20%的需求分析,这些需求就是要在后面一个迭代进行开发的内容,因此这个迭代的输出就是需求分析文档和这部分的设计文档。需求文档需要非常详细,每个测试人员和开发人员要清楚的知道自己那部分的需求是什么。设计文档中软件规格说明书一般由PM编写,不涉及具体的技术细节,是用户需求到软件需求的一个转化。这部分也需要很详细。设计文档还包括SE编写的软件设计文档(系统架构,数据库设计,接口设计,类图,事件流程等),但是可以是一个初步的第一版的设计。如在开发阶段,那每个迭代的主要输出就是程序了。

刚接触迭代开发的人会觉得很简单,但是真正做了之后就发现根本无法估量后面的工作量。甚至后面的几个Milestone都无法确定时间,这真是件头疼的事情。事实上,这却是很难。在现实生活中,有这几种情况。一、项目是时间点驱动的。比如某某时间会开一个软件大会,某某时间是娱乐,游戏软件的黄金上市时间,某某时间是行业大会等等。这种情况下,时间就是确定的了。所要做的就是把这些时间里面能够完成的功能做出来。二、项目是有固定截至时间的,无论是合同规定还是成本要求都使这种情况最普遍。这种情况下面,首先把几个大的阶段分出来。只要粗略地分一下即可。但是对于需求分析阶段,却需要仔细的分配时间。因为往往需求阶段只有一个迭代。后面就直接进入设计阶段了。因为需求分析的这个迭代和设计阶段的第一个迭代需要在一开始就定义清楚退出条件的。这个阶段的需求包括系统总体的需求和一部分地层的,关键的需求。因此需要对所有的需求分优先级,然后完成一部分最高的。估算迭代的具体方法会在后续文章中详细介绍,这里就说一个宗旨,估算迭代只要估算清楚当前的和后面的一到两个即可。

有些公司在迭代模型的基础上,详细的定义了每个阶段的输出,并且附带实行的方法,可称之为一套完整的方法论,其代表就是RUP(Rational统一过程)和MSF(微软解决方案框架)。RUP把原先上面我说的一维阶段--需求,设计,开发等变成了两维的--时间和内容。时间分为初始、细化、构造和交付;内容则用工作流定义分为建模、需求、设计、实现、测试和部署这几个核心工作流和配置管理、变更管理、项目管理和环境这几个支持工作流。每个时间阶段里面都有一到多个迭代,每个迭代中都有不同的工作流,每个工作流的制品输出也不同。每个工作在不同时间的不同迭代里面占的比重不同。看下其概念图,很容易理解。


MSF的体系很复杂,包含了开发过程,团队合作,技术体系等一系列内容。这里不考虑其他的东西,仅仅考虑其开发过程。MS的开发过程分为planning, initialization,implementation,stabulization和release这几个阶段。其实这样的分法更科学。第一个是计划(planning)而不是需求更表明了他们在迭代开发时候的灵活性。这两套体系都是他们根据各自的多年经验积累而成的,但是选择使用却要符合自己公司的现状,不能照搬照套。

4. 敏捷开发(Agile)
敏捷开发严格来说不是一种开发模型,也不是一种严格的生命周期模型。我更倾向于称它为一种理念。敏捷开发门派众多,我所知,所用也是有限,因此就拣这些我接触过的来整理比较好。说它是理念,因为敏捷开发实际上仍然逃不出需求,设计,开发,测试和发布这几个基本元素。它只是把这些元素的具体实践方法做了一些改动,使其适应性更强,灵活性更高,交互性更好,时效性更强。比如XP(eXtremeProgramming),有12种实践方法用来提高各个阶段的输出质量。它提倡的是快速开发,做出可交付的产品,交由客户使用,获得反馈,然后继续下一轮迭代。但是注意,它不是随便做做,我们以前做原型都是报着可作可不坐的心态,但是XP提倡的是“可交付的产品”,这句话保证了其质量品级。XP提倡TDD(Test Driven Development)测试驱动开发也是一个非常有用的实践。通过写测试用例,程序员很清楚这个功能的需求是什么,要达到什么目标才算通过,有目标的行为,当然效率要高些。Scrum有15min standing meeting,提倡开会少而精,每天跟踪进度,让每个人清楚三件事情:昨天已经做好什么,今天要做什么,现在有什么问题!

敏捷开发现在正在慢慢被人接受,别人认可。但是在真正的应用上,我个人认为还是应该先练习“楷书”--传统过程,再学习“草书”--敏捷开发。这样才能以不变应万变,特别是对年轻的没有经验的团队。君不见发明Agile的都是那些大胡子秃顶的老头么?他们的经验何其丰富,草书再草也不会失去控制变成涂鸦。


总结一下,软件开发方法很多,但是经典的就这么几种。重要的不是方法本身,而是知道在什么时候使用什么方法。比如自己做个习作,就一两个月的时间,需求明确,那用瀑布模型是最省力省心的。总之两句话: Do right things! Do things right!