跳转到内容

软件工程/质量简介

来自维基教科书,开放世界中的开放书籍

在软件工程的背景下,软件质量衡量软件设计得有多好(设计质量),以及软件与该设计的符合程度(符合质量),[1]虽然存在几种不同的定义。它通常被描述为软件的“适用性”。

符合质量关注的是实现(参见软件质量保证),而设计质量衡量的是设计和需求在创建有价值的产品方面的有效性。[2]

软件质量的一个挑战是“每个人都觉得他们理解它”。[3]

软件质量可以定义为对明确说明的功能和性能需求、明确记录的开发标准以及所有专业开发的软件应具备的隐含特性的符合程度。

该定义中的三个关键点

  1. 软件需求是衡量质量的基础。

    不符合需求就是质量不合格。

  2. 规定的标准定义了一组开发标准,指导软件工程管理人员。

    如果没有遵循这些标准,通常会导致质量不合格。

  3. 一组隐含的需求通常不会被提及,例如易用性、可维护性等。

    如果软件符合其明确的需求,但未能满足隐含的需求,则怀疑软件质量。

史蒂夫·迈克康奈尔在代码大全中的一个定义将软件分为两部分:内部外部质量特征。外部质量特征是产品面向其用户的那些部分,而内部质量特征是那些不面向用户的部分。[4]

汤姆·德马科博士的另一个定义是“产品的质量是它对世界产生的积极变化的函数”。[5]这可以被解释为,用户满意度比任何事情都更重要,决定了软件的质量。[1]

另一个定义,由杰拉尔德·温伯格在软件质量管理:系统思考中提出,是“质量是对某个人来说的价值”。这个定义强调质量本质上是主观的——不同的人对相同软件的质量体验会非常不同。这个定义的一个优势是它引发了软件团队思考的问题,例如“我们希望谁来重视我们的软件?”以及“对他们来说什么是有价值的?”

软件产品质量

[编辑 | 编辑源代码]
  • 正确性
  • 产品质量
    • 符合需求或程序规范;与可靠性有关
  • 可扩展性
  • 完整性
  • 没有错误
  • 容错性
    • 可扩展性
    • 可维护性
  • 文档

IT 软件质量联盟 (CISQ) 于 2009 年成立,旨在规范软件产品质量的度量。该联盟的目标是将来自全球 2000 家 IT 组织、系统集成商、外包商和软件供应商的行业高管汇聚在一起,共同解决规范 IT 软件质量度量的挑战,并促进支持其部署的市场驱动型生态系统。

源代码质量

[编辑 | 编辑源代码]

计算机无法理解“写得好的”源代码。但是,从人的角度来看,源代码可以以影响理解其行为所需工作量的方式编写。许多源代码编程风格指南,通常强调可读性,并且通常是特定于语言的约定,旨在降低源代码维护成本。影响代码质量的一些问题包括

  • 可读性
  • 易于维护、测试、调试、修复、修改和移植
  • 低复杂度
  • 低资源消耗:内存、CPU
  • 编译或 Lint 警告的数量
  • 鲁棒的输入验证和错误处理,由软件故障注入建立

提高质量的方法

  • 重构
  • 代码检查或软件评审
  • 代码文档

软件可靠性

[编辑 | 编辑源代码]

软件可靠性是软件质量的一个重要方面。它被定义为“在指定环境中指定时间内计算机程序无故障运行的概率”。[6]

可靠性的一个显著特征是它是客观的、可衡量的,并且可以估计,而大多数软件质量都是主观的标准。[7]这种区别在软件质量保证学科中尤为重要。这些衡量的标准通常被称为软件度量。

随着如今软件嵌入到许多设备中,软件故障带来的不仅仅是不便。软件错误甚至导致了人员伤亡。原因从设计糟糕的用户界面到直接的编程错误。莱维森博士在论文[1] (PDF) 中讨论了一个导致多人死亡的编程错误。这导致了一些类型软件开发的需求。在美国,食品药品监督管理局 (FDA) 和联邦航空管理局 (FAA) 都对软件开发有要求。

可靠性的目标

[编辑 | 编辑源代码]

客观地确定软件可靠性的方法的需求源于将当代工程领域的技巧应用于软件开发的愿望。这种愿望源于普通人和专家共同观察到的一个普遍现象,即计算机软件并没有按照预期的方式工作。换句话说,软件被认为表现出不希望的行为,包括彻底的失败,这对处理的数据、软件运行的机器,以及扩展到这些机器可能负面影响的人员和材料都会产生后果。软件在经济和生产过程中越关键,或者在维持生命的系统中越关键,评估软件可靠性的必要性就越重要。

