当前位置:文档之家› 软件开发过程

软件开发过程

软件开发过程
软件开发过程

软件开发过程

现代社会正变得越来越复杂,随之出现的问题也变得复杂了,这样解决问题就成一种生活方式。比如固体废料处理、全球变暖、国际金融、污染、核扩散等问题就是出现时间不长的新问题,该如何解决这些问题是对人类技术和能力的挑战。

大多数问题的解决方案要求考虑周全的计划,并需要预先考虑解决方案是否适当的和有效的。对于大多数程序设计的问题,需要考虑的因素也是如此。例如,通过反复试验为移动电话网络编写软件或者为百货公司创建管理程序的过程就

是如此。这样一个解决方案最好的结果是费用昂贵但效果良好,最坏的情况是损失惨重,脱离现实。

每一个研究领域都有器用于设计这些问题的解决方案所使用的系统方法的

命名规则。在科学界,这种方法称为科学方法,而在工程学科中,这种方法称为系统方法。为了理解需要解决的问题和为建立一个有效的且适当的软件解决方案,专业软件开发人员使用一种称为软件开发过程的方法。这个过程由下列四个阶段组成。

阶段1:确定程序的要求

阶段2:设计和开发

步骤1:分析问题

步骤2;选择一个完整的解决方案算法

步骤3:编写程序

步骤4:测试和修正程序

阶段3:文档编制

阶段4:维护

前三个阶段经常改进并相互影响,直到最终设计和程序被开发出来为止。而且在设计和开发阶段,你可能会发现问题没有被完全明确或分析,需要在初期的步骤做进一步的工作,以完成程序。每一个都将在下面的段落中讨论。

阶段1:确定程序的要求

这个阶段以问题的陈述或对程序的特定要求开始,称为程序的要求。你的任务是确保程序的要求被明确的陈述,而且要理解期望达到的目标是什么。例如,假设你收到一封来自主管的简短邮件,邮件内容是说我们需要提供一个关于圆的信息的程序。

这不是一个定义清楚的要求,他没有明确说明一个良好定义的问题,因为它没有准确地告诉我们要求什么信息。立即开始编写程序去解决这个缺少明确表达的问题将是一个严重的错误。为了弄清楚和定义这个问题的陈述,需要做的第一

步是向主管咨询准确的定义要产生的信息是什么以及能够提供的数据是什么。

假设你咨询了主管,并且知道升级想要的是计算和显示一个给定半径时求圆的周长的程序。只有在你了解了什么是一个清楚的陈述时,才可以进行下一步。

阶段2:设计和开发

一旦程序的详细说明已完成,形成程序设计过程核心的设计和开发阶段就可以开始了。这个阶段由下列四个步骤组成。

步骤1:分析问题。这个步骤要求确保问题事实上已经被清楚地说明和理解,并且已经为选择这个问题的算法提供了必要的信息。只有在你理解了下列内容时,这个问题才能被清楚的定义。

1.必须产生的输出

2.产生预期的输出所要求的输入数据

3.体现输入与输出之间的联系的公式

分析完成时,这三项中的每一项都必须清楚的定义。

在执行分析阶段,许新程序员喜欢首先确定数据,而在以后确定想要的输出,专业程序员则倾向于相反的工作方式。忽略输入而首先思考输出似乎对你来说有些奇怪,但输出是构造一个程序的首要的全部目的。知道了这个目的并将它牢记在心,能使你将精力集中于程序的重要方面。但是,如果你觉得一开始就确定输入数据会更轻松些,也可以这样做。

步骤2:选择一个完整的解决方案算法。这一步是确定和选择一个解决问题的算法。有时候确定完整的解决方案的算法相当容易,有时候它可能是复杂的。例如,确定某人口袋里零钱的数量或者确定一个矩形的面积的程序相当简单。但是,制造业公司的库存跟踪和控制系统的设计就比较复杂。在那些更完整的例子中,最初的解决方案的算法典型的被改进和被细化,直到这个算法极为详细地指明全部的解决方案为止。这个细化的例子稍后将在本节中提及。

