您的位置: 网站首页 > 公共课 > 新编计算机文化基础 > 第7章 程序设计基础 > 【7.3 软件工程基础】

7.3 软件工程基础

 

软件工程是指导计算机软件开发和维护的工程学科,它使用工程化的概念、原理、方法和技术来指导软件开发的全过程,使软件的质量、软件的可靠性、软件开发的成功率和软件开发的生产率大幅度提高。本节对软件工程的基础知识作由浅入深的介绍。

7.3.1  软件工程的概念

1.软件定义与软件的特点

计算机是由软件和硬件组成的,计算机软件是程序、数据及相关文档的完整集合。其中,程序是软件开发人员根据用户需求开发的用程序设计语言描述的、适合计算机执行的指令(语句)序列。数据是使程序能正常操纵信息的数据结构。文档是与程序开发、维护和使用有关的图文资料。可见软件由两部分组成:一是计算机可执行的程序和数据;二是计算机不可执行的,与软件开发、运行、维护、使用等有关的文档。

国标(GB)中对计算机软件的定义为:与计算机系统的操作有关的计算机程序、规程、规则,以及可能有的文件、文档及数据。

软件在开发、生产、维护和使用等方面与计算机硬件相比存在明显的差异。深入理解软件的定义需要了解软件的特点。

1)软件是一种逻辑实体,而不是物理实体具有抽象性。

2)软件的生产与硬件不同,它没有明显的制作过程。一旦研制开发成功,可以大量拷贝同一内容的副本。所以对软件的控制,必须着重在软件开发方面下功夫。

3)软件在运行、使用期间不存在磨损、老化问题。

4)软件的开发运行对计算机系统具有依赖性,受计算机系统的限制这导致了软件移植的问题。

5)软件复杂性高,成本昂贵。

6)软件开发涉及诸多的社会因素。

软件按功能可以分为:应用软件、系统软件、支撑软件(或工具软件)。应用软件是为解决特定领域的应用而开发的软件。系统软件是计算机管理自身资源,提高计算机使用效率并为计算机用户提供各种服务的软件。支撑软件是介于系统软件和应用软件之间,协助用户开发软件的工具性软件,包括辅助和支持开发和维护应用软件的工具软件。

2.软件危机与软件工程

软件工程概念的出现源自软件危机。

所谓有软件危机四伏是泛指在计算机软件开发和维护过程中所遇到的严重问题。实际上,几科所有的软件都不同程度地存在这些问题。

随着计算机技术的发展和应用领域的扩大,计算机硬件性能/价格比和质量稳步提高,软件规模越来越大,复杂程度不断增加,软件成本逐年上升,质量没有可靠的保证,软件已成为计算机科学发展的“瓶颈”。

具体地说,在软件开发和维护过程中,软件危机主要表现在以下几个方面:

1)软件需求的增长得不到满足。用户对系统不满意的情况经常发生。

2)软件开发成本和进度无法控制。开发成本超出预算,开发周期大大超过规定日期的情况经常发生。

3)软件质量难以保证。

4)软件不可维护或护程度非常低。

5)软件的成本不断提高。

6)软件开发生产率的提高赶不上硬件的发展和应用需求的增长。

总之,可以将软件危机归结为成本、质量、生产率等问题。

软件工程就是试图用工程、科学和数学的大批量与方法研制、维护计算机软件的有关技术及管理方法。

关于软件工程的定义,国标(GB)中指出,软件工程是应用于计算机软件的定义、开发和维护的一整套方法、工具文档、实践标准的工序。

1993IEEEInstitute of Electrical &Electronic Engineers ,电气和电子工程师学会)给出了一个更加综合的定义:“将系统化的、规范的、可度量的方法应用于软件的开发、运行和维护的过程,即将工程化应用于软件中”。

软件工程包括3个要素:方法、工具和过程。方法是完成软件工程项目的技术手段;工具支持软件的开发、管理、文档生成;过程支持软件开发的各个环节的控制、管理。软件工程的核心思想是把软件产品看作是一个工程产品来处理。

开发软件不能只考虑开发期间的费用,而且应考虑软件生命周期内的全部费用。因此,软件生命周期的概念就变得特别重要。在考虑软件费用时,不仅仅要降低开发成本,更要降低整个软件生命周期的总成本。

3.软件工程过程与软件生命周期

1)软件工程过程(Software Engineering Process)。

ISO 9000定义:软件工程过程是把输入转化为输出的一组彼此相关的资源和活动。定义支持了软件工程过程的两方面内涵。其一,软件工程过程是指为获得软件产品,在软件工具支持下由软件工程师完成的一系列软件工程活动。基于这个方面,软件工程过程通常包含4种基本活动:

PPlan——软件规格说明。规定软件的功能及其运行时的限制。

DDo——软件开发。产生满足规格说明的软件。

CCheck——软件确认。确认软件能够满足客户提出的要求。

AAction——软件演进。为满足客户的变更要求,软件必须在使用的过程中演进。通常把用户的要求转变成软件产品的过程也叫做软件开发过程。此过程包括对用户的要求进行分析,解释成软件需求,把需求变换成设计,把设计用代码来实现并进行代码测试,有些软件还需要进行代码安装和交付运行。其二,从软件开发的观点看,它就是使用适当的资源(包括人员、硬软件工具、时间等),为开发软件进行的一组开发活动,在过程结束时将输入(用户要求)转化为输出(软件产品)。所以,软件工程的过程是将软件工程的方法和工具综合起来,以达到合理、及时地进行计算机软件开发的目的。软件工程过程应确定方法使用的顺序、要求交付的文档资料、为保证质量和适应变化所需要的管理、软件开发各个阶段完成的任务。

