软件开发方法论概述

软件开发方法论概述

在60年代的软件开发行业,随着所开发的软件复杂度不断提升,使用原先的方法(1)开发出来的软件终于不能满足需要,其所出现的问题是层出不穷,而且由于缺少必要的文档,人们又没办法寻找定位出其中的问题所在。更有甚者,就算是找出其中的问题,但由于软件设计的杂乱不堪,其修改起来也是叫人头大...于是,终于爆发了所谓的软件危机。

危机爆发后,人们认识到之所以出现这类危机的原因,那是因为没有使用一种系统性的方法来规范软件的开发过程,导致开发出的软件缺少架构不明晰,代码编写不规范,文档缺乏等等问题。最终使得开发出来的软件可靠性大大下降,以至于到了不可使用的地步。

为了解决这种问题,北约组织各国的计算机专家于60年代末召开了两次国际会议(NATO Software Engineering Conference(2))来讨论软件危机问题。会议上提出了“software engineering”一词。从此,为解决软件危机问题,诞生了一门新兴的学科——软件工程学。

经历了几十年的发展,软件工程学这门学科,提出了很多实际可用的软件开发方法。这其中,最著名的,也是业界使用最广泛的,当属结构化的方法和面向对象的方法。本文标题内面向过程的分析(POA),其实就是结构化的分析(SA)。

记得我们在前面介绍课程的时候,说过任何程序都是由数据和处理这些数据的方法构成的,那么对于软件开发方法论来说,您仍然可以从这两方面去考虑。简单来说,您要仔细体会在某一个软件开发方法下,人们是如何考虑下面三点的:

  • ⒈ 人们如何从现实的待解问题中抽象出要处理的数据的?
  • ⒉ 人们是如何抽象出要处理这些数据的方法,并通过它们去解决整个问题的?
  • ⒊ 人们在将所抽象出的数据和方法映射到程序的时候,是如何考虑的?是数据方法分开考虑呢,还是一并考虑?

 

本文只重点讲述结构化的方法和面向对象的方法。您如果也有兴趣了解其他方法,还请广泛使用google/baidu。本文在讲述此两方法的时候,将尽力避免繁杂晦涩难懂的理论措辞,而通过一些具体的例子让您明白其中原理。

结构化的方法

按照软件生命周期的定义,结构化的方法可以分成三个阶段,即结构化的分析(SA)、结构化的设计(SD)、以及结构化的编程(SP)。由于下面的内容重在讨论结构化的分析,所以标题也只说分析,不说设计和编程。这点在讨论面向对象的方法时,也是一样。

1>.理论概念

概念上来说,结构话的方法,就是将整个系统分成为若干个功能上独立的模块。然后针对每个模块,自顶向下的,逐步求精其中每一个层次的各个功能步骤。考虑的时候,需要注意下面三个要素(合称IPO):

  • ⒈ 模块或者各功能步骤都需要一些什么样的数据作为处理对象(输入Input)
  • ⒉ 模块或者各功能步骤都是完成什么功能的(Process)
  • ⒊ 模块或者各功能步骤完成了相关处理后,输出了什么数据(Output)

2>.数据流图(DFD)

数据流图(DFD)是进行结构化分析的主要工具。在DFD里面,主要有四个要素:

  • ⒈ 信息终端(起点或终点)
      它表示需要和待开发系统相交互的外部实体。它可能是:
    •  
    • a, 是使用该系统的用户;  
    • b, 公司以外的某个组织(待开发系统工作在整个公司范围内);  
    • c, 公司以内的其他部门(待开发系统只作用在公司的本部门);  
    • d, 需要和待开发系统交互的其他计算机系统;

      信息终端在DFD中用一个矩形来表示:

     

    数据流图(DFD)中的一个信息终端
  • ⒉ 信息流
      它表示待开发系统内,从某一部分流动到另外一部分的信息集合。
      信息要么流入到某个处理,要么自某个处理中流出。
      信息流表示系统中运动着的数据,而数据存储则表示系统中静止存储着的数据。
      信息流在DFD中用一个箭头线段来表示:

     

    数据流图(DFD)中的一个信息流
  • ⒊ 功能处理过程
      它是数据流图中最重要的部分,它需要对某些输入数据进行处理,处理完后输出处理结果。
      所输入的数据和所输出的结果在DFD中都用信息流来表示,最终形成一个串。
      对于结构化的方法而言,其核心工作就是自顶向下的逐步细化这些功能处理过程。一个系统可能分解成若干个模块,而每个模块最后则会变成由信息流连接的一系列处理过程。
      功能处理过程在DFD中用一个圆角矩形来表示:

     

    数据流图(DFD)中的一个功能处理过程
  • ⒋ 数据存储
      它表示待开发系统内,某些静止存储着的数据。
      数据存储在DFD中用一个缺失了右边的矩形框表示:

     

    数据流图(DFD)中的一个数据存储