在最普通的形式中,一个可应用于大多数C语言程序的完全的解决方案算法是:

获得问题的输入

计算期望的输出

报告计算的结果

这三个任务几乎是每个问题的主要责任,我们把这个算法称为问题解算机算法。例如,假设要求你用一个已给定的半径计算圆的周长,这个问题的解算机算法就变成:

设置半径值r

使用公式C=6.28r,计算周长C

显示C的计算值

对于只需执行一个或几个计算的小的应用,通常这个问题解算机算法本身就足够了。对于较大的程序,则必须将它组编成较小的算法,以使这些较小的算法能相互连接并能明确地细化最初的算法。下面将描述细化的完成过程。

细化算法。对于较大的应用,最初的解决方案算法典型地从问题解算机算法开始,必须细化并组织成较小的算法,以指明这些小算法相互之间是如何衔接的。要达到这个目的,解决方案的描述必须从最高级要求开始,并向下逐步细化到必须被构造的部分。为了便于理解,假设有一个要求跟踪库存零件数量的计算机程序。这个程序所要求的输出是描述库存的全部零件和每种零件的数量,输入是每种零件最初的存货总量、已销售的量、退回的量和新采购的量。

程序设计者最初可能把这个程序的全部解决方案算法组编为如图1.18下半部分所示的三个问题解算机算法部分。这称为算法的一级结构图,因为它表示了最初的、还不够足够详细的、用于一个解决方案算法的结构的首次尝试。

一旦开发了一个最初的算法结构,你就能把它细化,直到这些方框中表示的任务完全被定义为止。例如,图1.18中的数据输入部分应该进一步细化到指定的输入数据的规定。由于为不可预见性的和人为的错误做规划是系统设计人员的责任,因此还必须为修改已经输入的不正确的数据和删除前面输入的数值定义某些规定。报表部分的细化也类似。

图1.19表示的是进一步细化了的库存跟踪系统的二级结构图。

图1.18 一级结构图

注意这种设计将产生一种树形结构,当我们从这个结构的顶部移动到底部时,这些级的分支就体现出来了。当设计完成时,在较低的方框中所设计的任务典型的代表了一些简单算法,这些简单算法被结构中较高的算法所使用。这种类型的算法开发方法称为自顶向下的算法开发,它从顶端开始,在它向下达到最后一组算法的过程中,会开发出来越来越多的详细算法。

步骤3:编写程序。这个步骤是将选定的解决方案算法翻译为C语言计算机程序。这个过程也称为编码算法。

图1.19 二级细化结构图

如果分析和解决方案步骤已经正确完成,编写程序的过程本质上就有些机械了。但是在一个设计良好的程序中,组成程序的语句应该遵守已经在解决方案步骤中定义的某些定义良好的结构,这些结构控制程序的执行并由下列类型组成。

1.顺序

2.选择

3.反复

4.调用

顺序定义了程序执行指令的次序。它指明了指令将用它们在编码中出现的次序执行,除非被其他结构的指令明确的改变了。

选择提供了根据某个条件式的结果在不同的指令间进行挑选的能力。例如,在执行除法之前必须检查作为被除数的数字的值。如果这个数字是0,除法将不能执行并且将给用户发布一个警告信息,数字不为0时可执行除法。选择操作及它在C语言中的编码方法在第四章介绍。

重复,也称为循环和反复,提供根据某个条件式的值重复地执行某些操作的能力。例如,学生的考试分数可能被重复地输入和相加,直到一个负的分数输入时为止。在这个例子中,负分数的输入是表示分数重复输入和相加的结束条件。在这一位置,所有输入的分数的平均值的计算能够执行。重复操作和它们如何在C语言中被编码将在第5章介绍。调用,即在需要时运行指定的代码段。调用操作和它们如何在C语言中被编码将在第6章和第7章介绍。