2)软件生命周期(Software Life Cycle)。

通常,将软件产品从提出、实现、使用维护到停止使用退役的过程称为软件生命周期。一般包括可行性研究与需求分析、设计、实现、测试、交付使用以及维护等活动。还可以将软件生命周期分为软件定义、软件开发及软件运行维护三个阶段。软件生命周期的主要活动阶段如下:

可行性研究与计划制定。确定待开发软件系统的开发目标和总的要求,给出它的功能、性能、可靠性以及接口等方面的可能方案,制定完成开发任务的实施计划。

需求分析。对待开发软件提出的需求进行分析并给出详细定义。编写软件规格说明书及初步的用户手册,提交评审。

软件设计。系统设计人员和程序设计人员应该在反复理解软件需求的基础上,给出软件的结构、模块和划分、功能的分配及处理流程。在系统比软件复杂的情况下,设计阶段可分解成概要设计阶段和详细设计阶段。编写概要设计说明书、详细设计说明书和测试计划初稿,提交评审。

软件实现。把软件设计转换成计算机可以接受的程序代码。即完成源程序的编码,编写用户手册、操作手册等面向用户的文档,编写单元测试计划。

软件测试。在设计测试用例的基础上,检验软件的各个组成部分。编写测试分析报告。

运行和维护。将已交付的软件投入运行,并在运行使用中不断地维护,根据新进出的需求进行必要而且可能的扩充和删改。

4.软件工程的目标与原则

1)软件工程的目标。

软件工程的目标是,在给定成本、进度的前提下,开发出具有有效性、可靠性、可理解性、可维护性、可重用性、可适应性、可移植性、可追踪性和可互操作性且满足用户需求的产品。

软件工程需要达到的基本目标应是:付出较低的开发成本;达到要求的软件功能;取得较好的软件性能;开发的软件易于移植;需要较低的维护费用;能按时完成开发,及时交付使用。

基于软件工程的目标,软件工程的理论和技术性研究的内容主要包括:软件开发技术和软件工程管理。

软件开发技术。

软件开发技术包括:软件开发法学、开发过程、开发工具和软件工程环境,其主体内容是软件开发方法学。软件开发方法学是根据不同的软件类型,按不同的观点和原则,对软件开发中应遵循的策略、原则、步骤和必须产生的文档资料都做出规定,从而使软件的开发能够进入规范化和工程化的阶段,以克服早期的手工方法生产中的随意性和非规范性做法。

软件工程管理。

软件工程管理包括:软件管理学、软件工程经济学、软件心理学等内容。软件工程管理是软件按工程化生产时的重要环节,它要求按照预选制定的计划、进度和预算执行,以实现预期的经济效益和社会效益。

软件工程经济学是研究软件开发中成本的估算、成本效益分析的方法和技术,用经济学的基本原理来研究软件工程开发中的经济效益问题。

软件心理学是软件工程领域具有挑战性的一个全新的研究视角,它是从个体心理、人类行为、组织行为和企业文化等角度来研究软件管理和软件工程的。

2)软件工程的原则。

为了达到上述的软件工程目标,在软件开发过程中,必须遵循软件工程的基本原则。这些基本原则包括抽象、信息隐蔽、模块化、局部化、确定性、一致性、完备性和可验证性

抽象。抽取事物最基本的特性和行为,忽略非本质细节。采用分层次抽象、自顶向下、逐层细化的办法控制软件开发过程的复杂性。

信息隐蔽。采用封闭技术,将程序模块的实现细节隐藏起来,使模块接口尽量简单。

模块化。模块是程序中相对独立的成分,一个独立的编程单位,应有良好的接口定义。模块的大小要适中,模块过大会使模块内部的复杂性增加,不利于对模块的理解,也不利于模块的调试和重用;模块太小会导致整个系统表示过于复杂,不利于控制系统的复杂性。

局部化。要求在一个物理模块内集中逻辑上相互关联的计算资源,保证模块间具有松散的耦合关系,模块内部有较强的内聚性,这有助于控制角的复杂性。

确定性软件开发过程中所有概念的表达应是确定的、无歧义且规范的。这有助于人与人的交互不会产生误解和遗漏,以保证整个开发工作的协调一致。

一致性。包括程序、数据和文档的整个软件系统的各模块应使用已知的概念、符号和术语;程序内外部接口应保持一致,系统规格说明与系统行为应保持一致。

完备性。软件系统不丢失任何重要成分,完全实现系统所需的功能。

可验证性。开发大型软件系统需要对系统自顶向下,逐层分解。系统分解应遵循容易检查、测评、评审的原则,以确保系统的正确性。

5.软件开发工具与软件开发环境

现代软件工程方法之所以能有效地实施,其重要的保证是软件开发工具的环境的保证,使软件在开发效率、工程质量等多方面得到改善。软件工程鼓励研制和采用各种先进的软件开发方法、工具和环境。工具和环境的使用进一步提高了软件的开发效率、维护效率和软件质量。

软件开发环境或称软件工程环境是全面支持软件开发全过程的软件工具集合。

计算机辅助软件工程(Computer Aided Software EngineeringCASE)是当前软件开发环境中富有特色的研究工作和发展方向。CASE将各种软件工具、开发机器和一个存放开发过程信息的中心数据库组合起来,形成软件工程环境。CASE的成功产品将最大限度地降低软件开发的技术难度并使软件开发的质量得到保证。

