目录
第0讲 软件构造概论
学分3.0,考试课,分数构成如下:
- 实验:35%(7%+14%+14%=35%)
- 个人博客:5%
- 期末考试:60%
第1讲 软件构造的多维度视图和质量目标
1.1 软件视图的三个维度
软件可以视作程序、数据和文档的集合,也可以视为模块和数据(控制)流的集合。
软件的视图可以按照以下形式划分:
- 按阶段划分:构造时/运行时视图;
- 按动态性划分:时刻/阶段视图;
- 按构造对象的层次划分:代码/构件视图。
时刻 | 阶段 | |||
代码层面 | 组件层面 | 代码层面 | 组件层面 | |
构造阶段 | 源代码、抽象语法树、接口、类、属性、方法 (类图描述) | 包、文件、静态链接、库、测试用例、生成脚本 (构件图描述) | 代码改动 | 配置项,版本 |
运行阶段 | 代码快照,内存转储 | 包、库、动态链接、配置、数据库、中间件、网络、硬件 (部署图描述) | 执行堆栈跟踪,并发多线程 | 事件日志、多进程、分布式进程 |
过程调用图、消息图 (序列图描述) |
1.1.1 构造阶段
构造阶段的视图描述如下:
- 代码层面:代码的逻辑组织,指代码中程序块的组织形式,以及程序块之间的依赖关系;
- 组件层面:代码的物理组织,指源代码是如何通过文件、目录、包、库等组织的,以及它们之间的依赖关系;
- 时刻视图:特定时刻的软件形态;
- 阶段视图:软件形态随时间的变化。
1. 构造阶段、时刻和代码层面视图
- 词汇层面:词汇导向的、半结构化的源代码,具有近乎自然语言的风格和特定的语法(形式语言),前者方便程序员,后者方便编译;
- 语法层面:抽象语法树(AST),用于将半结构化的源代码表示为一棵结构化的树,对树的操作等价于对于源代码的修改;
- 语义层面:使用图形化或者形式化的方式表达源代码试图实现的目标,可以用UML类图等描述,用于表达“需求”和“设计”思想,再转写成代码。
2. 构造阶段、阶段和代码层面视图
与时刻不同,阶段视图注重于表现代码变化,包括代码行的添加、删除和修改。
3. 构造阶段、时刻和组件层面视图
源代码存储在文件中;文件被封装到包(目录)中,从逻辑上讲,也可以视为被封装到组件和子系统中;可重用的模块以库的形式存在。
4. 构造阶段、阶段和组件层面视图
阶段和组件层面的视图注重于软件实体随着时间的变化。下面介绍软件或者SCI(配置项)的版本管理:
VCS(Version Control System)是一组进行版本控制的软件。软件随着时间变化的过程可以通过进化图进行描述:
软件的版本控制是指把一个唯一的版本名称或者版本号分配给软件的一个状态的过程。在细粒度层面上,版本控制还可以用于包括软件的所有电子信息中。
1.1.2 运行阶段
在运行阶段,程序载入机器,开始执行。运行阶段的视图描述如下:
- 代码层面:逻辑实体在内存中的呈现,包括程序在某个时刻的内存状态,以及各个程序单元是如何通信的;
- 组件层面:物理实体在物理硬件环境中的呈现,即软件是如何部署在机器上的(可能有多个机器),以及这些组件的通信方式;
- 时刻视图:逻辑/物理实体在内存/硬件环境中特定时刻的形态;
- 阶段视图:逻辑/物理实体在内存/硬件环境中的形态随时间的变化。
5. 运行阶段、时刻和代码层面视图
使用代码快照图描述这个视图,描述程序运行时内存里变量的状态,例如:
也可以使用内存信息转储技术查看程序某个时刻的状态,内存信息转储将进程内存内容保存到硬盘上的一个文件中,一般当进程因某种内部错误或信号而中止时产生,以便调试。
6. 运行阶段、阶段和代码层面视图
可以用UML时序图或者日志的方式记录程序操作的次序,进行执行跟踪。
7. 运行阶段、时刻和组件层面视图
可以用UML部署图表达。
8. 运行阶段、阶段和组件层面视图
可以使用系统层面的事件日志,事件日志记录不同类别的事件和详细信息,它为每类事件分配一个唯一的代码,格式化输出一条人类可以理解的消息。
1.1.3 运行时程序的组成
可执行程序是指一组机器可以直接理解的指令序列和相关的数据的集合。
可执行程序可以存在以下几种形式:
- 原生机器码:效率最高,将源代码编译为机器可以直接理解的指令序列,例如C、C++等;
- 完全解释执行:解释器将代码载入内存,解释代码,代码通过解释器和机器交互,例如BASIC、UNIX Shell等;
- 解释型字节码:编译器将代码编译成类似于机器代码的字节码,但是机器不能直接执行它,需要通过JVM等翻译成机器码执行,如Java等、
Python、Perl在执行前通过解释器翻译成字节码,然后在虚拟机上运行。
库是一组可以在各种程序中重复使用的代码函数集合,以文件的形式存储在磁盘文件中。在构造阶段,库可以视为对语言的扩展,开发者可以像使用编程语言指令一样使用库中的功能。
库的来源可以包括:操作系统提供的库、编程语言提供的库、第三方库、自己积累的库。
链接库的方式包括静态链接和动态链接,静态链接发生在构造阶段,在静态链接后,库被拷贝进入代码形成整体,执行的时候无需提供库文件;动态链接不会在构造阶段被加入可执行软件,仅仅做出标记(视作指针),程序运行时,根据所做的标记装载指定库至内存,调用需要的函数。
发布软件时,要附带依赖的所有动态库。动态库相对于静态库的优点如下:
- 更新库的版本时,可能不需要重新构建可执行程序;
- 多个软件同时调用一个库时,操作系统会进行优化,只装载一份进入内存供这些软件使用,节省空间。
1.1.4 视图的转换
1.2 软件的质量指标
软件的质量指标分为外部指标和内部指标。外部质量因素影响用户,内部质量影响软件本身和开发者,软件的外部质量取决于内部质量。
软件的外部质量指标包括:
- 正确性:按照预先定义的规约(Spec)执行,是最重要的指标,为了保证正确性,可以采用测试和调试、防御式编程、形式化验证方法(数学证明);
- 健壮性:针对异常情况的处理,是对正确性的补充,在出现规约以外的情形时,要做出恰当的反应,不可以崩溃,异常情况取决于Spec的定义,即Spec没有覆盖的情况就是异常情况;
- 可扩展性:对规约的修改的容易度,以应对不同的变化,规模越大的软件扩展越不容易,为了提升可扩展性,需要遵循简约主义、分离主义设计原则;
- 可复用性:发现共性,一次开发,多次使用;
- 性能:包括算法、IO、内存管理等,必须保证正确性的前提下关注性能,性能的优化有时会降低可复用性和可扩展性,需要与其他属性进行折中;
- 及时性:软件需要在用户约定的时间前交付。
软件的内部指标包括:
- LOC(代码行数)、循环复杂度等;
- 结构相关的因素,如耦合性和内聚性等;
- 可读性、可理解性和清晰性;
- 软件大小。
复杂性会降低外部质量指标,内部质量因素通常被用作外部质量因素的部分考量。
在软件开发过程中,需要对各个因素进行折中,开发者应该将不同质量因素之间如何做出折中的设计决策和标准明确的写下来,但是正确性必须得到保证,不允许折中。
软件开发过程中的5个关键质量目标:
- 易于理解:体现可读性、可理解性和清晰性;
- 开发成本低:体现可复用性;
- 易于修改:体现可维护性;
- 没有Bug:体现正确性、健壮性;
- 运行高效:体现性能。