HIT软件构造第1章知识点复习整理
第一章 软件构造的多维度视图和质量目标
多维软件视图
1. build-time views
构造阶段:idea->requirement->design->code->installable/可执行文件
三个相互关联的形成
词汇层面
基于词汇的半结构化代码(近乎自然语言的风格和遵循特定的编程语法)
语义层面
AST:彻底结构化,将源代码变成一棵树,对树的各种操作==对源代码的修改
语法层面
基于图形的或正式定义的通常是图形化或形式化的——在设计阶段建模,并转化为源代码(它是根据用户的需求进行面向对象分析与设计的结果)
库
库存储在他们自己的磁盘文件中,收集了一组可以跨各种程序重用的代码函数。库的来源:操作系统提供的库、编程语言提供的库、第三方公司提供的库、自己积累的库。
库的链接
编程时和build时,需要告诉IDE和JVM在哪里寻找某些库
将库集成到可执行程序中两种不同的方法
- 静态链接
发生在build时
1) 库是单个对象文件的集合
2) 在构建过程中,当链接器工具确定某个函数时,它会从库中提取适当的目标文件,并将其复制到可执行程序中
在创建了最终的可执行程序后,不可能将程序与其库分开
2. Runtime views
可执行程序
CPU执行的机器可读指令序列,以及相关的数据值(完全编译好的程序)可以直接加载到计算机的内存中并运行
配置和数据文件
不是可执行文件,他们为程序提供有用的数据和配置信息,可以从磁盘加载。(从硬盘文件中获得有用的数据)
分布式程序
这种类型的软件由多个可执行程序组成,这些程序通过网络相互通信,或者简单的称为运行在同一机器上的多个进程
分布式程序
这种类型的软件由多个可执行程序组成,这些程序通过网络相互通信,或者简单的称为运行在同一机器上的多个进程
原生机器码
- 完全将可执行程序转换为CPU的本地机器代码。
- CPU只是简单地“跳转”到程序的起始位置,并且所有的执行都是纯粹使用CPU的硬件来执行的。
- 在执行时,程序可选择调用操作系统以访问文件和其他系统资源。
- 这是执行代码的最快方式,因为程序可以完全访问CPU的特性。
程序完全解释执行
运行时系统将整个源代码加载到内存中并对其进行解释(如基本代码、UNIX shell等)
解释型字节码
- 字节代码类似于本机机器代码,除了CPU不能直接理解它们。
- 它首先将它们转换为本机机器代码,或者在程序执行时解释它们。
- 因此,字节代码环境需要在程序旁边加载一个额外的解释器或编译器。
Perl或Python
它们是解释的,而不是编译的,但在运行时使用字节代码。
执行Perl或Python脚本的简单操作会自动触发字节码的生成。
动态链接
- 动态链接方法不会将对象文件复制到可执行的映像中,相反,它会注意到成功执行程序需要哪些库。
库文件不会在build阶段被加入可执行软件,仅仅做出标记
- 当程序开始运行时,这些库将作为单独的实体加载到内存中,然后与主程序连接。
程序运行时,根据标记装载库至内存
- 动态库是通过连接对象文件而构造的磁盘文件。然后,该库被收集到发布包中,并安装在目标机器上。只有这样,它才能被加载到机器的内存中。
发布软件时,记得将程序所依赖的所有动态库都复制给用户
动态链接的优点
- 可以升级到更新的库版本(添加特性或修复bug),而不需要重新创建可执行程序。
- 许多操作系统可以通过将库的一个副本加载到内存中来优化内存使用,同时与其他需要该库的程序共享
内存信息转储
硬盘上的一个文件,其中包含进程内存内容的副本,当进程被某些类型的内部错误或信号中止时产生。
执行跟踪
用日志的方式记录程序执行的调用次序
事件日志记录为系统管理员提供了对诊断和审计有用的信息
事件日志:系统层面
在开发周期中,会考虑将记录的不同类别的事件,以及将在事件消息中显示的详细信息。
每个类事件都被分配一个唯一的“代码”来格式化和输出人类可读的消息。
事件日志记录(构件/系统层面) | 执行跟踪(代码层面) |
---|---|
主要由系统管理员使用 | 主要由开发人员消费 |
记录“高级”信息(例如,程序安装失败) | 记录“低级”信息(例如,抛出的异常) |
不能太“嘈杂”(包含许多重复的事件或对目标受众没用的信息) | 可能会嘈杂 |
基于标准的输出格式通常是可取的,有时甚至是必需的 | 对输出格式的限制很少 |
事件日志消息通常都被本地化了 | 本地化很少会引起关注 |
添加新类型的事件,以及新的事件消息,不需要很敏捷 | 添加新的跟踪消息必须是敏捷的 |
视图之间的转换
软件系统的质量特性
外部质量因素:影响用户
内部质量因素:影响软件本身和他的开发者
外部质量取决于内部质量
外部质量因素
按照预先定义的“规约”执行
正确性:最重要的质量指标
测试和调试:发现不正确、消除不正确
防御式编程:在写程序的时候就确保正确性
形式化方法:通过形式化验证发现问题
健壮性:针对异常情况的处理(出现异常的时候不要“崩溃”)
健壮性是对正确性的补充
正确性:软件的行为要严格的符合规约中定义的行为
健壮性:出现规约定义之外的情形的时候,软件要做出恰当的反应
鲁棒性:鲁棒性涉及到“异常情况”,这意味着正常情况和异常情况的概念总是相对于某一规范的(其中正常和非正常的情况是主观的而不是客观的)未被specification覆盖的情况就是“异常情况”(所谓的“异常“,取决于spec的范围)
在这个意义上,“正常的”不意味就是“可取的”
可扩展性:可扩展性是指使软件产品易于适应规格的变化。
可复用性:一次开发,多次使用
(发现共性)
兼容性:不同软件之间相互可容易的集成
软件元素之间需要相互交互,所以兼容性很重要
兼容性的关键是标准化,特别是标准协议。
方法包括:
- 标准化的文件格式,如在Unix系统中,其中每个文本文件都只是一个字符序列
- 标准化的数据结构,如在Lisp系统中,其中所有的数据和程序,都用二进制树(在Lisp中称为列表)表示
- 标准化的用户界面,如各种版本的Windows、OS/2和MacOS,其中所有工具都依赖于一个单一的范例与用户通信,基于标准组件,如Windows、图标等
效率:效率是指软件系统对硬件资源提出尽可能少的需求的能力,如处理器时间、内部和外部存储器中所占用的空间、通信设备中所使用的带宽。
可移植性:软件可方便的在不同的技术环境之间移植
易用性:容易学、安装、操作、监控
给用户提供详细的指南
Structural simplicity
Know the user
功能性:功能性是指系统提供的可能性范围
程序设计中有一种不适宜的趋势,即软件开发者增加越来越多的功能,企图跟上竞争,结果是程序极为复杂不灵活,占用过多的磁盘空间
及时性
Other(可验证性、完整性、可修复性、经济性)
内部质量因素
源代码相关因素,如代码行(LOC)、循环Complexity圈复杂度等
与架构相关的因素,如耦合、凝聚力、耦合度、内聚度等
可读性、可理解性、清晰度、大小
折中
例子:最佳效率需要对特定硬件和软件环境的完美适应,这与可移植性相反,以及对规范的完美适应,在规范中,可重用性推动解决比最初给出的更普遍的问题。§的及时性压力可能会诱使我们使用“快速应用程序开发”技术,其结果可能没有太大的可扩展性
开发人员需要对以上情况做出权衡
正确的软件开发的过程中,开发者应该行不同质量因素之间如何做出这种的设计决策和标准明确的写下来
虽然需要折中但是“正确性”不能与其他质量因素折中
正确性和鲁棒性:可靠性
可扩展性和可重用性:模块化
OOP如何提高质量?
正确性:封装、去中心化
健壮性:封装、错误处理
可扩展性:封装、信息隐蔽
可重用性:模块化、组件、模型、模式
兼容性:标准化模块和接口
可移植性:信息隐藏、抽象
软件建设的五大关键质量目标
Easy to understand
Ready for change(可维护性)
Cheap for develop(可重用性)
Safe from bugs(防止错误)(鲁棒性/正确性)
Efficient to run
总结
描述软件系统的三个维度:
按阶段:构建和运行时视图
按动态:时刻和周期视图
按级别:代码和组件视图
每个视图的元素、关系和模型
视图之间的转换
软件系统的质量特性
-外部和内部的质量因素
-重要的外部质量因素
-质量因素之间的权衡
软件建设的五大关键质量目标
-易于理解:优雅而漂亮的代码/可理解性
-准备更改:可维护性和适应性
-开发成本低廉:重用设计/可重用性
-避免bug:健壮性
-运行高效:性能