无论单个软件应用程序的 критичность 如何,人们也越来越频繁地观察到,软件已经通过我们使用的技术渗透到现代生活的各个方面。预计这种渗透将继续,以及我们社会维持的系统对软件的依赖随之而来。随着软件对我们依赖的系统运行越来越重要,人们认为,软件应该提供相应的可靠性水平。换句话说,软件应该按照预期的方式运行,甚至更好,按照它应该运行的方式。

可靠性挑战

[编辑 | 编辑源代码]

前一句的循环逻辑并非偶然——它旨在说明衡量软件可靠性问题中的一个基本问题,即难以预先确定软件的预期运行方式。这个问题似乎源于对软件考虑中的一个常见概念错误,即软件在某种程度上承担了人类原本应该承担的角色。这是一个双重问题。首先,大多数现代软件执行人类永远无法执行的工作,特别是在与人类相比,人们经常期望软件达到很高的可靠性水平。其次,软件从根本上无法实现人类的大部分精神能力,这些能力将人类与单纯的机制区分开来:例如适应性、通用知识、概念和功能上下文意识以及常识。

然而,大多数软件程序都可以被认为具有特定的甚至唯一的目的。如果允许该目的可以很好地甚至完全定义的可能性,那么它应该提供一种方法来至少客观地考虑软件是否实际上是可靠的,方法是将预期结果与在给定环境中运行软件的实际结果进行比较,并使用给定的数据。不幸的是,目前尚不清楚是否可以通过穷举的方式确定给定程序的整个可能的环境和输入数据的预期结果或实际结果,如果没有这些,可能无法以任何确定性确定程序的可靠性。

然而,人们正在努力尝试控制软件环境和输入变量空间的广阔性,无论是针对实际程序还是针对程序的理论描述。此类旨在提高软件可靠性的尝试可以在真实软件的程序开发的不同阶段应用。这些阶段主要包括:需求、设计、编程、测试和运行时评估。理论软件可靠性的研究主要关注正确性的概念,这是计算机科学的一个数学领域,它源于语言和自动机理论。

程序开发中的可靠性

[编辑 | 编辑源代码]

如果程序的开发人员实际上并不知道程序的预期行为,或者他们无法在开发过程中与开发并行确定其预期行为,并且细节足够详细,则无法期望程序按预期工作。什么程度的细节被认为足够是激烈争论的。完美细节的想法很有吸引力,但可能不切实际,甚至不可能。这是因为预期行为往往会随着行为可能范围的确定而发生变化,而行为可能范围的确定是通过实际尝试或更准确地说是尝试失败来实现的。

如果程序的预期行为根本无法指定,那么它是否可以在预先成功指定就是一个有争议的问题,这就是试图将创建新软件项目需求的过程形式化的重点。与形式化工作同时进行的是试图帮助非专家(尤其是非程序员)了解软件项目,而他们对计算机软件的实际能力了解不足。由于如上所述,即使程序员也无法始终提前知道软件在尝试之前实际上可能是什么,因此传达这种知识变得更加困难。

虽然需求旨在指定程序应该做什么,但设计旨在至少在较高层面上指定程序应该如何做。设计的有用性也受到一些人的质疑,但那些寻求将确保可靠性的过程形式化的人通常会提供良好的软件设计过程作为实现它的最重要手段。软件设计通常涉及使用更抽象和更通用的方法来指定软件的各个部分及其功能。因此,它可以被视为将大型程序分解为许多较小的程序的一种方式,以便这些较小的程序组合在一起可以完成整个程序的工作。

高级设计的目的是:它将被认为是架构问题或整个程序概念和结构问题与实际编码问题区分开来,实际编码问题解决实际数据处理问题。它通过缩小较小软件组件的范围,从而对开发过程施加额外的约束,并因此(希望)消除可能增加编程错误可能性的变量。它提供了一个程序模板,包括接口规范,可以由不同的开发团队在不同的部分共享,以便他们可以预先知道他们的每个贡献将如何与其他团队的贡献交互。最后,也许最具争议的是,它独立于实现语言或语言来指定程序,从而消除语言特定的偏差和限制,否则这些偏差和限制会潜入设计中,也许是程序员设计师无意中造成的。

