软件构造

概述

[SWEBOK2004] 将软件构造定义为:通过编码、验证、单元测试、集成测试和调试等工作的结合,生产可工作的、有意义的软件的详细创建过程。

活动

软件构造的主要活动包括:

  1. 详细设计
  2. 编程
  3. 测试
  4. 调试
  5. 代码评审
  6. 集成与构建
  7. 构造管理

详细设计

  • 有些项目会将主要的详细设计工作分配在软件构造阶段完成
  • 不论是哪种项目,在软件构造阶段都不可避免的会涉及到详细设计的调整工作。因为编程语言是软件设计的一个重要约束,随着编程工作的进行和深入,人们可能会发现与预想不一致的情况和更多的约束,这个时候就需要在软件构造阶段修改详细设计方案。
  • 软件构造阶段详细设计使用的方法与技术与软件设计阶段是一样的,只是应用在更小的规模上。

编程

编程是软件构造的核心活动,其目的是生产高质量的程序代码。程序代码的典型质量包括:

  1. 易读性:程序代码必须是易读的,看上去“显而易⻅是正确的”。易读性是编程最为重要的目标,它可以使得程序更容易开发,尤其是易于调试;可以使得程序更容易维护,减少理解代码的难度和成本;可以使得程序易于复用。
  2. 易维护性:除了易读之外,易维护性要求程序代码易于修改(遵守开闭原则)
  3. 可靠性:程序代码必须是可靠的,要执行正确,并妥善处理故障
  4. 性能:程序代码必须是高性能的,包括时间性能和空间性能,需要进行详细的数据结构和算法设计
  5. 安全性:不要遗留程序漏洞,不要出现重要信息的泄漏(例如内存数据区泄漏)

编程的主要技术有

  • 构造可理解的源代码的技术,包括命名和空间布局;
  • 使用类、枚举类型、变量、命名常量和其它类似实体;
  • 使用控制结构;
  • 处理错误条件——既包括预计的错误,也包括未预期的异常;
  • 预防代码级的安全泄露(例如,缓冲区超限或数组下标溢出);
  • 使用资源,用互斥机制访问串行可复用资源(包括线程和数据库锁);
  • 源代码组织(组织为语句、例程、类、包或其它结构);
  • 代码文档;
  • 代码调整。

测试

通常来说,程序员每修改一次程序就会进行最少一次单元测试,在编写程序的过程中前后很
可能要进行多次单元测试,以证实程序达到了要求,没有程序错误。集成测试一般在单元测
试之后,用来测试多个单元之间的接口是否编程正确。

测试驱动方法和持续集成方法

调试

调试主要分为三个部分:重现问题、诊断缺陷和修复缺陷

修复缺陷时需要注意:

  1. 一次只修复一个缺陷
  2. 修改前保留旧版本的备份,如果项目使用了配置管理系统,这个工作回由配置管理工具完成,否则就需要由程序员手动完成
  3. 使用测试和评审验证修复的有效性
  4. 检查和修复类似的缺陷,这可以在代码搜索、程序切片等工具的帮助下进行

代码评审

代码评审是对代码的系统检查,通常是通过同行专家评审来完成的。通过评审会议可以发现并修正之前忽略的代码错误,从而同时提高软件的质量和开发者的技巧。

代码评审一般分为正式评审、轻量级评审和结对编程

[Cohen2011]的“实践经验”

  • 就算不能评审全部的代码,最少也要评审一部分(20–33%)代码,以促使程序员编写更好的代码。
  • 一次评审少于 200–400 行的代码。
  • 目标为每小时低于 300–500 LOC 的检查速率。
  • 花足够的时间进行正确缓慢的评审,但是不要超过 60–90 分钟/每次。
  • 确定代码开发者在评审开始之前就已经注释了源代码。
  • 使用检查列表,因为它可以极大地改进代码开发者和评审者的工作。
  • 确认发现的缺陷确实得到修复了。
  • 培养良好的代码评审文化氛围,在这样的氛围中搜索缺陷被看做是积极的活动。
  • 采用轻量级,能用工具支持的代码评审。