7.3.2  软件需求分析

软件开发方法是软件开发过程所遵循的方法和步骤,其目的在于有效地得到一些工作产品,即程序和文档,并且满足质量要求。软件开发方法包括分析方法、设计方法和程序设计方法。

1.需求分析与需求分析方法

1)需求分析。

软件需求是指用户对目标软件系统在功能、行为、性能、设计约束等方面的期望。需求分析的任务是发现需求、求精、建模和定义需求的过程。需求分析将创建所需的数据模型、功能模型和控制模型。

需求分析的定义。

·    用户解决问题或达到目标所需的条件或权能。

·    系统或系统部件要满足合同、标准、规范或其他正式规定文档所需具有的条件或权能。

·    一种反映A、或B所描述的条件或权能的文档说明。

由需求分析定义可知,需求分析的内容包括:提炼、分析和仔细审查已收集到的需求;确保所有利益相关者都明白其含义并找出其中的错误、遗漏或其他不足的地方;从用户最初的非形式化需求到满足用户对软件产品的要求的映射;对用户意图不断进行提示和判断。

需求分析阶段的工作。

需求分析阶段的工作,可以概括为四个方面:

·    需求获取。需求获取的目的是确定对目标系统的各方面需求。涉及到的主要任务是建立获取用户需求的方法框架,并支持和监控需求获取的过程。

·    需求分析。对获取的需求进行分析和综合,最终给出系统的解决方案和目标系统的逻辑模型。

·    编写需求规格说明书。需求规格说明书作为需求分析的阶段成果,可以为用户、分析人员和设计人员之间的交流提供方便,可以直接支持目标软件系统的确认又可以作为控制软件开发进程的依据。

·    需求评审。在需求分析的最后一步,对需求分析阶段的工作进行得审,验证需求文档的一致性、可行性、完整性和有效性。

2)需求分析方法。

常见的需求分析方法有:

·    结构化分析方法。主要包括:面向数据流的结构化分析方法(SA——Structured Analysis面向数据结构的Jackson方法(JSD——Jackson System Development Method)、面向数据结构的结构化数据系统开发方法(DSSD——Data structured system development method

·    面向对象的分析方法(OOA——Object-Oriented method)。

从需求分析建立的模型的特性来分,需求分析方法又分为表态分析方法和动态分析方法。

2.结构化分析方法

1)关于结构化分析方法。

结构化分析方法是结构化程序设计理论在软件需求分析阶段的运用。

对于面向数据流的结构化分析方法,按照DeMarco的定义,“结构化分析就是使用数据流图(DFD)、数据字典(DD)、结构化英语、判定表和判定树等工具,来建立一种新的、称为结构化规格说明的目标文档”。

结构化分析方法的实质是着眼于数据流自顶向下,逐层分解,建立系统的处理流程,以数据流图和数据字典为主要工具建立系统的逻辑模型。

结构化分析的步骤如下:

A.通过对用户的调查,以软件的需求为线索,获得当前系统的具体模型。

B.去掉具体模型中非本质因素,抽象出当前系统的逻辑模型。

C.根据计算机的特点分析当前系统与目标系统的差别,建立目标系统的逻辑模型。

D.完善目标系统并补充细节,写出目标系统的软件需求规格说明。

E.评审直到确认完全符合用户对软件的需求。

2)结构化分析的常用工具。

·    数据流图(Data Flow DiagramDFD

数据流图是描述数据处理过程的工具,是需求理解的逻辑模型的图形表示,它直接支持系统的功能建模。

数据流图从数据传递和加工的角度,来刻画数据流从输入到输出的移动变换过程。数据流图中的主要图形元素与说明如下。

加工(转换):输入数据经加工变换产生输出。

数据流:沿箭头方向传送数据的通道,一般在旁边标注数据流名。

存储文件(数据源):表示处理过程中存放各种数据的文件。

数据源或终点:表示系统和环境的接口,属系统之外的实体。

一般通过对实际系统的了解和分析后,使用数据流图为系统建立逻辑模型。建立数据流图的步骤如下。

1步:由外向里,先画系统的输入输出,然后画系统的内部。

2步:自顶向下,顺序完成顶层、中间层、底层数据流图。

3步:逐层分解。

为保证构造的数据流图表达完整、准确、规范,应遵循以下数据流图的构造规则和注意事项:

对加工处理建立唯一、层次性的编号,且每个加工处理通常要求既有输入又有输出。

数据存储之间不应该有数据流。

数据流图的一致性。

父图、子图关系与平衡规则。

·    数据字典(Data DictionaryDD

数据字典是结构化分析方法的核心。数据字典是对所有与系统相关的数据元素的一个有组织的列表,以及精确的、严格的定义,使得用户和系统分析员对于输入、输出、存储成分和中间计算结果有共同的理解。数据字典把不同的需求文档和分析模型紧密地结合在一起,与各模型的图形表示配合,能清楚地表达数据处理的要求。

概括地说,数据字典的作用是对DFD中出现的被命名的图形元素的确切解释。通常数据字典饮食的信息有名称、别名、何处作用/如何使用、内容描述、补充信息等。

·    判定树

使用判定树进行描述时,应先从问题定义的文字描述中分清哪些是判定的条件,哪些是判定的结论,根据模仿材料中的连接词找出判定条件之间的从属关系、并列关系、选择关系,根据它们构造判定树。

·    判定表

判定表与判定树相似,当数据流图中的加工要依赖于多个逻辑条件的联欢会,即完成该加工的一组动作是由于某一组条件联欢会的组合而引发的,使用判定表描述比较适宜。判定表由4部分组成:基本条件、条件项、基本动作、动作项。

3.软件需求规格说明书

软件需求规格说明书(software Requirement SpecificationSRS 是需求分析阶段的最后成果,是软件开发中的文档之一。

1)软件需求规格说明书的作用。

便于用户、开发人员进行理解和交流。

反映出用户问题的结构,可以作为软件开发工作的基础和依据。

作为确认测试的验收的依据。

2)软件需求规格说明书的内容。

概述。

数据描述。

·    数据流图。

·    数据字典。

·    系统接口说明。

·    内部接口。

功能描述。

·    功能。

·    处理说明。

·    设计的限制。

性能描述。

·    性能参数。

·    测试种类。

?   预期的软件响应l

?   应考虑的特殊问题l

参考文献目录。

附录。

其中,概述是从系统的角度描述软件的目标和任务。数据描述是对软件系统所必须解决的问题做出的详细说明。功能描述中描述了为解决用户问题所需要的每一项功能的过程细节。对每一项功能要给出处理说明和在设计时需要考虑的限制条件。在性能描述中说明系统应达到的性能和应该满足的限制条件、检测的方法和标准,预期的软件响应和可能需要考虑的特殊问题。参考文献目录中应包括与该软件有关全部参考文献,其中包括前期的其他文档、技术参考资料、产品目录手册以及标准等。附录部分包括一些补充资料。

3)软件需求规格说明书的特点。