步骤4:测试和修正程序。测试的目的是验证程序是否运行正确并实际达到它的要求。理论上,测试应该揭露所有存在的程序错误。在计算机术语中,程序的错误称为bug。实际工作中,程序测试要求检查所有可能的语句执行的组合。由于所要求的时间和效果,这通常是一个不可能达到的目标,除非是极简单的程序。

对大多数程序而言,彻底的测试完全是不现实的。由于这个原因,各种测试

方法学逐渐发展起来。在这些方法的最基本层面,测试应该包括一个有意识的、能够确保程序正确运行和产生有意义的结果的效果。必须仔细思考这个测试想要达到的目标以及你在这个测试中将使用什么样的数据。如果测试揭露了一个错误,就必须着手调试程序,包括定位、纠错和验证这个纠错。重要的是,要认识到虽然测试可能揭露错误的存在,但并没有指明错误不存在。于是,虽然一个测试揭露了一个bug,但是这个事实并不表明另外的bug没有潜伏在程序中。

为了捕捉和修正程序中的错误,首要的是开发一组确定这个程序是否给出正确答案的数据。事实上,在正式的软件测试中,一个可接受的步骤是在编写代码之前规划这个测试过程和建立有意义的测试数据,这有助于程序员更加客观的理解这个程序必须做什么。这个测试应该检查一个程序将被使用的每一种合理的情形。这意味着测试应该使用在可接受的限制范围内的数据、在合理范围内的数据、使用程序应该检测和报告为无效数据的数据。事实上,开发优良的验证测试和使问题更加复杂的数据可能比编写这个程序本身的代码更加难一些。

阶段3:文档编制

实践中,大多数程序员在完成编程工作之后几个月就会忘记程序中许多细节。如果他们或其他程序员以后必须对程序进行修改,重新理解这个原来的程序时如何工作的就可能需要许多宝贵的时间。良好的文档编制能防止这种情况的发生。

这样多的工作变得无用或者丢失,这样多的任务必须重做,都是因为文档编制不完全,从而证明了文档编制时解决方案中最重要的步骤。实际上,有许多关键的文档需要在分析、设计、编码和测试过程中建立。完整的文档编制要求收集这些文档、增加附加的材料和对你或你的机构最有用的形式呈现它。

虽然,并不是每个人都用相同的方法把这些文档分类,但用于每个问题的解决方案基本上包含6个关键的文档。

1.要求陈述

2.将编码的算法描述

3.程序代码内的注释

4.按时间所做的修改和更改的描述

5.样本测试运行,包括每次运行使用的输入和获得的输出

6.用户手册,怎样使用这个程序的详细说明

一个大机构的团队中任何可能使用你的程序作品的人的换位思考——从秘

书到程序员再到用户——将有助于使重要的文档的内容和设计更清楚。文档编制阶段从阶段1正式开始,一直延续到维护阶段。

阶段4:维护

这个阶段的重点是问题更正、修改程序以满足变化的需求以及增加新的特点。

维护经常是主要的阶段、主要的收入来源和最持久的工程阶段。软件可能花几天或几个月的时间,而维护可能要进行几年或几十年。文档的编制的越好,维护阶段就越有效,客户和用户将越高兴。学生们通常会觉得奇怪,因为他们习惯于解决一个问题并继续转向一个不同的问题。但是,商业和科学领域不这样操作。在这些领域,一个应用或一个概念典型地建立在一个前面的应用之上并可能要求几个月或几年的工作。这在程序设计中尤其如此。一个应用程序可能花了几周或几个月的时间编写,当需要新的特点时,维护可能持续好几年。由于通信、网络、光纤和新的图形显示技术的发展,经常需要更新软件产品。

程序怎样能够容易的维护(修正、修改或者增强),与程序能够不费力的阅读和理解有联系。正如你已经知道的一样,这取决于程序在设计时的关注程度和高质量文档编制的可用性。