3>.用结构化方法分析CBM项目

知道DFD的构成元素后,我们可以通过一个具体的例子来学习如何使用结构化的分析方法。我们的例子名为CBM项目,在此感谢加拿大多伦多大学计算机系的约翰.迈罗包罗斯教授给我们提供了这样一个例子,您可以访问他在多伦多大学的主页

注意不管您使用的是结构化的方法,还是后面要介绍的面向对象的方法,其分析材料均来自于一个系统的最原始需求描述文档。许修文档的描述详尽程度直接影响着后面的分析质量,进而影响接下来的设计及编码,所以在您开始分析一个项目之前,请务必把需求材料收集全面,需求文档直接用中文或英文等自然语言描述。

  • A,CBM项目的需求
     
    我们通过仔细调查走访,得到CBM项目的需求描述如下(其实这个需求文档并不详细的足以支撑系统的开发,但这里作为例子用已经足够了):
     
      现在有一家公司,名为“The Computer Books By Mail Corp.”,其主要业务是作为计算机专业书籍的零售商,接受顾客的订单(顾客通过email或者电话下单)。订单审核通过后,该公司会从仓库里面提取所需要的书籍,发运给对应的顾客。如果仓库里面不具备足够数量的,或者没有所需要的书籍,该公司会向相关的出版商发出订单,以较低的价格购买后再发运给顾客。顾客在收到书籍后,再依据该公司给开具的发票,付清书款。注意,在做生意过程中,公司极重视诚信,在每次业务之前都会进行信用检查。
     
      现CBM Corp.公司要求我们开发一个计算机系统,用以自动化的处理此主要业务。
     
  • B,最顶层数据流图
     
      我们在粗略分析CBM项目的需求后,得知要开发的系统比较简单,其中只需要一个模块,所以我们马上在纸上画下最顶层的数据流图如下:

     

    CBM项目顶层数据流图

    图一: CBM项目顶层数据流图


      该系统只需要一个模块(Process orders)。该模块接受顾客下单后,会检查该顾客的信用程度(Customer Data)。信用检查通过后,该模块会从当前仓库中(Book Data)所订书目发运给顾客(当然,如果仓库中有的话),在发运的同时会附上发票。
     
  • C,第一层数据流图之一
     
      对于分析来讲,上面的DFD显然太过于粗糙。需求中有提到收到顾客订单后如果发现库中书目数量不够,公司会向相应的出版商订购书籍以便满足顾客需求。那么,作为细化顶层DFD中Process orders处理(模块)的第一步,我们另外建立系统的第一层数据流图,并将此需求表现在其中:

     

    细画顶层数据流图的第一次尝试----生成CBM项目的第一层数据流图

    图二: 第一次尝试后的第一层数据流图


      我们在第一层DFD中新建了两个process,一个用于检查顾客所下的订单是否有效(主要是看该顾客信用是否达标),检查后如发现仓库内书目数量如果不够,那我们用另外一个process来生成要发送给相应出版商的订购申请,以便满足顾客的购书要求。
     
      注意,第一层数据流图是对顶层数据流图内处理Process Oders的细化,所以我们得保证流入流出处理Process Orders信息流的一致性。但是,对比我们刚刚画出的第一层数据流图和顶层数据流图,显然这种一致性没有得到满足,所以我们还得在这第一层数据流图上加点什么。
     
  • D,第一层数据流图之二
     
      上面所说的一致性要求我们要给顾客返回他所购买的书籍以及发票。不从一致性角度考虑,返观我们的需求文档,也要求我们的第一层数据流图上有这样的信息流反馈给顾客。其实这里,最本质得决定这一点的,其实是我们的需求,而并非一致性原则。所以,切记您的需求一定要分析到位,并且在您画顶层DFD的时候要保证一点,那就是在系统与外界交互的边界上不漏掉一点东西。这点做到了,此后细化DFD的时候,就只需要简单的遵循一致性原则即可。
     
      我们在这里先考虑系统如何处理向顾客发运所购书籍,先不考虑发票问题。另外,在CBM公司向出版商订购书目的时候,我们也要接收出版商所发的书目,这里一并考虑之。我们将所有这些先表现在第一层数据流流图中,如下示:

     

    细画顶层数据流图的第二次尝试----往第一层数据流图中添加反馈给顾客的书本信息流

    图三: 第二次尝试后的第一层数据流图


      我们额外添加了三个process用于处理向顾客反馈所订购书目,以及验证我们从出版商那里订购的书目。
     
  • E,细化任何一个需要细化的处理
     
      结构化的分析方法总是这样,当你画出一个初步的DFD后,你肯定需要进一步细化其中的每个Process。细化出第一层后,您得再看看这些Process是否已经足够清楚可用来设计与开发了,如果不够,那您还得再行细化那些比较烦琐的Process。那么到底需要多少层呢,这也没有标准答案,就看您团队里的共识了。感觉到没?这就是结构化方法的精髓,即自顶向下,逐步求精。
     
      还没感觉到也不要紧,我们再来细化第一层数据流图中给出版商准备订单的那个Process,即Assemble requisition to publisher:

     

    细画第一层数据流图中的复杂Process----生成CBM项目的第二层数据流图

    图四: CBM系统的第二层数据流图

  • F,最终的概念模型
     
      我们将返回发票给顾客的功能也考虑到第一层数据流图里面去,这样构成了CBM系统的整个概念模型,如下示:

     

    细画顶层数据流图的第二次尝试----往第一层数据流图中添加反馈给顾客的书本信息流

    图三: 第二次尝试后的第一层数据流图