计算机编程语言发展史通常可以在掌握计算机程序复杂性的尝试中得到最好的理解,否则计算机程序的复杂性会随着程序的大小(可能呈指数级)而变得越来越难以理解。(看待编程语言演变的另一种方式仅仅是让计算机做更多的事情,但这可能只是另一种说法)。对程序整体结构和功能的理解不足是无法检测程序错误的必然途径,因此,反过来,使用更好的语言应该通过使更好的理解成为可能来减少错误数量。

语言的改进往往逐渐提供软件设计试图一步到位的东西:在越来越高的抽象级别上考虑软件。语句、子例程、文件、类、模板、库、组件等发明允许使用层、层次结构和模块等抽象来指定程序各个部分的排列,这些抽象在不同的粒度上提供结构,以便从任何角度来看,程序代码都可以想象成井然有序且易于理解。

此外,语言的改进使得对数据元素的形状和使用方法有了更精确的控制,最终形成了抽象数据类型。可以对这些数据类型进行非常细致的指定,包括如何以及何时访问它们,甚至访问数据之前和之后的 数据状态。。

软件构建和部署

[编辑 | 编辑源代码]

许多编程语言(如 C 和 Java)要求将程序的“源代码”翻译成计算机可以执行的形式。这种翻译是由一个称为编译器的程序完成的。为了创建软件应用程序可用的运行时配置,可能涉及其他操作,例如将文件关联、绑定、链接或打包在一起。编译和组装过程的总和通常称为“构建”软件。

软件构建对软件质量至关重要,因为如果任何生成的 文件不正确,软件构建很可能会失败。而且,如果意外地使用了不正确的程序版本,那么测试会导致错误的结果。

软件构建通常在与运行时区域(如应用程序服务器)无关的工作区域中完成。为此,需要一个部署步骤将软件构建产品物理传输到运行时区域。部署过程也可能涉及技术参数,如果设置不正确,也会阻止软件测试开始。例如,Java 应用程序服务器可能具有首选父级或最后父级类加载选项。使用错误的参数会导致应用程序无法在应用程序服务器上执行。

支持软件质量的技术活动,包括构建、部署、变更控制和报告,统称为软件配置管理。许多软件工具已经出现,以帮助应对配置管理的挑战,包括文件控制工具和构建控制工具。

测试

[edit | edit source]

软件测试,如果操作正确,可以通过测试产品是否符合其要求来提高整体软件符合性质量[8] 测试包括但不限于

  1. 单元测试
  2. 功能测试
  3. 回归测试
  4. 性能测试
  5. 故障转移测试
  6. 可用性测试

许多敏捷方法在开发周期的早期使用测试来确保其产品的质量。例如,测试驱动开发实践(在要测试的代码之前编写测试)在极限编程中使用,以确保质量。

运行时

[edit | edit source]

运行时可靠性确定类似于测试,但超越了对行为的简单确认,而是对性能、与其他代码或特定硬件配置的互操作性等质量的评估。

软件质量因素

[edit | edit source]

软件质量因素是软件程序的非功能性需求,客户合同中没有提及,但仍然是提高软件程序质量的理想需求。请注意,这些因素都不是二元的;也就是说,它们不是“要么有要么没有”的特征。相反,它们是人们希望在软件中最大限度地提高以优化其质量的特征。因此,不要问一个软件产品是否“具有”因素x,而是问它在多大程度上(或没有)具有因素x

这里列出了一些软件质量因素

可理解性
目的明确。这超出了简单的目的陈述;所有设计和用户文档都必须写得清楚,以便于理解。这显然是主观的,因为必须考虑用户环境:例如,如果软件产品要由软件工程师使用,则不需要对非专业人士可理解。
完整性
所有组成部分的存在,每个部分都得到充分开发。这意味着,如果代码调用外部库中的子例程,软件包必须提供对该库的引用,并且必须传递所有必需的参数。所有必需的输入数据也必须可用。
简洁
尽量减少过多的或冗余的信息或处理。这在内存容量有限的情况下很重要,并且通常被认为是将代码行数保持在最低限度的良好做法。可以通过将重复的功能替换为一个实现该功能的子例程或函数来改进它。它也适用于文档。
可移植性
能够在多个计算机配置上良好且轻松地运行。可移植性既可以指不同硬件之间的可移植性——例如在 PC 和智能手机上运行——也可以指不同操作系统之间的可移植性——例如在 Mac OS X 和 GNU/Linux 上运行。
一致性
在符号、符号、外观和术语方面保持一致性。
可维护性
倾向于促进更新以满足新的需求。因此,可维护的软件产品应该有良好的文档记录,不应复杂,并且应该有备用容量用于内存、存储和处理器利用率以及其他资源。
可测试性
倾向于支持验收标准和性能评估。如果要使产品易于测试,则必须在设计阶段内置这种特性;复杂的设计会导致可测试性差。
可用性
使用方便实用。这受到诸如人机界面等因素的影响。对可用性影响最大的软件组件是用户界面 (UI),为了获得最佳的可用性,用户界面通常是图形化的(即 GUI)。
可靠性
预期能够令人满意地执行其预期功能的能力。这意味着有一个时间因素,即可靠的产品预期能够在一段时间内正常运行。它还包含环境因素,即产品要求在任何环境中都能正常运行(有时称为健壮性)。
效率
在不浪费资源的情况下实现目的,例如内存、空间和处理器利用率、网络带宽、时间等。
安全性
能够保护数据免受未经授权的访问,并能够抵抗恶意或意外干扰其操作。除了存在适当的安全机制(如身份验证、访问控制和加密)外,安全性还意味着在面对恶意、智能和自适应攻击者时具有弹性。