备份

尽管不是正式的软件开发过程的一部分,但在编写程序时制作何保留作品的复制品是最重要的。在修订程序的过程中,你可以容易的把程序的当前工作版本修改得面目全非。备份复制品能使你用最小的努力恢复最近时期的工作。一个有用的程序的最终工作版本至少应该备份两次。在这一点上,另一方有用的程序设计习惯用语是:“如果你不介意重新开始,备份是不重要的”。维护程序的三个基本规则是:

1.备份!

2.备份!!

3.备份!!!

大多数机构至少保持一份备份在能够获取的地方,而把另一份备份放在防火保险箱中或放在遥远的地方。

案例研究:设计和开发

这一节将把软件开发过程的设计和开发阶段应用到下面的程序要求。

圆的周长C可由公式C=6.28r确定,r是圆的半径。利用这个公式,编写一个C程序,计算半径为2英寸的圆的周长。

步骤1:分析问题

这一步验证这个程序说明的完整性,并证实我们已对所要求的东西有完全的理解。

1.确定期望的输出。在确定期望的输出过程中,应关注要求陈述中类似计算、打印、决定、查找或比较这样的表述。对于上面的样本程序的要求,关键的短语是计算圆的周长,这确定了一个输出项目。由于这个问题没有其他的类似短语,

只有一个输出被要求。

2.确定输入项目。在明确地确定期望的输出之后,必须确定所有的输入项目。在这一阶段,区分输入项目和输入值之间的差别是重要的。输入项目是输入量的名称,而输入值是能够用做输入项目的特定的数字或数量。例如在我们的程序要求中,输入项目是圆的半径。虽然在这个问题中这个输入项目有一特定的数字量,实际的输入值在这一阶段是不重要的。

在这一点上输入值是不需要的,因为输入和输出之间的关系典型地不取决于特定的输入值。公式取决于明确的输出和输入以及是否存在明确的限制。应注意输入和输出之间用公式表达的关系是否正确,而不必考虑任何赋给输入项的特定的值。尽管没有特定数值的输入项目不能产生一个实际的输出项目数值,但是输入和输出之间的正确关系可由相关的公式表达,这个公式接下来将列出。

3.列出相关输入和输出的公式。最后的步骤是确定如何根据输入建立输出,这由已知的输出和输入之间的公式回答。在本例中,这个关系由C=6.28r提供,式中C是输出项目,r是输入项目。还要明白这个公式不要求列出特定的输入值,只是确定输出与输入项之间的关系。

如果你不清楚如何从给定的输入获得所要求的输出,则可能需要更清楚的需求陈述。换句话说,你需要获得关于这个问题的更多信息。

4. 执行手工计算。有了列出的公式,下一步骤是用特定的输入值来检查这个公式。用手工或计算器执行一个人工计算有助于确保你真正理解这个问题。一个人工计算的另外的特点是这个结果以后能够用在测试阶段中验证程序的运行。然后,当最终程序用其他数据运行时,你就有足够程度的自信,相信正在计算的是正确的结果。

在这一步,我们需要能够赋予公式所使用的输入项目的特定的输入值,以产生期望的输出。对于这个问题,存在一个输入值:半径r为2英寸。把这个值代人公式,我们获得这个圆的周长C=6.28r=12.56英寸。

步骤2:选择一个全面解决方案的算法

在前面的段落中介绍的一般问题解算机算法是:

获得问题的输入

计算期望的输出

报告计算的结果

为了确定圆的周长,这个算法变成:

设置半径值r为2

使用公式C=6.28r,计算周长C

显示C的计算值

步骤3:编写程序

程序1.1展示的是计算一个半径为2英寸的圆的周长的代码。因为我们还没有介绍C语言,这个程序对你来说可能不太熟悉,但是你应该能够理解关键的行正在做什么。为了帮助理解,在程序中添加了行号。这些行号从来就不是C程序的一部分,但为了易于区分不同的C语句,将总是插入行号。