4>.其它方面

经过了上面例子的分析,您对如何用结构化的方法来分析系统应该有所感觉了。说到底,还是那八个字,自顶向下,逐步求精。但若要在实际项目中熟练运用,还需仔细体会其中思想,时刻注意培训锻炼自己的思维。

回到我们当初考虑问题的着眼点上来,还记得么?数据和方法。那么,您认为DFD图建模的重点是偏向数据呢,还是方法?显然,是方法。那么结构化的思想中,如何去分析系统中数据的呢?需知,DFD中那些信息流都可能包含有更详细的数据项噢,而且各种信息流中都会牵扯上关系。呵呵,这里的答案就是E-R图,中文称之为实体-关系图。相关资料,还请您先查找资料,自行学习吧。E-R图在数据库应用中使用尤其广泛。

对于结构化分析来讲,DFD和ERD是两种主要分析的工具,但是光用这两种工具还不够。为什么?看看我们画的DFD图,我们能用图描述完系统中的所有需求信息么?显然是不行的。我们还得借助另外两项文字性工具:Data Dictionary(数据词典)和Process Specification(处理规约)。前者,用于描述系统中涉及到所有名词定义,每个名词定义都有可能包含有不同的数据项;后者用来描述各个Process的操作步骤,也即操作序列。关于这些,也请您查找资料进行学习。其实,系统分析中,任何一种分析方法,也都是图示搭配文字描述的,这点在后面的面向对象分析中也可得到验证。

结构化的分析(SA)完成了,后面的SD和SP就比较简单了。如果您是用C语言开发,那说白了,其实就是定义C结构和写C函数了。这个并不难,不在本文的讨论范围之内。

5>.参考资料

关于结构化分析的参考资料,网上还非常多的。我仅给大家推荐一份PDF文档:即 Ed Yourdon 所著的《Just Enough Structured Analysis》,您可于此处下载,仔细研读。

在进入开发行业后,我们的同学不应该让自己只拘泥于某种技术细节,更应关注其背后的思考方法,想方设法地努力掌握底下的思维习惯,这对以后的发展大有裨益。

其实,在软件领域,没有什么比系统分析更能体现总体智慧了。想想看,其他人在那边哼哧哼哧写代码的时候,你却在那千里之外运筹帷幄,这是何等的不一样。我极同意 Ed Yourdon 关于系统分析的论述:

In fact, systems analysis is more interesting than anything I know, with the possible exception of sex and some rare vintags of Australian wine.

所以,将此作为你毕生的兴趣吧。

面向对象的方法