软件需求规格说明书是确保软件质量的有力措施,是衡量软件需求规格说明书质量好坏的标准。

正确性。体现待开发系统的真实要求。

无歧义性。对每一个需求只有一种解释,其陈述具有唯一性。

完整性。包括全部有意义的需求,功能的、性能的、设计的、约束的,属性或外部接口等方面的需求。

可验证性。描述的每一个需求都是可以验证的,即存在有限代价的有效过程验证确认。

一致性。各个需求的描述矛盾。

可理解性。需求说明书必须简明易懂,尽量少包含计算机的要领和术语,以便用户和软件人员都能接受它。

可修改性。每一个需求的来源、流向是清晰的,当产生和改变文件编制时,可以方便地引证每一个需求。

7.3.3  软件设计

1.软件设计的基本概念

1)软件设计的基础。

软件设计是软件工程的重要阶段,是一个把软件需求转换为软件表示的过程。软件设计的基本目标是用比较抽象概括的方式确定目标系统如何完成预定的任务,即软件设计是确定系统的物理模型。软件设计的重要性和地位概括为以下几点:

软件开发阶段(设计、编码、测试)占据软件项目开发总成本绝大部分,是在软件开发中形成质量的关键五一节。

软件设计是开发阶段最重要的步骤,是将需求准确地转化为完整的软件产品或系统的唯一途径。

软件设计做出的决策,最终影响软件实现的成败。

设计是软件工程和软件维护的基础。

从技术观点来看,软件设计包括软件结构设计、数据设计、接口设计、过程设计。其中,结构设计是定义软件系统各主要部件之间的关系;数据设计是将分析时创建的模型转化为数据结构的定义;接口设计是描述软件内部、软件和协作系统之间以及软件与人之间如何通信;过程设计则是把系统结构部件转换成软件的过程性描述。

从工程管理角度来看,软件设计分两步完成:概要设计和详细设计。概要设计(又称结构设计)将软件需求转化为软件体系结构、确定系统级接口、全局数据结构或数据库模式;详细设计确立每个模块的实现算法和局部数据结构,用适当方法表示算法和数据结构的细节。

软件设计的一般过程是:软件设计是一个迭代的过程,先进行高层次的结构设计,后进行低层次的过程设计,穿插进行数据设计和接口设计。

2)软件设计的基本原理。

软件设计遵循软件工程的基本目标和原则,建立了适用于在软件设计中应该遵循的基本原理和与软件设计有关的概念。

抽象化。

抽象是一种思维工具,就是把事物本质的共同特性提取出来而不考虑其他细节。软件设计中考虑模块化解决方案时,可以定出多个抽象级别。抽象的层次从概要设计到详细设计逐步降低。在软件概要设计中的模块分层也是由抽象到具体逐步分析和构造出来的。

模块化。

模块化是指把一个待开发的软件分解成若干个小的简单的部分。如高级语言中的过程、函数、子程序等。每个模块可以完成一个特定的子功能,各个模块可以按一定的方法组装起来成为一个整体,从而实现整个系统的功能。模块化是指解决一个复杂问题时自顶向下逐层把软件系统划分成若干模块的过程。

为了解决复杂的问题,在软件设计中必须把整个问题进行分解来降低复杂性,这样就可以减少开发工作量并降低开发成本和提高软件生产率。但是划分模块并不是越多越好,因为这会增加模块之间接口的工作量,所以划分模块层次和数量应该避免过多或过少。

信息隐蔽。

信息隐蔽是指,在一个模块内包含的信息(过程或数据),对于不需要这些信息的其他模块来说是不能访问的。

模块独立性。

模块独立性是指,每个模块只完成系统要求的独立的子功能,并且与其他模块的联系最少且接口简单。它是评价设计好坏的重要度量标准。衡量软件的模块独立性有耦合性和内聚性两个定性的度量标准。

