HIT软件构造第一章知识点总结

一.软件构造过程的多维视图

    总的来说,软件构造有3个维度,每个维度划分为两种情况,共八种视图,下面一一详细的介绍。
HIT软件构造第一章知识点总结

1.三个维度

(1).时间维度

    主要是按照是否周期性的去看待一个软件来进行划分的,分为瞬时角度和周期角度。
    瞬时角度,顾名思义,就是我们去看待某一次我们写出的代码,并不考虑我们一次次更新代码之间的联系。当然,作为大学生,我们之前写各种各样的程序一般都是从瞬时角度去看待的。
    周期角度上,由于现在的软件整体趋势是变得越来越复杂,功能越来越多,因此我们更关注的就是变化情况了,我们也希望能看出我们每次完善或更新这个软件都做了哪些工作。

(2).编码维度

    分为开发(构建)阶段和运行阶段。
    在开发阶段,我们更多的是在一个程序开发人员的角度上去看待各种各样的问题,比如代码风格,数据结构,类的结构等等。
    在运行阶段,我们更多的是在用户的角度上去看待软件的一系列问题,比如运行的快慢,占用的空间,目前类中有多少个对象等等。
    根据某种语言的运行时文件是否已经是整个的二进制文件,我们分为编译型语言与解释型语言。编译型语言比如C,C++等在运行程序时,可执行程序已经完全是一个二进制的机器码了,因此运行快,但是由于机器码严重依赖于机器和操作系统,因此可移植性差;而解释型语言java和python等不需要编译,在运行程序时,执行到某条语句的时候,才开始翻译这条语句,因此速度会比较慢,但是兼容性很好。

(3).层级维度

    总的来说,分为代码角度和模块角度。
    代码角度其实就是比较细致的去看我们的代码,主要是关注类内的详细组成和结构等等。
    而模块的角度则更宏观,主要是我们去研究类与类之间的联系,以及一些更高层级的联系等等,不关注微观操作,而是更关注于整体逻辑。

2.八种视图

(1).构建阶段,瞬时角度的代码层级视图

    主要关注的是我们在编写程序的某一时间点,我们的代码呈现出一种什么样的形式。主要体现在词汇层面,语法层面和语义层面。
    词汇层面上,主要是变量名,语句等的风格。一方面我们让程序员大家更好理解,另一方面我们也要照顾编译器。
    语法角度上,我们主要是看我们使用的算法的流程,例如语法树等等。我们甚至可以把我们的整个程序看成一颗树,把对树的操作等同于对代码的修改。
    语义层面上,我们看的主要是类与类之间的联系情况。例如下图中的java集合类的各类之间的联系情况。当然,更详细的还有UML图等等。

HIT软件构造第一章知识点总结

(2).构建阶段,周期角度的代码层级视图

    主要是关注随着时间,我们的代码的改变情况。我们主要是通过版本控制工具来实现对代码变化情况的记录。第二章中讲详细介绍。下图是用git实现版本控制,红色为上一次提交时有而这次没有的代码,绿色是这次新增的代码。
HIT软件构造第一章知识点总结

(3).构建阶段,瞬时角度的模块层级视图

    主要关注的是代码的组织情况,也就是我们所使用的类和文件等等如何进行组织。比如把功能类似的类放在一个包里等等。
    库文件是很好的组织方式。java打头的都是java自身提供的库,只要有JRE,程序import进对应的库就可以直接使用;而其他的则为第三方库,需要添加到编译路径中,让程序可以找到库的位置才可以使用。
    将库中的内容与我们的代码链接起来有两种实现方式,分别是静态链接与动态链接。
    静态链接是比较早期的链接方式了,就是程序在编译的过程中,把程序被翻译成的二进制代码与库文件中的内容整合起来形成一个整体。优点就是运行时不用再去寻找链接库(因为以及都整合到一起了),但缺点就是如果有很多文件都调用这个库文件,则会有大量的空间浪费,以及如果要是库文件更新,那对所有的使用了该库文件旧版本的程序都要进行重新编译,这将是非常麻烦的事情。基于以上的原因,现在静态链接逐渐被淘汰,动态链接成为主流。
    动态链接的方式就是只有当程序真正执行的时候,才会按照需要去加载对应的库文件的内容,这样库文件作出改动并不会很大的影响需要这些库的程序;编译阶段仅仅是做出标记。动态链接的库文件也是要在发布软件的时候一起发布的。
    关于更详细的与链接相关的内容可以参考CSAPP教材第七章的部分。