相较于结构化的方法而言,面向对象的方法是现今开发软件的趋势性方法。它有着和结构化方法截然不同的思维方式,虽说不同,但此种方法却极好理解,因为你我每天都在生活中用着它,只不过不自知罢了。

1>.何谓对象

面向对象,重点自然是对象。那何所谓对象呢?其实,在我们日常生活中所见的任何事物,你都可以作为对象。您的宠物狗,早上刮胡子用的电动剃须刀,上班用的自行车,写程序用的电脑等等。。。放眼望去,进入您眼帘的皆可为对象。

当我们说到这些对象的时候,脑袋里总会浮现它的特定轮廓。说到猫,总知道它有四条腿,两个眼睛,身上有毛,叫声是喵喵的;说到电脑,总会知道有个屏幕,有个键盘,如果是笔记本电脑,还会有一个电池,电池上的电量可能不能坚持多久等等。。。所有这些,都是用来描述你头脑里的那个对象的。确切的说,这些都代表了对象某一方面的性质。所有性质综合起来,也就描述了这个对象。

另外一方面,这些对象都能有自己的某种行为,或者为外界所利用的某种能力。比方你踢了猫一下,猫就会喵喵叫着跑离开你;你打开电动剃须刀的开关,它如果有电的话,就会开始运转;你跨上自行车,用脚踏自行车的脚蹋,自行车它自己就会向前移动;等等诸如此类,都是对象本身所能执行的某种行为。即便看起来好象没有自己行为的石头,也是如此。试想假如石头本身有个不为零的速度,那么按照牛顿运动第一定律,它自己就能继续运动下去。再比如它的温度如果升高到一定程度,其形态就有可能由固态变化到液态等等。

再次回到前面我们所提考虑问题的着眼点上面来。结构化的方法,是把数据和方法分开考虑的,但是面向对象的方法又是如何的呢?你知道,对于一个完整的对象来说,性质和行为必不能分开考虑。它们两者缺一不可,无论丢开了哪个,对象即不成其为对象。其实性质和行为分别对应于数据和方法,可见,面向对象的方法把数据和方法联合起来考虑了。

在面向对象的术语里,对象的数据称之为对象的属性(attribute),对象所能具有的行为称之为方法(method)。将属性与方法合并起来考虑,称之为对象的封装(encapsulation)。

另外注意,对象在执行某种行为的过程当中,通常需要改变这个对象的某些数据,也就是改变整个对象的状态。比方你在使用电动剃须刀的过程中,剃须刀的会电量随之下降。

2>.对象之间的交互

既然这世界是由对象所组成的,那么对象之间也就必定会有交互。比方你踢猫,你是一个对象;你踢的那只猫也是一个对象。你们两个对象之间就是一种交互。

那这种交互又是如何发生的呢?在你踢猫这个例子中,你踢猫是你这个对象使用自身的踢这个行为,这个行为作用到了猫这个对象身上。猫在被踢后,喵喵叫着跑离开你。在这里,猫这个对象的叫和跑这两个行为得到了执行。那试想,是谁执行了这两个行为?显然是猫,但这里与其说是猫,还不如说是你在执行踢行为的过程中执行了猫的叫行为和跑行为。不是么?难道你踢猫不正是想让猫走开,或者听几声猫的惨叫来取乐?

所以假如你的名字叫Jason,你的猫叫Jack.那么我们可以认为:Jason在踢方法内,调用了Jack的叫方法和跑方法。用面向对象的记号记作:“Jason.踢(Jack)”调用了“Jack.叫()”和“Jack.跑()”。括号中的Jack是Jason对象踢方法的参数,表示踢行为的作用对象。

用另外一种说法,我们认为:Jason在执行踢方法的过程中,给Jack发送了两个消息以作为命令,Jack收到此两消息后,执行了自己的方法。这正是对象之间交互的实质所在,也即对象之间通过发送消息来进行交互。

3>.封装和信息掩藏

前面我们讲了将属性和方法结合起来考虑,称之为对象的封装(encapsulation)。但封装的目的更是为了达到信息掩藏(information hiding)。

举个例子,比方你开一辆汽车。你只要踏下油门踏板就好。至于在汽车油门踏板被压下后,内部如何燃烧燃料,汽车如何驱动内燃机做活塞运动,以产生牵引力等等,你是不需要关心的。实际上,它将很多内部细节掩藏起来,而只给你提供某种可以简单易用的接口(interface),用这些接口,你就可以使用汽车所具有的能力--开动跑起来以运东西。