·    内聚性:内聚性是一个模块内部各个元素间彼此结合的紧密程度的度量。内聚是从功能角度来度量模块内的联系。内聚有如下的种类,它们之间的内聚性由弱到强排列为:偶然内聚、逻辑内聚、时间内聚、过程、通信内聚、顺序内聚、功能内聚。内聚性是信息隐蔽和局部化概念的自然扩展。一个模块的内聚性越强则该模块的模块独立性越强。作为软件结构设计的设计原则,要求一个模块的内部都具有很强的内聚性,它的各个组成部分彼此都密切相关。

·    耦合性:耦合性是模块间互相连接的紧密程度的度量。

耦合性取决于各个模块之间接口的复杂度、调用方式以及哪些信息通过接口。耦合可以分为下列几种,它们之间的耦合度由高到低排列如下:

?     内容耦合  若一个模块直接访问另一模块的内容,则这两个模块称为内容耦合。

?     公共耦合  若一组模块都有访问同一全局数据结构,则它之间的耦合称之为公共耦合。

?     外部耦合  一组模块都访问同一全局简单变量(而不是同一全局数据结构),且不通过参数表传递该全局变量的信息,则称为外部耦合。

?     控制耦合  若一模块明显地把开头量、名字等信息送入另一模块,控制另一模块的功能,则为控制耦合。

?     标记耦合  若两个以上的模块都需要其余某一数据结构子结构时,不使用其余全局变量的方式而是用记录传递的方式,即两模块间通过数据结构变换信息,这样的耦合称为标记耦合。

?     数据耦合  若一个模块访问另一个模块,被访问模块的输入和输出都数据项参数,即两模块间通过数据参数交换信息,则这两个模块为数据耦合。

?     非直接耦合  若两个模块没有直接关系,它们之间的联系完全是通过主模块的控制和调用来实现的,则称这两个模块为非直接耦合。非直接耦合独立性最强。

?     耦合性越强,独立性越弱,用户希望模块之间的耦合表现为非直接耦合方式。但是,由于问题所固有的复杂性和结构化设计的原则,非直接耦合往往是不存在的。

耦合性与内聚性是模块独立性的两个定性标准,耦合与内聚是相互关联的。在程序结构中,各模块的内聚性越强,则耦合性越弱。一般较优秀的软件设计,应尽量做到高内聚、低耦合,既需减弱模块之间的耦合性和提高模块内的内聚性,又要提高模块的独立性。

3)结构设计方法。

结构化需求分析方法相对应的是结构化设计方法。结构化设计就是采用最佳的可能方法设计系统的各个组成部分以及各成分之间的内部联系的技术。也就是说,结构设计是这样一个过程,它决定用哪些方法把哪些部分联系起来,才能解决好某个具体有清楚定义的问题。结构化设计方法的基本思想是将软件设计成由相对独立、单一功能的模块组成的结构。

2.概要设计

1)概要设计的任务。

软件概要设计的基本任务包括以下几种:

·    设计软件系统结构

在需求分析阶段,已经把系统分解成层次结构,而在概要设计阶段,需要过去时一步分解,划分为模块以及模块的层次结构。划分的具体过程如下:

采用某种设计方法,将一个复杂的系统按功能划分成模块。

确定每个模块的功能。

确定模块之间的调用关系。

确定模块之间的接口,即模块之间传递的信息。

评价模块结构的质量。

·    数据结构及数据库设计

数据设计是实现需求定义和规格说明过程中提出的数据对象的逻辑表示。数据设计的具体任务是:确定输入、输出文件的详细数据结构;结合算法设计,确定算法所必需的逻辑数据结构及其操作;确定对逻辑数据结构所必须的那些操作的程序模块,限制和确定各个数据设计决策的影响范围;需要与操作系统或调试程序接口所必需的控制表进行数据交换时,确定其详细的数据结构和使用规则;数据的保护性设计:防卫性、一致性、冗余性设计。数据设计中应注意掌握以下设计原则:

用于功能和行为的系统分析原则也应用于数据。

应该标识所有的数据结构以及其上的操作。

应当建立数据字典,并用于数据设计和程序设计。

底层的设计决策应该推迟到设计过程的后期。

只有那些需要直接使用数据结构、内部数据的模块才能看该数据的表示。

应该开发一个由有用的数据结构和应用于其上的操作组成的库。

软件设计和程序设计语言应该支持抽象数据类型的规格说明和实现。

·    编定概要设计文档

在概要设计阶段,需要编写的文档有概要设计说明书、数据库设计说明书、集成测试计划等。

·    概要设计文档评审

在概要设计中,对设计部分是否完整地实现了需求中规定的功能、性能等要求,设计方案的可行性,关键的处理及内外部接口定义正确性、有效性、各部分之间的一致性等都要进行评审,以免在以后的设计中出现大的问题而返工。

2)软件设计的工具——结构图。

常用的软件结构设计工具是结构图(Structure  ChartSC),也称程序结构图。使用结构图描述软件系统的层次和分块结构关系,它反映了整个系统的功能实现以及模块与模块之间的联系与通信,是未来程序中的控制层次体系。

结构图是描述软件结构的图形工具。模块用一个矩形表示,矩形内注明模块的功能和名字;箭头表示模块间的调用关系。在结构图中还可以用带注释的箭头表示模块调用过程中来回传递的信息。如果希望进一步标明传递的信息是数据还是控制信息则可用带实心圆的箭头表示传递的是控制信息,用带空心圆的箭头表示传递的是数据。

根据结构化设计思想,结构图构成的基本形式如下:

·    基本形式。

·    顺序形式。

·    重复形式。

·    选择形式。

程序结构图的有关术语如下。

