软件复杂性概述

软件复杂性问题定义

软件复杂性与程序复杂性不一样,软件复杂性是一个更为高层的概念,主要反映为分析,设计,测试,维护和修改软件的困难程度或复杂程度。而软件复杂性也是软件危机产生的最直接原因,人类的思维有限,要明确的认识软件的运行对人类而言有点勉强,我们只能通过定义软件的对象,属性,边界,交互逻辑来描述软件的运行机制。

当软件的运行逻辑条目越来越多时,复杂性呈指数提高,软件复杂性已经远远超过人类对复杂性控制的能力,软件隐含错误的概率越来越多,软件可靠性和可维护性越差,甚至可能引发软件项目的失败。软件复杂性是无法避免的,就像软件危机一样,是客观存在的,我们只能尽可能地以某种概率来减轻其不良影响。

分析,度量和控制软件复杂性是软件可靠性工程急需解决的重要问题,我们可以通过降低由软件设计方法和技巧使用不当而带来的复杂性,以更好地对软件开发过程进行控制。软件复杂性同时也直接关联到对软件开发费用,开发周期和软件内部隐藏错误的评估。

软件复杂性出现的主要原因

  1. 软件应用需求的复杂性;
  2. 软件应用框架,结构及模型的复杂性;
  3. 开发环境及应用环境的复杂性;
  4. 软件开发过程的复杂性;
  5. 涉及人力管理的复杂性
  6. 软件设计与验证的复杂性。

软件结构复杂性

软件复杂性的主要体现

  1. 软件结构复杂性
  2. 程序算法复杂性

软件复杂性形成的根源

软件设计过程是根源,我们在需要:

  1. 进行概要设计的时候需要对软件总体模块结构复杂性进行有效控制;
  2. 在进行详细设计的时候对模块结构复杂性和模块内部复杂性进行控制。

使之保持在一个合理的范围内。

软件结构复杂性体现为

  1. 模块复杂性:
    1. 模块内部结构复杂性:
      1. McCabe 度量
      2. Halstead 度量
    2. 模块接口复杂性:
      1. 模块调用关系图
      2. 模块或信息的扇入扇出数来度量
  2. 总体结构复杂性
    1. 尚无权威的度量方法
    2. 矛盾:单个模块划分越小,功能越简单,虽然降低模块内部结构复杂性,但是模块之间联系多,接口 复杂,总体复杂性增加。

软件复杂性控制

  • 内部模块结构复杂性控制
    • 模块隔离。单个模块进行单独的编制,调试,查错,修改 ,测试和维护。模块隔离有助于防止错误蔓延,降低软件复杂性,提高软件可靠性。
    • 控制模块大小和结构的控制。
  • 总体结构复杂性控制
    • 提高模块独立性
      • 模块耦合性控制。尽量使用数据耦合,少用 控制耦合,限制公共耦合范围,完全不用内容耦合四个原则。减少耦合性,降低模块复杂性。
      • 模块高内聚,并能识别低内聚。内聚是指模块功能的相对强度,用于衡量一个模块内部各元素彼此结合的紧密程度,是信息隐蔽和局部化的自然延伸。
    • 保持适当的扇入扇出。扇出量
      • 扇出量越大,模块功能宽度越大,模块就越复杂。
      • 扇出量太小,下级模块进一步分解成若干子模块并合并到上级模块。
    • 简化软件接口
      • 接口传递的信息尽量保持简单。
      • 单入口,单出口。
      • 避免模块接口之间的病态连接,杜绝引入或引用一个模块内部结构。

形成软件复杂性的重要原因

  1. 控制结构和数据结构复杂的程序复杂性高;
  2. 转向语句使用不当的程序复杂性高;
  3. 非局部变量较多的程序复杂性高;
  4. 按地址调用参数比按值调用参数的复杂性高;
  5. 模块及过程之间联系密切的程序的复杂性高;
  6. 嵌套深度大的程序的复杂性高;
  7. 循环结构的复杂性比选择结构和顺序结构的复杂性高;
  8. 模块宽度是形成软件复杂性的主要原因。

软件复杂性度量的基本度量准则集。

软件复杂性度量

软件复杂性度量的结果是软件复杂度,是对软件复杂性的定量描述,为软件复杂性的定量分析和控制提供依据,是软件复杂性分析和控制研究的基础。

软件复杂性度量的根本目的:通过控制软件复杂性来改善和提高软件的可靠性。

软件复杂性的度量的方法和标准主要分为两大类:

  1. 面向过程的软件复杂性度量:
    1. 代码语句行度量
    2. 基于FPA(功能点分析)的度量
    3. Halstead 软件科学度量法!!
    4. McCabe 结构复杂性度量
  2. 面向对象的软件复杂性度量
    1. C&K,MOOD

复杂性度量元的分类:

  1. 规模: 命令总数。如line count
  2. 难度:程序出现操作数的数目所决定的量表示。如Halstead 复杂性
  3. 结构:通常与程序结构有关的度量,McCabe 复杂度
  4. 智能度:算法难易程度。

LineCount 复杂度 (规模度量元)

统计程序的源代码行数,将其作为程序复杂性的度量。

Halstead 复杂度(难度度量元)

Halstead 复杂度根据程序中语句行的操作符和操作数的数量计
算程序复杂性。

  • 操作符和操作数的量越大,程序结构就越复杂。
  • 操作符包括语言保留字、函数调用、运算符,也可以包括有关的分隔符等。
  • 操作数可以是常数和变量等标识符。

Halstead 复杂度有11种方法,见PPT3.3 P21-22

McCabe 复杂度 (结构度量元)

McCabe 对程序流程图PFC进行静态分析,并将其转化为程序控制流图CFG,然后以图论的方法进行严格的结构分析 。

McCabe 复杂度包括:

  1. 环路复杂度

    1. 衡量判定模块的复杂程度。数量上可以表现为程序控制流图(第4章讨论) 中从
      开始点到终结点的独立路径条数,相当于合理预防错误所需测试的最少路径条数。
    2. 计算公式 :V(G) = m - n + 2p m 是G 的边数目;n 是G 的顶点数目;p 是G 的连通分支数
    3. 结构化模块:单入口单出口;非结构化模块:(可选的)多入口多出口。
    4. 当结构化模块程序控制流图增加从出口指向入口的辅助边,形成强连通图。此时强连通图的环路复杂度定义为图的秩数。