实际上,接口(interface)规定的,是你如何使用这个对象的这种能力。至于对象在其内部如何动作以体现这种能力,那是属于实现(implementation)的范畴。

信息掩藏(information hiding)是面向对象里的关键概念,也是面向对象方法之所以能战胜结构化方法的重要原因。其存在不仅大大简化了外界使用对象的方式,更在于它不允许外界随随便便就去修改对象内部的数据和状态。回想一下前面结构化分析的方法,所有信息流指代的数据都是全局的,也就是说所有的处理都可以去修改这些数据,不管这种修改是出于有意的,还是无意的,总之它没有提供一种禁止修改的机制,这在实际上带来了很多问题。但是面向对象的方法就不同,所有数据都作为属性放在对象内部的,对它们的修改也都是可控的,因为对象本身是可自知的。

4>.类之抽象

人类区别于其他动物的一个关键因素是具备抽象思维的能力。那么既然普世都是由对象所组成的,那么何不将它们按照彼此相近程度分门别类来理解这个世界呢?其实面向对象的思考方法正是这样的。

你的猫叫Jack,"猫和老鼠"里有只猫叫Tom,另外还有只肥猫叫"Garfield"...这所有的猫都是一个个具体的对象,虽然毛色可能不尽相同,但本质上都是会喵喵叫的猫。所以,我们可以将其归为一类:猫。相仿的,你能找出其他很多对象,并归为不同的类(class)。

类(class),顾名思义,乃描述了一系列具有共通性质的东西。比如猫类,其描述的必定是一些长有四条腿的,会喵喵叫的,身上长有一层毛皮的东西。所以类描述了所有对象共通的属性和行为。至于其他的,比方说毛皮的颜色,Jack,Tom,Garfield可能各有不同,也很正常,因为这正是此猫区别于其他猫的所在之处。

倘若我们现在在猫类里面新添加一个名为毛色的属性。那么Tom的灰白,Garfield的橙色,皆为毛色属性的一个实例,对否?所以,何不把这种思维扩散开来,认为Jack,Tom,Garfield等个体皆为猫类的不同实例?:)实际上,正是如此,面向对象的方法里认为对象皆为某个类的不同实例(instance)。

实际上,类(class)有如建筑师手里的设计蓝图,只要有足够的财力和意愿,我们就可以从同一份设计蓝图出发,建造出一样的多幢建筑来。但是,正如哲学家莱布尼茨所说:“世界上没有两片完全相同的叶子”,我们认为它们是几个独立的、不相同的对象。用面向对象的术语来说,从类出发,创建出不同的对象,称之为实例化(instantiation)。

5>.类之继承

上面我们抽象出了猫类,另外,你也可能抽象出了狗类,牛类等等。这些类里面,有一个共通的性质,那就是胎生。既然是共性,那将它们放在不同的类里,就比较冗余。于是我们再另外抽象出一个类,哺乳动物类,并将胎生等性质放到这里类里面。然后将胎生等性质从猫类、狗类、牛类等类里面删除,接着让它们继承自哺乳动物类。

经过这样的一次继承,猫类等仍然拥有胎生的性质,只不过此性质并非原先存于猫类中的那个胎生性质(已被删除),而是自哺乳动物类继承得来的。不仅类的属性可以继承,方法也可以通过继承得到。

不管是猫,还是狗和牛,都要吃东西。虽然吃的东西可能不尽相同,但是其吃东西的方法,则均是将食物放在口腔里,咀嚼过之后咽下,然后到胃里面消化。。。所以,我们与其将吃方法放在不同的猫类,狗类及牛类里面,倒不如将其放在哺乳动物类里。如此,记号“Tom.吃()”调用到的就是继承来的那个方法。

像前面那个样子,抽取猫类,狗类及牛类的共性,继而抽象出哺乳动物类的方法,其实是一种泛化(generalization),很显然,哺乳动物类的范畴大多了。反过来,我们认为猫类,狗类及牛类则是哺乳动物类的不同特化。

用面向对象的术语来讲,哺乳动物类称为其他三个类的基类,而其他三个类则继承自哺乳动物类,被称为派生类。

继承或者泛化是面向对象世界里类之间的最基本关系,其他关系还有诸如关联,聚合,包含等等。您若有兴趣,可在久联技术的课堂里面通过例子学习。