(4).构建阶段,周期角度的模块层级视图

    在这个视图下,我们注重的就是软件实体随时间的变化了,而不是代码的变化。我们通常在这个视图下,通过版本控制工具,确定软件的版本,以及版本之间的功能的变化等等。版本号的命名规则如下图所示。
HIT软件构造第一章知识点总结

(5).运行阶段,瞬时角度的代码层级视图

    关注的其实就是在某一运行时刻有多少个对象以及对应的属性等等。我们平时在debug过程中进行watch以及memory dump中所看到的内容,其实就是属于这个视图。在第三章会更详细的介绍代码快照图——用于描述程序运行时内存里变量层面的状态。

(6).运行阶段,周期角度的代码层级视图

    看重的是代码的执行情况,我们主要也是使用UML图。我们使用日志等追踪工具来记录程序执行的调用顺序和次数等等,就属于这个视图。注意,这个视图中的所谓的周期其实是程序的一个运行周期,也可以看做是上面视图5的随时间变化的情况。

(7).运行阶段,瞬时角度的模块层级视图

    主要考虑的是程序在不同机器上,或一台机器上不同位置下的模块配置情况。当我们发布软件或者是将我们软件的版本交给与我们共同开发的人的时候,我们就要详细的去考虑这一点的影响。

(8).运行阶段,周期角度的模块层级视图

    我们更关注的就是系统的使用情况了,同样也是使用日志来进行记录,但当然与前文有所不同,主要是从系统,宏观的事件来看。比如何时遇到了什么样的请求(比如输入用户名和密码,请求登陆网站)等等,而不是具体的某一个函数的调用情况。
    下面的图详细的描述了阶段6与阶段8之间日志的不同之处。
HIT软件构造第一章知识点总结

3.视图之间的联系

    下面一张图完美的解释了以上八个视图的联系。总之我们的起点是简简单单的敲代码,终点是构造出一个完整的软件。
HIT软件构造第一章知识点总结

二.软件构造的质量目标

    总的来说,我们构造软件是要追求“好”的软件,而所谓的对这个“好”的定义,就十分的复杂了。总的而言,我们可以按照影响的人群,来对我们构造软件的目标进行分类——主要影响用户使用的外部质量因素和主要影响软件本身和它的开发者以及其他程序员的内部质量因素。总的而言,外部的质量取决于内部质量。
    下面我们就总体的介绍对应的目标,对于各目标的更具体的实现方法,主要是在后面的课程学习中讲解。

1.外部质量目标

(1).正确性

    显然,一个软件的正确性显然是最重要的,运行不正确的软件就失去了价值。但什么是“正确性”呢?可能每个人有不同的看法,因此这里的正确性一般就是指预先定义的规则了,如果能够满足所有的规则,那就可以称这个软件目前是完全正确的了。
    各个层级的正确性是软件满足正确的基础。从最上层的插件,库文件,网络相关内容;到下面的高级程序代码,编译器;再到下面的指令体系结构,操作系统;最后到最底层的电路等等,都要保证正确性。
    根据历史经验,更能高效的确保软件的正确性的开发方法是基于测试优先的编程,具体的测试方法和技巧会在第六章进行讲解,总之就是,在开发前就将测试用例写好,开发的过程中与测试紧紧相连。

(2).健壮性

    健壮性指的就是软件系统在对异常情况(程序规格书里并没有进行说明)做出正常反应的能力,一般是至少要求程序不崩溃,与正确性互补。一般而言,健壮性的满足还是比较困难的,因为可能出现的异常情况很多。
    java语言有强大的异常处理机制,相比而言比C语言等在对异常的处理方面实用的多,对应的内容会在第七章进行讲解。