软件质量因素的度量

[edit | edit source]

该领域对度量有不同的观点。许多度量受到一些专业人士的重视——或者在某些情况下,受到其他人的谴责为有害。一些人认为,软件质量的定量度量是必不可少的。另一些人认为,定量度量有用的情况非常罕见,因此更喜欢定性度量。该领域的几位软件测试领导者撰写了关于难以衡量我们真正想很好地衡量的东西的文章。[9][10]

一个流行指标的例子是软件中遇到的故障数量。一些人认为,包含少量故障的软件比包含大量故障的软件质量更高。以下问题可以帮助确定此指标在特定环境中的有用性

  1. 什么是“大量故障”?这是否因软件的目的而异(例如,博客软件与导航软件)?这是否考虑了软件的大小和复杂性?
  2. 这是否考虑了错误的重要性(以及这些错误影响的人对利益相关者的重要性)?是否试图根据错误的严重程度或受其影响的用户发生率来加权此指标?如果是,如何加权?如果不是,如何知道发现的 100 个错误比 1000 个错误更好?
  3. 如果发现的错误数量正在减少,我该如何知道这意味着什么?例如,这是否意味着该产品现在比以前质量更高?或者,这比以前更小/更不雄心勃勃的变化?或者,投入到该项目中的测试人员工时少于以前?或者,这个项目是由比以前技能更差的测试人员测试的?或者,团队发现报告的错误更少符合他们的利益?

最后一个问题指出了一个特别难以管理的问题。所有软件质量指标在某种程度上都是对人类行为的度量,因为人类创建软件。[9] 如果一个团队发现他们将从报告的错误数量下降中受益,那么该团队极有可能开始报告更少的缺陷。这可能意味着电子邮件开始绕过错误跟踪系统,或者四五个错误被合并到一个错误报告中,或者测试人员学会不报告轻微的烦恼。困难在于衡量我们想要衡量的指标,而不会为软件程序员和测试人员创造有意识或无意识地“玩弄”这些指标的动机。

由于其定义模糊,无法衡量软件质量因素。有必要找到度量或指标,可以用来量化它们作为非功能性需求。例如,可靠性是一个软件质量因素,但不能独立评估。但是,确实有一些与可靠性相关的属性可以测量。这些属性包括平均故障间隔时间、故障发生率和系统的可用性。类似地,可移植性的一个属性是程序中目标依赖语句的数量。

下面给出了一种可以用来评估软件质量因素的方案。对于每种特性,都有一组与该特性相关的问题。可以根据对这些问题的答案开发某种评分公式,从中可以获得对该特性的测量结果。

可理解性

[edit | edit source]

变量名是否描述了所表示的物理或功能属性? 独特的可识别功能是否包含足够的注释,以便其目的明确? 是否对偏离前向逻辑流进行了充分的注释? 数组的所有元素是否在功能上相关?...

完整性

[编辑 | 编辑源代码]

所有必要的组件是否可用? 任何进程是否因缺乏资源或编程而失败? 代码中所有潜在的路径是否都已考虑在内,包括适当的错误处理?

所有代码是否可以访问? 任何代码是否冗余? 循环中多少个语句可以放在循环之外,从而减少计算时间? 分支决策是否过于复杂?

可移植性

[编辑 | 编辑源代码]

程序是否依赖于特定安装中独有的系统或库例程? 是否已标记并注释了机器相关的语句? 是否已避免对字母数字或特殊字符的内部位表示的依赖? 将程序从一个硬件/软件系统或环境转移到另一个环境需要多少工作量?

一致性

[编辑 | 编辑源代码]