6>.多态

多态(polymorphism)是面向对象方法里最叫人着迷的地方,也是新手最难以理解的地方。那什么是多态呢,多态多态,一个东西多种状态?:)这是纯粹从字面上得来的理解。我们还是举例来说明吧。

前面,我们说对象的时候,说过对象暴露给外界知道的,只是其接口,而非实现。接口只是规定了外界如何去使用对象的能力,而实现则归纳了该对象如何去实现这种能力。比方说,Tom猫有一个叫()接口让外界命令Tom猫去叫。而Tom猫收到这个命令,执行叫方法后,外界得到的是某一种类的空气震动。那么Tom猫是如何实现这个叫()接口的呢,则是震动其声带发出一种特定的震动波,这种震动波经过叫()接口返回给外界后,传到外界其他对象的耳朵里便是喵喵的声音。这是Tom猫对叫()的实现方式,如果Tom猫它自己愿意,它也可以发出另外一种震动波,让外界听到呼呼的声音。

Tom猫是喵喵叫的,Jack猫和Garfield猫也都是喵喵叫的,所以你在抽象出猫类的时候,势必会将叫方法的接口以及实现都放在猫类里边。如此,任何一个由猫类实例化出来的对象A,记号“A.叫()”必然也就是喵喵的。

同样的,你也会在狗类,及牛类里面加上叫方法的接口和实现。和猫类的叫方法相比,其接口叫()都一样,不同的只是各种动物实现叫()接口的方式而已,即它们发出了不同的震动波。好,那既然有这样一个原因,我们何不把叫方法的接口移到基类哺乳动物类那里,而在派生类里保留各自不同的实现?

经过这样的修改后,记号“Tom.叫()”仍然是喵喵的。现在假设有一只名为Bao的狗和一只名为Mo的牛,那么记号“Bao.叫()”和记号“Mo.叫()”仍然会是汪汪的和哞哞的。

好,现在我们用一个代词它来指代某一只哺乳动物,用另外一种记号“它->叫()”表示命令这只哺乳动物执行叫方法。而因为猫、狗、牛等皆属于哺乳动物,所以它可指代猫类、狗类、牛类的任意一个对象。当指代Tom猫时,记号“它->叫()”是喵喵的;当指代Bao狗时,记号“它->叫()”是汪汪的;当指代Mo狗时,记号“它->叫()”是哞哞的;

当它指代不同的派生类对象时,同一个记号“它->叫()”带来的结果确是不一样的。这正是多态的体现呐!所以本段开头用“一个东西多种状态”的论述来理解多态,虽然不甚精确,但也勉强尚可。

7>.面向对象方法小结

以上介绍了面向对象的一些基本观念,不算难,对吧?其实用面向对象的方法就是分离出待解问题中的各个对象,对他们之间的交互建立模型。继而抽象出不同的类,以及不同类之间的不同关系。最后用某种面向对象的语言(诸如C++,Java等等),来实现你所建立的模型。

关于面向对象,现在市面上很多书籍、很多课程一上来就给同学介绍很多高深的工具与语言。殊不知,最重要的是理解这背后的概念。所以花点时间是值得的,掌握好了这些概念之后,您才能慢慢的深入学好其他更多的东西,诸如C++,UML,Design Patterns等等。您若有兴趣,可以联系我们深入学习。

尽管我现在所从事的行业方向是嵌入式linux驱动开发,但我仍努力不断的以OO的方式来分析问题作为第二乐趣。我想,您也许可以和我一样。不过,在涉足OO领域之前,我仍强烈希望您先掌握好基本概念,因为我也极同意 Craig Larman 在文章"What the UML Is--and Isn't"中的论述:

Unfortunately, in the context of software engineering and the UML diagramming language,acquiring the skills to read and write UML notation seems to sometimes be equated with skill in object-oriented analysis and design. Of course, this is not so, and the latter is much more important than the former. Therefore, I recommend seeking education and educational materials in which intellectual skill in object-oriented analysis and design is paramount rather than UML notation or the use of a case tool.


注意:

1在软件开发的最初阶段,甚至都没用上什么方法。那个时候的软件功能都很单一,也都是自己写给自己用的,所以也就不需要什么工程性的方法。

2关于这两次会议的更详细情况,请看这里

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值