(3).易扩展性

    由于软件都是要发生变化的,就像我们使用的很多软件,都是过一段时间就要更新的,因此有应对潮流的可扩展性是很重要的。例如FLASH,曾经真的是火到不行,但这十几年间,随着技术的进步,而FLASH的可扩展性不好,因此FLASH的热度已经大大降低,市场也缩水了很多。
    总的而言,软件的规模越大,它的易扩展性越差,有的时候在某处小小的改变,就在其他各处出现前奇百怪的矛盾…
    目前比较流行且有效的办法是使用简单的体系结构和增强模块的自治性,同时减少模块与模块之间的相互影响,具体实现方式就是抽象数据类型的实现以及面向对象的编程思想。

(4).复用性

    复用性高其实也可以使得代码变得简洁。例如java中的接口,其实就是一种很好的提高复用性的方法。

(5).兼容性以及可移植性

    我把这两条放在一起,主要是它们有一定的相似度,容易搞混。其实他们的总体思路是一样的,就是当进入“陌生环境”时,软件的适应能力。只不过兼容性,主要指的是这个软件进入其他软件或操作系统等等综合的一个环境中,如何更好的集成,另外有的时候还指这个软件是否可以比较好的向下兼容版本;而可移植性主要就指的是进入了不同平台等等,是否需要花费大量的代价来调整。
    例如win7下的软件在win10系统下运行的很好,就可以说是兼容性好,而在Linux系统下运行的很好,就可以说是可移植性好。

(6).效率

    谈到效率大家肯定都不会陌生,尤其是对于OI选手。软件的效率也体现在对空间和时间的利用率上,当然包括了很多因素。
    但是,这条目标现在随着计算机算力的指数级增长,显得不像资源紧缺时的以前那么重要了。尤其是一些引入概率或贪心算法,大幅度降低时间复杂度但是使得结果不完全正确的情况,现在就和第一条产生冲突了。

(7).易用性

    这条主要是针对于用户体验而言的。这条的主观性还是很强的,一般体现在GUI的设计风格上。

(8).功能性

    这条并不是100%的优点了。一方面功能多肯定有助于提高竞争力,另一方面,功能多会导致操作繁琐,降低可易用性,可扩展性等等,甚至会更容易引起bug,维护起来更难。因此对功能性的追求应该是尽量谨慎的。
    我们的目标应该是在提高功能性的同时,保证质量水平不会降低。

(9).时效性

    一般指的是按照期限完成开发。一些开发策略比如敏捷开发就是为了提高时效性,在第二章即有详细的讲解 。一般而言,时效性和正确性,健壮性等是很容易产生冲突的。

(10).其他

    当然其实还有很多我们追求的性质,比如安全性,完整性,可验证性,可修复性等等等等。只能说软件的构造是要考虑很多很多方面的,这和我们之前写个小游戏等等完全不同,有时稍有不慎,影响都是巨大的。

2.内部质量目标

    主要是在软件开发人员的角度来说的。例如代码的可读性,当然还有重要的模块内高耦合,模块外低耦合的思想等等。其实一些外部的质量与内部质量目标紧紧相连,例如GUI的风格紧紧与易用性相连,代码风格与正确性相连。

3.目标之间的权衡

    显然,上面列出来了很多很多要追求的目标,每个目标都相应的有一些说起来比较抽象,具体问题还要具体问题的方法。例如OOP,真正用好还是需要一段时间的练习的。有些目标是互相冲突的,我们如何去做相应的权衡其实是一个没法做出很笼统的概括的,没法用层次分析法,给出每项指标的权值就量化了这个复杂的问题;因此我们只能具体问题具体分析,学会有意识地去权衡这些目标。
但总的而言,有下列五条比较重要的质量目标,如下图所示,对应的知识点也会在后面的章节更详细的列出。
HIT软件构造第一章知识点总结