深度:表示控制的层数。

上级模块、从属模块:上、下两层模块AB,且有A调用B,则A是上级模块,B是从属模块。

宽度:整体控跨度(最大模块数的层)的表示。

扇入:调用一个给定模块的模块个数。

扇出:一个模块直接调用的其他模块数。

原子模块:树中位于叶子结点的模块。

传入模块:从下属模块取得数据,经处理再将其传送给上级模块。

传出模块:从上级模块取得数据,经处理再将其传送给下必模块。

变换模块:从上级模块取得数据,进行特定的处理,转换成其他形式,再传送给上级模块

协调模块:对所有下属模块进行协调和管理的模块。

3.详细设计

详细设计的任务是为软件结构图中的每一个模块确定实现算法和局部数据结构,用某种选定的表达工具表示算法和数据结构的细节。

详细设计阶段主要确定每个模块的具体执行任务,主要任务如下:

1)为每个模块进行详细的算法设计。

2)对模块内的数据结构进行设计。

3)对数据库进行物理设计,即确定数据库的物理结构。

4)其他设计,如代码设计、输入输出格式设计和用户界面设计。

5)编写详细设计说明书。

6)评审。

常见的过程工具设计工具有3种。

1)图形工具:程序流程图、N-SPADHIPO

2)表格工具:判定表。

3)语言工具:PDL

下面对几种常用的工具进行说明。

·    程序流程图

流程图是一种传统的、应用广泛的软件过程设计表示工具,也称为程序框图。程序流程图表达直观、清晰,易于学习和掌握,在任何程序设计语言中都可使用。

构成程序流程图的最基本图符及含义如图7-29所示。

7-29  程序流程图构成的五种控制结构

按照结构化程序设计的要求,程序流程图构成的任何程序描述为如图7-30所示的五种控制结构。

7-30  N-S图图符与构成的五种控制结构

·    N-S

为了避免流程图在描述程序逻辑时的随意性和灵活性,NossiSheneiderman提出了用方框图来代替传统的程序流程图,这种图称为N-S图。

N-S图的基本图符及表示五种的基本控制结构如图7-31所示。

·    PAD

PADprobleman alysis diagram)是一种描述软件详细设计的图形工具,其基本的图符及表示的五种基本控制结构如图7-32所示。

7-31  N-S图图符与构成的五种控制结构

7-32  PAD图图符与构成的五种控制结构

7.3.4  软件测试

软件测试目前仍是发现软件中错误和缺陷的重要手段,软件测试的结果只能证明软件有错误和缺陷,不能证明软件没有错误和缺陷。经过测试的软件可以正常使用,否则很难保证正常使用,甚至会导致巨大的损失。

1.软件测试的目的

测试是软件的执行过程,其目的是尽可能多地发现软件产品中的错误和缺陷。一次成功的测试是发现至今为止尚未发现的错误的测试。

对软件的测试,除了要有测试数据外,还应同时给出该组测试数据应该得到的输出结果,称之为预期结果。测试用例是由测试数据和预期结果组成的。一个好的测试用例在于能发现至今尚未发现的错误。

2.软件测试的原则

软件测试的原则如下:

·    确定预期输出结果是测试用例必不可少的一部分。

·    程序员应避免测试自己的程序,程序设计机构不应测试自己的程序。

·    对非法和非预期的输入数据也要像合法的和预期的输入数据一样编写测试用例。

·    程序模块经测试后,残存的错误数目与已发现的错误数目成正比。

·    严格执行测试计划,排除测试的随意性。

·    应当对每一个测试结果作全面检查。

·    妥善保管测试计划、测试用例,出错统计和最终分析报告,为软件维护提供方便。

3.软件测试技术与方法

对软件的测试,可以从不同的角度加以分类。若按照是否执行被测试软件的角度,可分为静态测试和动态测试。若按照功能划分可分为白盒测试和黑盒测试。

1)白盒测试。

白盒测试是结构测试、逻辑驱动测试或基于程序的测试。测试者熟悉程序的内部结构,依据程序模块的内部结构来设计测试用例,检测程序代码的正确性。

白盒测试的程序模块检测类别如下:

程序模块独立执行路径检测。

逻辑判定TRUE OR FALSE各种情况检测。

循环检测(循环边界和循环界内执行情况)。

程序内部数据结构的正确性。

2)黑盒测试。

黑盒测试是功能测试、数据驱动测试或基于规格说明的测试。在不考虑程序内部结构和内部特性的情况下,测试者依据该程序功能上的输入输出关系,或是程序的外部特性来设计和选择测试用例,推断程序编码的正确性。

黑盒测试检测的基本内容如下:

功能错误或遗漏。

输入和输出接口的正确性。

数据结构或外部信息访问错误。

性能要求实现情况。

初始化或终止性错误。

3)测试步骤。

软件测试可运用多种不同的测试策略来实现,最常用的方式是自底向上分阶段进行,对不同开发阶段的产品采用不同的测试方法进行检测,从独立程序模块开始,然后进行程序测试、设计测试到确认测试,最终进行系统测试,共分为4个阶段过程:

·    单元测试

单独检测各模块,验证程序模块和详细设计是否一致,消除程序模块内部逻辑上和功能上的错误及缺陷。一般采用白盒测试法。

单元测试检查模块界面的输入输出数据,判断模块是否符合设计要求、模块所涉及的局部数据结构的状况和改变、模块内部重要执行路径(包括出错处理路径)的正确性。

·    集成测试