一个变量名是否用于在程序中表示不同的逻辑或物理实体? 程序中是否只包含任何给定物理或数学常数的一种表示形式? 功能相似的算术表达式是否以类似的方式构建? 是否对缩进、命名法、调色板、字体和其他视觉元素使用了一致的方案?

可维护性

[编辑 | 编辑源代码]

是否已为将来的扩展预留了一些内存容量? 设计是否具有凝聚力,即每个模块是否具有独特、可识别的功能? 软件是否允许更改数据结构(面向对象的設計更有可能允许这样做)? 如果代码是基于过程的(而不是面向对象的),更改是否可能需要重新构建主程序,或者只是一个模块?

可测试性

[编辑 | 编辑源代码]

代码中是否使用了复杂的结构? 详细设计中是否包含清晰的伪代码? 伪代码的抽象级别是否高于代码? 如果在并发设计中使用任务,是否提供了用于提供足够的测试用例的方案?

可用性

[编辑 | 编辑源代码]

是否使用了 GUI? 是否有足够的在线帮助? 是否提供了用户手册? 是否提供了有意义的错误消息?

可靠性

[编辑 | 编辑源代码]

循环索引是否进行了范围测试? 输入数据是否已检查范围错误? 是否避免了除以零? 是否提供了异常处理? 软件在指定时间段内在规定的操作条件下正确执行其预期功能的概率,但需求文档中也可能存在问题...

功能是否已针对速度进行了优化? 是否已将重复使用的代码块形成子例程? 程序是否已检查内存泄漏或溢出错误?

安全性

[编辑 | 编辑源代码]

软件是否保护自身及其数据免受未经授权的访问和使用? 它是否允许操作员执行安全策略? 安全机制是否合适、充分且正确地实施? 软件是否能够抵御其预期环境中可能发生的攻击?

用户的视角

[编辑 | 编辑源代码]

除了软件的技术质量外,最终用户的体验也决定了软件的质量。 软件质量的这个方面被称为可用性。 很难量化给定软件产品的可用性。 一些需要问的重要问题是

  • 用户界面是否直观(不言自明/自文档)?
  • 执行简单操作是否容易?
  • 执行复杂操作是否可行?
  • 软件是否提供合理的错误消息?
  • 小部件的行为是否符合预期?
  • 软件是否记录良好?
  • 用户界面是否响应迅速或过慢?

此外,(免费或付费)支持的可用性也可能影响软件的可用性。

参考文献

[编辑 | 编辑源代码]
注释
  1. a b Pressman 2005, p. 746
  2. Pressman 2005, p. 388
  3. Crosby, P., Quality is Free, McGraw-Hill, 1979
  4. McConnell 1993, p. 558
  5. DeMarco, T., Management Can Make Quality (Im)possible, Cutter IT Summit, Boston, April 1999
  6. J.D. Musa, A. Iannino, and K. Okumoto, Engineering and Managing Software with Reliability Measures, McGraw-Hill, 1987
  7. Pressman 2005, p. 762
  8. ISTQB - What is software testing?
  9. a b Cem Kaner http://www.kaner.com/pdfs/metrics2004.pdf
  10. Douglass Hoffman http://www.softwarequalitymethods.com/Papers/DarkMets%20Paper.pdf
参考书目
  • McConnell, Steve (1993), Code Complete (First ed.), Microsoft Press
  • Pressman, Scott (2005), Software Engineering: A Practitioner's Approach (Sixth, International ed.), McGraw-Hill Education

进一步阅读

[编辑 | 编辑源代码]
  • 国际标准化组织。 软件工程 - 产品质量 - 第 1 部分:质量模型。ISO,瑞士日内瓦,2001 年。ISO/IEC 9126-1:2001(E)。
  • Diomidis Spinellis。 代码质量:开源视角。Addison Wesley,美国马萨诸塞州波士顿,2006 年。
  • Ho-Won Jung、Seung-Gweon Kim 和 Chang-Sin Chung。测量软件产品质量:ISO/IEC 9126 调查IEEE 软件,21(5):10–13,2004 年 9 月/10 月。
  • Stephen H. Kan。 软件质量工程中的度量和模型。Addison-Wesley,美国马萨诸塞州波士顿,第二版,2002 年。
  • Robert L. Glass。 构建高质量软件。Prentice Hall,美国新泽西州上鞍河,1992 年。
  • Roland Petrasch,“‘软件质量’的定义:一种实用方法”,ISSRE,1999 年
[编辑 | 编辑源代码]
华夏公益教科书