在本例中,程序遵循一个顺序次序,在这里每一个语句用严格的顺序次序一个接一个地执行。但是为了帮助你理解它,注释(也就是符号/*和*/之间的文本)已经包含在行号为5,7和8的语句中。虽然所有的程序行将在下一章才全面地解释,但是现在我们只需注意这三行并使用这些注释把这些行与分析阶段选择的算法相联系。

在行号5中,定义了由这个程序使用的名称radius和circumference。这

个程序没有对这些名称附上任何的意义(例如名称r和c,x和y,或者in和out 都同样可以定义),但是应该总是选择更多的描述性的和对实际问题有些含义的名称。在行号7中,赋给了名称radius一个数值,而在行号8中,一个名为circumference的项目进行了计算。最后在行号9中,输出circumference的值。

程序1.1

1 #include < stdio.h >

2

3 int name ()

4 {

5 float radius, circumference; /* declare an input and output item */

6

7radius =2.0;

8circumference =2.0 * 3.14 *radius;

9printf (“The circumference of the circle is %f\n”, circumference);

10

11return 0;

12}

当执行程序1.1时,产生下列输出:

The circumference of the circle is 12.56

步骤4:测试和修正程序

因为只有一个计算由这个程序执行,测试程序1.1实际上意味着验证这个

输出是否正确。因为这个输出与我们前期的手工计算相符,我们现在能够使用这个程序用不同的半径计算圆的周长,并且将自信这个结果是正确的。

常见编程错误

学习任何编程语言的人正在犯一些基本的错误,而这些错误在你之前其他刚入门的程序员也同样犯过。每一种语言都有它自己的一组常见编程错误在等待你的粗心大意,这些错误往往使人感到十分失望。与这一章介绍的材料相关的最常见的错误如下:

1.没有花足够的时间研究问题或者没有花足够时间设计合理的算法就匆忙去编

写代码、运行程序。在这一点上,记住一条编程习惯用语是非常有用的“没有充分理解某个问题就不可能设计一个成功的程序”。一个类似的和等价的习惯用语是:“对应用进行编程所花的时间越短,通常调试和编译用的时间就越长”。

2.忘记备份程序。几乎所有的新程序员都会犯这个错误,直到他们丢失一个花

费了大量时间编码的程序为止。

3.不理解计算机只响应明确定义的算法。告诉一台计算机加一组数字与告诉一

个朋友加这些数字完全不同。计算机只接受用编程语言描述的加法的精确指令。

if-else 语句

if-else语句引导计算机根据比较结果选取一个以上的指令序列。例如,如果新泽西州居民收入少于20000美元,适应州收入税率是2%,如果个人的收入大于20000美元,对超过20000美元的部分应用不同的税率。在这种情形中能够使用if-else语句确定基于毛收入是否少于或等于20000美元的实际收入的实际税额。最常用的if-else语句的形式是:

if (表达式)

语句1;

else

语句2;

首先计算表达式的值,如果表达式的值为非0,相当于这个表达式为真,执行语句1,如果这个值为0,则执行语句2——保留字else之后的语句。这样两个语句之一总是取决于表达式的值来执行。注意这个被测表达式必须放入括号中,而分号只放在每个语句的终止处。

程序4.2

1#include

2#define LOWRATE 0.02

3#define HIGHRATE 0.025

4#define CUTOFF 20000.0

5#define FIXEDAMT 400

6

7int main()

8{

9float taxable, taxes;

10

11printf(“please type in the taxable income:”);

12scanf (“%f”, &taxable);

13

14if (taxable <=CUTOFF)

15taxes = LOWRATE*taxable;

16else

17taxes =HIGHRATE*(TAXABLE –CUTTOFF) +FIXEDAMT; 18

19printf(“Taxes are $%7.2f\n”, taxes);

20

21return 0;

22}

相关主题
文本预览
相关文档 最新文档