集成与构建

  • 在以分散的方式完成程序基本单位(例程、类)之后,软件构造还需要将这些分散单位集成和构建为构件、子系统和完整系统。
  • 集成有大爆炸式集成和增量式集成两种方式。实践中增量式集成有着更好的效果。(自顶向下、自底向上等多种方式)
  • 构建将可读的源代码转换为标准的能在计算机上运行的可执行文件。构建过程需要配置管理工具的帮助。

构造管理

构造管理主要包括构造计划、度量和配置管理三个任务。

构造计划

构造计划根据整个项目的开发过程安排,定义要开发的构件与次序,选择构造方法,明确构造任务并分配给程序员。构造方法的选择是构造计划活动的关键方面,影响着源代码的质量

度量

软件构造阶段的产品度量主要围绕源代码展开,常见度量包括:

  1. 每个类或者方法的复杂度
  2. 每个类或者方法的代码行数
  3. 每个类或者方法的注释行数

配置管理

实践方法

重构

为什么要重构

  1. 因为无法预计到后续数年的修改,导致软件开发阶段的设计方案不能满足修改要求;
  2. 随着修改次数的增多,软件设计结构的质量越来越脆弱,很难继续维持可修改性。

重构的定义

[Fowler1999]:修改软件系统的严谨方法,它在不改变代码外部表现的情况下改变其内部结构。

  1. 不改变代码的外部结构是指不改变软件系统的功能。
  2. 改变代码的内部结构是指详细设计结构的质量,使其能够继续演化下去

重构的时机

  • 增加新的功能时。需要注意的是重构发生在新功能增加完成之后,用来消除新功能所添加代码导致的坏味道;而不是发生在新功能添加之前,重构不改变代码外部行为,不是能够实现新功能添加的方法。
  • 发现了缺陷进行修复时。诊断缺陷时如果发现代码存在坏味道或者修复代码会引入坏味道(code smell),就需要进行重构。
  • 进行代码评审时。如果在评审代码时发现了坏味道,就需要进行重构。

Code Smell 坏味道,是设计结构低质量的表现,例如:

  • 太⻓的方法,往往意味着方法完成了太多的任务,不是功能内聚的,需要被分解为多个方法。[McConnell2004]认为如果方法代码⻓度超过了一个屏幕,就需要留心注意了。
  • 太大的类,往往意味着类不是单一职责的,需要被分解为多个类。
  • 太多的方法参数,往往意味着方法的任务太多或者参数的数据类型抽象层次太低,不符合接口最小化的低耦合原则,需要将其分解为多个参数少的方法或者将参数包装成对象、结构体等抽象层次更高的数据类型。
  • 多处相似的复杂控制结构,例如多处相同类型的Case结构,往往意味着多态策略不足,需要使用继承树多态机制消除复杂控制结构。
  • 重复的代码,往往意味着隐式耦合,需要将重复代码提取为独立方法。 一个类过多使用其他类的属性,往往意味着属性分配不正确或者协作设计不正确,需要在类间转移属性或者使用方法委托代替属性访问。
  • 过多的注释,往往意味着代码的逻辑结构不清晰或者可读性不好,需要进行逻辑结构重组或者代码重组。

测试驱动

  • 测试驱动开发又被称为测试优先(Test First)的开发,随着极限编程方法的普遍应用而得到普及。
  • 测试驱动开发要求程序员在编写一段代码之前,优先完成该段代码的测试代码。测试代码通常由
    测试工具自动装载执行,也可以由程序员手工执行。完成测试代码之后,程序员再编写程序代码,并在编程中重复执行测试代码,以验证程序代码的正确性。

测试驱动

结对编程

两个程序员挨着坐在一起,共同协作进行软件构造活动

Reference

  1. 南京大学软件学院2022春季学期《软件工程与计算二》
文章作者: ZY
文章链接: https://zyinnju.com/2022/06/18/软件构造/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 ZY in NJU