将已测试的模块组装进行检测,对照软件设计检测和排除子系统或系统结构上的错误。一般采用黑盒测试法。

集成测试的重点是检测模块接口之间的连接,发现访问公共数据结构可能引起的模块间的干扰,以及全局数据结构的不一致,测试软件系统或子系统输入输出处理、故障处理和容错等方面的能力。

·    确认测试

按规定需求,逐项进行有效性测试。检验软件的功能和性能及其他特性是否与用户的要求相一致,一般采用黑盒测试法。确认测试的基本事项如下。

功能确认:以用户需求规格说明为依据,检测系统需求规定功能的实现情况。

配置确认:检查系统资源和设备的协调情况,确保开发软件的所有文档资料编写齐全,能够支持软件运行后的维护工作。文档资料包括:设计文档、源程序、测试文档和用户文档等。

·    系统测试

检测软件系统运行时与其他相关要素(硬件、数据库及操作人员等)的协调工作情况是否满足要求,包括性能测试、恢复测试和安全测试等内容。

性能测试:程序的响应时间、处理速度、精确范围、存储要求以及负荷等性能的满足情况。

恢复测试:系统在软硬件故障后保存数据和控制并进行恢复的能力。

安全测试:检查系统对于用户使用权限进行管理、控制和监督以防非法进入、篡改、窃取和破坏等行为的能力。

上述4个阶段相互独立且顺序相接,单元测试在编码阶段即可进行,单元测试结束后进人独立测试阶段,从集成测试开始,依次进行。

4)设计测试用例的基本原则。

设计测试用例的基本原则如下:

一个好的测试用例在于能够发现至今没有发现的错误。

测试用例应由测试输入数据和与之对应的预期输出结果这两部分组成。

在测试用例设计时,应当包含合理的输入条件和不合理的输入条件。

5)白盒测试的测试用例设计。

白盒测试测试用例一般采用逻辑覆盖法和基本路径法进行设计。

·    逻辑覆盖法

逻辑覆盖是以程序内部的逻辑结构为基础的测试用例设计技术,这一方法要求测试人员对程序的逻辑结构有清楚的了解。逻辑覆盖可分为:语句覆盖、判定覆盖、条件覆盖、判定/条件覆盖、条件组合覆盖与路径覆盖。

语句覆盖就是设计若干个测试用例,运行所测程序,使得每一可执行语句至少执行一次。语句覆盖是一种很弱的覆盖标准。

判定覆盖就是设计若干个测试用例,运行所测程序,使得程序中每个判断的取真分支和取假分支至少经历一次。

条件覆盖就是设计若干个测试用例,运行所测程序,使得程序中每个判断的每个条件的可能取值至少执行一次。

判定/条件覆盖就是设计足够的测试用例,使得判断中每个条件的所有可能取值至少执行一次,同时每个判断的所有可能判断结果也至少执行一次。

条件组合覆盖就是设计足够的测试用例,运行所测程序,使得每个判断的所有可能的条件取值组合至少执行一次。

路径测试就是设计足够的测试用例,覆盖程序中所有可能的路径。

通常在设计测试用例时应该根据代码模块的复杂度,选择覆盖方法。一般的代码的复杂度与测试用例设计的复杂度成正比。因此,设计人员必须做到模块或方法功能的单一性、高内聚性,使得方法或函数代码尽可能的简单。这样将可大大提高测试用例设计的容易度,提高测试用例的覆盖程度。

·    基本路径法

基本路径测试法是在程序控制流图的基础上,通过分析控制构造的环路复杂性,导出基本可执行路径集合,从而设计测试用例的方法。设计出的测试用例要保证在测试中程序的每个可执行语句至少执行一次。基本路径测试法包括以下5个方面。

程序的控制流图:描述程序控制流的一种图示方法。

程序环境复杂性:McCabe复杂性度量,从程序的环路复杂性可导出程序基本路径集合中的独立路径条数,这是确定程序中每个可执行语句至少执行一次所必须的测试用例数目的上界。

导出测试用例。

准备测试用例:确保基本路径集中的每一条路径的执行。

图形矩阵:是在基本路径测试中起辅助作用的软件工具,利用它可以实现自动地确定一个基本路径集。

另外,对于测试用例的选择除了满足所选择的覆盖程度(或覆盖标准)外还需要尽可能地采用边界值分析法、错误推测法等常用的设计方法。采用边界值分析法设计合理的输入条件与不合理的输入条件;条件边界测试用例应该包括输入参数的边界与条件边界(ifwhileforswitchSQL Where子句等)。错误推测法,列举出程序中所有可能的错误和容易发生错误的特殊情况,根据它们选择测试用例。在编码、单元测试阶段可以发现很多常见的错误和疑似错误,对于这些错误应该做重点测试,并设计相应的测试用例。

6)黑盒测试的测试用例设计。

此用例设计是把所有可能的输入数据,即程序的输入域划分成若干部分(子集),然后从每一个子集中选取少数具有代表性的数据作为测试用例。常用的黑盒测试用例,设计方法有:

·    划分等价类

等价类是指某个输入域的子集合。在该子集合中,各个输入数据对于揭露程序中的错误都是等效的。并合理地假定:测试某等价类的代表值就等于对这一类其他值的测试。因此,可以把全部输入数据合理划分为若干等价类,在每一个等价类中取一个数据作为测试的输入条件,就可以用少量代表性的测试数据。

·    边界值分析法

边界值分析方法是对等价类划分方法的补充。

长期的测试工作经验告诉我们,大量的错误是发生在输入或输出范围的边界上,而不是发生在输入输出范围的内部。因此针对各种边界情况设计测试用例,可以查出更多的错误。

