1 Multi-dimensional software views(多维软件视图)
- build-time /Run-time
- Moment/Period
- Code-level/Component-level
(1)开发阶段视图(Build-time view)
Build-time : idea -> requirement -> design -> installable / executable package
代码级视图:源代码:源代码是如何在逻辑上由基本的程序块组织起来的,如函数、类、方法、接口等,以及它们之间的依赖关系(代码的逻辑组织)
组件级视图:体系结构——源代码如何由文件、目录、包、库及其之间的依赖关系进行物理组织(代码的物理组织)
时刻视图:源代码和组件在特定时间内是什么样子的(特定时刻软件形态)
周期图:如何随着时间的变化(软件形态随时间的变化)
代码的逻辑组织:三种相互相关形式:
词汇层面:面向词汇的源代码
语法层面:面向语法的程序结构:例如,抽象语法树(AST)(将半结构化的源代码表示为一个结构化的树,对树做各种操作==对源代码的修改)
语义层面:面向语义的程序结构:例如,类图(使用类图(UML)来描述接口、类、属性、方法和它们之间的关系。在设计阶段建模,并转换为源代码。它是在用户需求方面的面向对象分析和设计的结果)
生成时间、时间周期和代码级视图:描述“变化”,随时间而变化的视图。§代码变化(定义为从一个版本到另一个版本向文件添加、修改或删除的行。):从一个版本到另一个版本添加、修改或删除到文件的行。
生成时间、时刻和组件级别的视图:源代码在物理上组织成文件,这些文件进一步由目录组织;§文件被封装成包,逻辑上,组件和子系统。§可重用的模块以库的形式存在
库:
库存储在它们自己的磁盘文件中,收集一组可跨各种程序重用的代码函数。
开发人员并不总是构建一个可执行程序文件,而是将定制开发的软件和预构建的库加入到一个程序中。§
在构建时,库函数可以看作是标准语言的扩展,其使用方式与开发人员编写的函数相同。开发者像使用编程语言指令一样使用库中的功能System.out.println(“Hello世界”);§
库的来源:
来自操作系统预装的库集,如文件和网络I/O、GUI、数学、数据库评估;操作系统提供的库-从语言SDK;编程语言提供的库;来自第三方来源;第三方公司提供的库;开发人员也可以发布自己的库。你自己积累的库
与存储库之间的链接:
在编辑、构建和安装程序时,必须提供要搜索的库的列表。编程时和build时,需告诉IDE和JVM在哪里寻找某些库§
如果源代码中引用了函数,但开发人员未显式编写,则会搜索库列表以找到所需的函数。javac类路径。/lib/*。jar§找到该函数后,会将相应的对象文件复制到可执行程序中。§
将库集成到可执行程序中的两种不同方法:静态链接;动态链接
静态连接:
在静态链接中,库是单个对象文件的集合。§
在构建过程中,当链接器工具确定需要函数时,它从库中提取适当的对象文件并将其复制到可执行程序,即库被拷贝进入代码形成整体、执行的时候无需提供库文件
库的对象文件与开发人员自己创建的任何对象文件完全相同。§
静态链接发生在生成时间内
最终是要加载到目标计算机上的一个可执行程序。
创建最终可执行程序后,无法将程序与其库分离。静态链接发生在构造阶段
评估图:评估图描述了软件的开发过程和阶段。
版本控制:
软件版本控制是为计算机软件的唯一状态分配唯一版本名或指定计算机软件的唯一版本号的过程。
在给定的版本号类别内(主要、次要)中,这些数字通常按递增顺序分配,并与软件的新开发相对应。
在细粒度级别上,修订控制通常用于跟踪增量不同版本的电子信息,无论这些信息是否是计算机软件
- 运行时视图
运行时:程序被载入目标机器,开始执行
代码级视图:源代码:可执行程序的内存状态是什么样子的,程序单元(对象、函数等)是如何相互交互的?逻辑实体在内存中如何呈现?
组件级视图:体系结构——软件包如何部署到物理环境中(操作系统、网络、硬件等),以及它们如何交互?物理实体在物理硬件环境中如何呈现?
运行时软件的高级概念:
- 可执行程序:CPU执行的机器可读指令的序列,以及相关的数据值。这是完全编译的程序,准备加载到计算机内存并执行。程序首先加载到内存中,存在几种执行软件的机制,这取决于加载程序之前进行的编译量以及程序支持的数量。
可执行程序:本机计算机代码:将可执行程序完全转换为CPU的本地机器代码。CPU只是“跳转”到程序的起始位置,并且所有的执行都纯粹使用CPU的硬件来执行。在执行时,程序可选择地调用操作系统以访问文件和其他系统资源。这是执行代码的最快方式,因为程序可以完全访问CPU的功能
完整程序解释(程序完全解释执行):运行时系统将整个源代码加载到内存中并进行解释它(如基本、UNIXshell等)
解释的字节码(解释型字节码):字节码类似于本地机器码,但CPU不直接理解它们。它首先将它们转换为本机机器代码,或在程序执行时解释它们。因此,字节码环境需要在程序旁边加载一个额外的解释器或编译器。
- 库:可被不同程序重用的常用对象代码的集合。大多数操作系统都包括开发人员可以重用的标准库,而不是要求每个程序提供自己的库。库不能在目标计算机上直接加载和执行;它必须首先与可执行程序进行链接
动态连接:
动态链接方法不会将对象文件复制到可执行映像中,它会注意成功执行程序需要哪些库。库文件不会在build阶段被加入可执行软件,仅仅做出标记§
当程序开始运行时,将库作为单独的实体加载到内存中,然后与主程序连接。程序运行时,根据标记装载库至内存§
动态库是通过连接对象文件而构建的磁盘文件。然后将库收集到发布包中并安装在目标机器上。只有这样,才能将其加载到机器的内存中。发布软件时,记得将程序所依赖的所有动态库都复制给用户
优点:可以升级到库的较新的版本(添加功能或修复错误),而无需重新创建可执行程序。许多操作系统可以通过只将内存的一个副本加载到内存中,但与需要同一库的其他程序共享来优化内存使用
- 配置和数据文件:这些文件不是可执行文件;它们提供了程序可以从磁盘加载的有用数据和配置信息
任何大小较大的程序都使用外部数据源,例如磁盘上的文件。
您的程序调用操作系统,以请求将数据读入内存。
屏幕上显示的位图图形图像
以数字化波形形式存储的声音
自定义程序行为的配置文件
包含联机帮助文本的一套文档
包含名称和地址的数据库
4、分布式程序:这种类型的软件由多个可执行程序组成,它们通过网络或仅仅作为在同一台机器上运行的多个进程相互通信。-这与具有单片程序映像的传统软件形成鲜明对比。
例如,软件系统可能使用客户端/服务器模型,单台服务器程序运行在一台计算机上,大量客户端程序运行在许多其他计算机上。§
在这个场景中,构建系统可以创建两个发布包,因为不同的人将安装服务器程序和客户端程序。§
或者,可以使用相同的版本包来安装这两个单独的程序。§
分布式程序的运行态:需要多个运行程序,分别部署于多个计算机物理环境
快照图:重点关注目标计算机内存中的可变级执行状态。§程序的细粒度状态。
内存信息转储:硬盘上的一种文件,其中包含进程内存内容的副本,是当进程由某种内部错误或信号中止时产生的。
调试器可以加载转储文件,并显示其中包含的有关正在运行的程序状态的信息。
信息包括寄存器的内容、调用堆栈和所有其他程序数据(计数器、变量、交换机、标志等)。它是为了分析程序的状态,程序员会查看内存缓冲区,以查看在故障时正在处理哪些数据项。
UML中的序列图:程序单元(对象)之间的交互作用
执行跟踪:跟踪涉及专门使用日志记录来记录有关程序执行的信息。用日志方式记录程序执行的调用次序§
这通常被程序员用于调试目的,并取决于跟踪日志中包含的信息的类型和详细信息,由有经验丰富的管理员或技术支持人员以及软件监控工具来诊断软件的常见问题
事件日志:事件日志记录为系统管理员提供了对诊断和审计有用的信息。系统层面在开发周期中考虑将记录的不同事件类别以及事件消息中显示的详细信息。§
要为每类事件分配一个唯一的“代码”,以格式化和输出人类可读的消息。
这便于本地化,并使系统管理员能够更容易地获取有关所发生的问题的信息
- 软件构建:视图之间的转换
软件建设中的转换类型:
无->代码:编程/编码(ADT/OOP) 查看、静态分析/检查§
代码->组件:设计(ADT/OOP;可重用性;可维护性)-生成:编译、静态链接、包、安装等构建时->运行时:安装/部署-调试、单元/集成测试(健棒性和正确性)§
Momont->周期:版本控制-加载、动态链接、执行(倾销、分析、日志记录)-并发线程
- 软件系统的质量特性
外部质量因素 影响 用户
内部质量因素 影响 软件本身和它的开发者
外部质量取决于内部质量
外部因素:
正确性:正确性是指软件产品执行其规范所定义的精确任务的能力。按照预先定义的“规约”执行。正确性时最重要的质量指标。
假设软件系统已分层开发:在下层也正确的假设下,保证其正确性。
确保正确性的方法:测试和调试
防御性的编程,如打字和断言
形式化程序规范和验证的数学技术
健壮性:健壮性是指软件系统对异常情况作出适当反应的能力。它补充了正确性。
正确性指软件的行为要严格的符合规约中定义的行为,而健壮性指出现规约定义之外的情形的时候,软件要做出恰当的反应而非崩溃
(异常情况:没有被规约覆盖的因素)
可扩展性:是使软件产品适应规范变化而进行修改的难易度
规模越大,扩展起来越不容易
有两个原则可以提高可扩展性:
简约主义设计:一个简单的架构总是比一个复杂的架构更容易适应变化。
分离主义设计:模块越自主,一个简单的变化只影响一个模块或少量模块的可能性,而不是触发整个系统变化的连锁反应的可能性就越高
可复用性:软件元素用于构建许多不同应用程序的能力。一次开发,多次使用。
对可重用性的需求来自于观察到,软件系统通常遵循类似的模式;应该有可能利用这一共性,并避免对以前遇到的问题重新发明解决方案。
一个可重用的软件元素将适用于许多不同的开发
兼容性:将软件元素与其他元素结合起来的易用性
兼容性很重要,因为我们不在真空(真空)中开发软件元素:它们需要相互交互。但是他们经常遇到互动的困难,因为他们对世界其他地方做出了相互矛盾的假设。例如,许多操作系统都支持的各种不兼容的文件格式。只有在文件格式兼容时,程序才能直接使用他人的结果作为输入。(文件格式的兼容性)
兼容性的关键是标准化,特别是标准协议。
以下方法可以帮助:
标准化的文件格式,如在Unix系统中,其中每个文本文件都只是一个字符序列。
标准化数据结构,如在Lisp系统中,其中所有数据和程序都由二叉树表示(在Lisp中称为列表)。
标准化用户界面,如各种版本的Windows、OS/2和MACOS,其中所有工具都基于标准组件,如窗口、图标等与用户通信。§
通过定义对由软件操作的所有重要实体的标准化访问协议来获得更通用的解决方案
性能:效率是软件系统对硬件资源提出尽可能少量需求的能力,如处理器时间、内外存储器中占用的空间、通信设备中使用的带宽。
如果软件不正确,效率并不重要。
性能毫无意义,除非有足够的正确性。对效率的关注必须与其他目标相平衡,如可扩展性和可重用性;对性能的关注要与其他质量属性进行折中—极端优化使软件如此专业化,不适合更改和重复使用。过度的优化导致软件不再适应变化和复用
过早优化是万恶之源。
可移植性:系统可以方便的在不同技术环境间移植。
易用性:易学、易操作、易安装,需要给用户详细的指南。
需要保障软件结构的简单,了解用户的需求。
实用性:由系统提供的可能性的范围
程序设计中一种不适宜的趋势,即软件开发者增加越来越多的功能,企图跟上竞争,其结果是程序极为复杂、不灵活、占用过多的磁盘空间
更容易的问题是,添加新特性可能导致一致性,影响它的易用性。
更困难的问题是避免如此关注特征,以忘记其他品质(忽略整体质量)
借助OO开发的质量增强技术,在整个项目中除功能之外的所有方面保持质量水平恒定。§您只是不会在可靠性、可扩展性等方面达成妥协:在您对新功能感到满意之前,您拒绝继续使用新功能
及时性:软件系统在用户需要时或之前发布的能力。
可验证性(可验证性)是易于准备验收程序,特别是测试数据,以及在验证和操作阶段检测故障和跟踪故障到错误的程序。§
完整性是软件系统保护其各种组件(程序、数据)免受未经授权访问和修改的能力。§
可修复性是一种促进修复缺陷的能力。§
经济(经济性),是一个系统在分配预算下或低于分配预算下完成的能力
内部因素:
源代码相关因素,如代码行(LOC)、周期复杂度等§
体系结构相关因素,如耦合、内聚性等§
可读性§可理解性§清晰度§大小
质量性能之间的权衡:折中:正确的软件开发过程中,开发者应该将不同质量因素之间如何做出折中的设计决策和标准明确的写下来
虽然需要折中,但“正确性”绝不能与其他质量因素折中。
最重要:正确性、健壮性、可扩展性、可复用性
软件构造关键:
可理解性:
代码的可理解性(变量/子程序/语句的命名与构造标准、代码布局与风格注释、复杂度)构件/项目的可理解性(包的组织、文件的组织、命名空间)
可重用性:
ADT/OOP;
接口与实现分离;继承/重载/重写;组合/代理;多态;子类型与泛型; OO设计模式
维护性和可适应性:
模块化设计;聚合度/耦合度; SOLID; OO设计模式;
健壮性:对异常情况的处理,错误处理,程序保护机制
表现:代码优化,空间/时间复杂性,并行/多线程,分布式系统。