使用边界值分析方法设计测试用例,首先应确定边界情况。通常输入和输出等价类的边界,就是应着重测试的边界情况。应当选取正好等于、刚刚大于或刚刚小于边界的值作为测试数据,而不是选取等价类中的典型值或任意值作为测试数据来代替大量内容相似的测试数据,借以实现测试的经济性。

·    错误推测法

错误推测法是基于经验和直觉推测程序中所有可能存在的各种错误,从而有针对性地设计测试用例的方法。

错误推测方法的基本思想:列举出程序中所有可能有的错误和容易发生错误的特殊情况,根据他们选择测试用例。例如,在单元测试时曾列出的许多在模块中常见的错误。以前产品测试中曾经发现的错误等,这些就是经验的总结。还有,输入数据和输出数据为零的情况。输入表格为空格或输入表格只有一行。这些都是容易发生错误的情况。可选择这些情况下的例子作为测试用例。

·    因果图方法

前面介绍的等价类划分方法和边界值分析方法,都是着重考虑输入条件,但未考虑输入条件之间的联系,相互组合等。考虑输入条件之间的相互组合,可能会产生一些新的情况。但要检查输入条件的组合不是一件容易的事情,即使把所有输入条件划分成等价类,它们之间的组合情况也相当多。因此必须考虑采用一种适合于描述对于多种条件的组合,相应产生多个动作的形式来考虑设计测试用例。这就需要利用因果图(逻辑模型)。

因果图方法最终生成的就是判定表。它适合于检查程序输入条件的各种组合情况。

7.3.5  软件调试与维护

1.程序调试的基本概念

在对程序进行了成功测试后,进入程序调试阶段,程序调试的主要任务是诊断和改正程序中的错误。软件测试时尽可能多地发现软件中的错误,然后借助于一定的调试工具找出软件中错误的具体位置,软件测试贯穿整个软件生命期,而调试主要在开发阶段。

程序调试由两部分组成:确定程序中可疑错误的确切性质和位置;对程序(设计、编码)进行修改,排除错误。

1)程序调试的基本步骤。

1步:错误定位。

2步:修改设计和代码,以排除错误。

3步:进行回归测试,防止引进新的错误。

2)程序调试的原则。

程序的调试原则从调试活动由对程序中错误的定位、定性和排错两方面来考虑。

在对错误的定位、定性时的注意事项如下:

·    分析思考与错误征兆有关的信息。

·    避开死胡同。

·    把调试工具当作辅助手段来使用。    ·

·    避免用试探法,最多只能把它当作最后手段。

修改错误的原则如下:

·    在出现错误的地方,很可能还有别的错误。

·    修改错误的一个常见失误是只修改了这个错误的征兆或这个错误的现象,而没有修改错误本身。

·    注意修正一个错误的同时有可能会引入新的错误。

·    修改错误的过程将迫使人们暂时回到程序设计阶段。

·    修改源代码程序,不要改变目标代码。

2.软件调试方法

从是否跟踪和执行程序的角度来说,程序调试可分为静态调试和动态调试。静态调试对测试程序不在机器上运行,而是采用人工检测和计算机辅助静态分析的手段对程序的数据流和控制流进行分析。动态测试对程序通过运行发现错误,一般意义上的测试大多数指动态测试。对软件产品进行动态测试也有白盒测试和黑盒测试,分别对软件的结构和功能进行检测和调试。主要的调试方法如下:

1)强行排错法。

这是一种传统的调试方法,其过程可概括为:设置断点、程序暂停、观察程序状态、继续运行程序。这种方法使用得较多,但效率较低。涉及的调试技术主要是设置断点和监视表达式。

2)回溯法。

对于小规模的程序排错可以采用这种方法。对程序中发现的错误,先分析错误征兆,确定最先发现“症状”的位置,然后从这个地方开始,沿程序的控制流程,逆向跟踪源程序代码,直到找到错误根源或确定错误产生的范围。

3)原因排除法。

原因排除法即通过演绎和归纳,以及二分法来实现的。演绎法是设想可能的原因,用排除法寻求错误原因。归纳法通过归纳错误信息的发生因果特性,从出错信息推测问题。二分查找法是通过区分程序段查找。

3.软件维护

软件维护就是在软件已经交付使用之后,为了改正错误或满足新的需要而修改软件的过程。软件维护是整个软件生存周期中的最后一个阶段,也是持续时间最长的阶段。

软件维护通常包括4方面内容。

1)校正性维护。

测试过程中未发现的错误,而在投入运行后出现,必须加以纠正。

2)适应性维护。

软件系统为适应不断变化的运行环境(硬件、软件)而进行的修改。

3)完善性维护。

软件系统运行成功后,根据用户要求新增一些处理功能,或修改原有功能。

4)预防性维护。

为提高软件的可维护性和可靠性而进行的修改和扩充。

在软件维护中,影响维护工作量的程序特性有系统大小、程序设计语言、系统年龄、数据库技术的应用、先进的软件开发技术等。

软件维护中因修改软件而造成的错误或其他不希望出现的情况称为维护的副作用,维护的副作用有编码副作用、数据副作用和文档副作用。

软件可维护性是指纠正软件系统出现的错误和缺陷,以及为满足新的要求进行修改、扩充或压缩的容易程度。软件工程学的主要目的就是提高软件的可维护性,降低维护的代价。软件的可理解性、可测试性和可修改性是决定软件可维护性的基本因素。