10. 软件架构的演化和维护

1 软件架构演化和定义的关系

1.1 演化的重要性

软件架构的演化就是软件整体结构的演化,演化过程涵盖软件架构的全生命周期,包括软件架构需求的获取、软件架构建模、软件架构文档、软件架构实现以及软件架构维护等阶段。

为什么软件架构演化如此重要?

  1. 软件架构演化正是为了保障这些方面向人们预期的方向发展的重要措施。
  2. 基于软件架构进行的软件检测和修改成本相对较低。
  3. 演化可以更好地保证软件演化的一致性和正确性,而且明显降低软件演化的成本,并且软件架构演化使得软件系统演化更加便捷。

1.2 演化和定义的关系

  • 定义多样性:软件架构的定义多样,不同定义下架构的演化方式和组成规则不同。
  • SA 定义:SA(Software Architecture)定义包括组件、连接器和约束,关注构件和约束的演化。

2 面向对象软件架构演化过程

2.1 对象演化

在面向对象软件架构中,对象演化包括添加对象(AddObject,AO)和删除对象(DeleteObject,DO)两种操作:

  • 添加对象(AO)

    • 在顺序图中添加一个新的对象。
    • 用于实现系统需要的新功能或增加架构灵活性。
  • 删除对象(DO)

    • 删除顺序图中现有的对象。
    • 用于移除不再需要的功能或简化系统。
    • 对于没有交互关系的对象,删除对系统无影响。

对象演化通常伴随消息流的变化,新增消息以完成交互,从而影响架构的正确性或动态属性。

2.2 消息演化

消息演化是顺序图中的核心元素,包含名称、源对象、目标对象、时序等信息。消息演化会影响对象之间的交互行为,从而对架构的正确性或时态属性产生影响。

2.2.1 消息演化的分类

  1. AddMessage (AM)
    • 添加新消息,影响对象之间的交互行为。
  2. DeleteMessage (DM)
    • 删除现有消息,可能影响对象之间的交互行为。
  3. SwapMessageOrder (SMO)
    • 改变消息的发送或接收顺序,不一定会影响对象之间的交互行为。
  4. OverturnMessage (OM)
    • 改变消息的发送或接收对象,影响对象之间的交互行为。
  5. ChangeMessageModule (CMM)
    • 改变消息的发送或接收对象的模块,影响对象之间的交互行为。
  6. 其他消息演化
    • 如 CMM 和 SMO 组合、AM 和 DM 组合等。

2.2.2 消息演化的影响

  • 第 1 类演化(AM 和 DM)直接影响对象之间的交互行为。
  • 第 2 类演化(SMO)不一定会影响对象之间的交互行为,但可能会影响架构设计的正确性或时态属性。
  • 第 3 类演化(OM和CMM)直接影响对象之间的交互行为。

消息演化是顺序图中演化的核心,对象的演化会伴随着消息演化,但二者的演化是相互独立的。在进行架构演化时,需要对相关联的消息演化进行分析。

2.3 复合片段演化

复合片段演化涉及对象交互关系的控制流描述,主要包括四种类型:

  1. AddFragment (AF)
    • 添加新的复合片段,增加控制流。
  2. DeleteFragment (DF)
    • 删除现有复合片段,移除控制流。
  3. FragmentTypeChange (FTC)
    • 改变复合片段的类型,调整控制流。
  4. FragmentConditionChange (FCC)
    • 改变复合片段内部执行条件,影响控制流。

复合片段演化对对象交互流程有直接影响,可能导致架构设计的正确性或时态属性变化。演化时需验证以确保不产生错误。

2.4 约束演化

约束演化涉及架构配置的修改,主要包括:

  1. Add Constraint (AC)
    • 添加新的约束信息,影响架构设计。
    • 直接添加约束,需验证其满足性。
  2. Delete Constraint (DC)
    • 移除现有约束信息,调整架构设计。
    • 直接移除约束,需确保设计仍满足演化后的约束。

约束演化通常不直接存储在定义的层次自动机中,需要通过添加和删除约束信息进行管理。修改约束信息可视为删除旧约束并添加新约束。

3 软件架构演化方式的分类

软件架构演化方式可以根据不同的标准进行分类,主要包括以下几种方法:

  1. 按实现方式和实施粒度分类
    • 基于过程和函数的演化
    • 面向对象的演化
    • 基于组件的演化和基于架构的演化
  2. 按支持演化的准则、可维护性的指示分类
    • 第1类:支持演化的准则、可维护性的指示(如内聚和耦合)、代码重构等
    • 第2类:版本和工程的管理工具,如 CV S和 COCOMO
    • 第3类:架构变换的形式方法,包括系统结构和行为变换的模型,以及架构演化的重现风格等
    • 第4类:架构演化的成本收益分析,决定如何增加系统的弹性
  3. 按演化过程是否处于系统运行时期分类
    • 静态演化 (Static Evolution):发生在软件架构的设计、实现和维护过程中,软件系统未运行或处于运行停止状态
    • 动态演化 (Dynamic Evolution):发生在软件系统运行过程中

3.1 软件架构演化时机

  1. 设计时演化 (Design-Time Evolution)
    • 发生在体系结构模型和与之相关的代码编译之前的软件架构演化。
  2. 运行前演化 (Pre-Execution Evolution)
    • 发生在执行之前、编译之后的软件架构演化。
  3. 有限期运行时演化 (Constrained Runtime Evolution)
    • 系统在设计时就规定了演化的具体条件,将系统置于“安全”模式下,演化只发生在某些特定约束满足时。
  4. 运行时演化 (Runtime Evolution)
    • 系统在运行时不能满足要求时发生的软件架构演化,包括添加组件、删除组件、升级替换组件、改变体系结构的拓扑结构等。

3.2 软件架构静态演化

静态演化需求广泛存在,分为设计时和运行前两个方面:

  1. 设计时演化需求
    • 调整架构以实现与软件过程的一致性。
    • 满足运行环境变化的需求。
  2. 运行前演化需求
    • 修复缺陷和完善系统功能。

静态演化一般过程包括软件理解、需求变更分析、演化计划、系统重构和系统测试五个步骤。

3.2.1 静态演化的原子演化操作

基于UML模型的软件架构,静态演化操作基于原子操作组合而成,主要包括:

  • 模块间依赖关系操作
    • AMD (Add Module Dependency):增加模块间的依赖关系。
    • RMD (Remove Module Dependency):删除模块间的依赖关系。
    • AMI (Add Module Interface):增加模块间的接口。
    • RMI (Remove Module Interface):删除模块间的接口。
    • AM (Add Module):增加一个模块。
    • RM (Remove Module):删除一个模块。
    • SM (Split Module):拆分模块。
    • AGM (Aggregate Modules):聚合模块。
  • 消息相关操作
    • AMS (Add Message):增加消息。
    • RMS (Remove Message):删除消息。
    • AO (Add Object):增加对象。
    • RO (Remove Object):删除对象。
    • AF (Add Fragment):增加消息片段。
    • RF (Remove Fragment):删除消息片段。
    • CF (Change Fragment):改变消息片段。
    • AU (Add Use Case):增加用例。
    • RU (Remove Use Case):删除用例。
    • AA (Add Actor):增加参与者。
    • RA (Remove Actor):删除参与者。
  • 顺序图中的消息交互操作
    • AMS/RMS:修改消息交互。
    • AO/RO:修改对象。
    • AF/RF/CF:修改消息片段。
    • AU/RA:修改参与者。

这些操作影响架构的可维护性和可靠性,需评估其对架构的影响。

3.2.2 静态演化实例:正交软件体系结构

正交软件体系结构通过分层和顺序图分析架构演化,使用正交设计方法处理复杂应用系统,确保架构的可维护性和可靠性。

正交体系的演化过程概括如下:

  1. 需求变动归类,使需求的变化和现有组件及线索相对应,判断重用情况;
  2. 制订架构演化计划;
  3. 修改、增加或删除组件;
  4. 更新组件之间的相互作用;
  5. 产生演化后的软件架构,作为系统更新的详细设计方案和实现基础。

3.3 软件架构动态演化

动态演化是在系统运行期间进行的演化,需要在不停止系统功能的情况下完成。较之静态演化更加困难,具体发生在有限的运行时演化和运行时演化阶段。

3.3.1 动态演化的需求

动态演化主要来自两类需求:

  1. 软件内部执行导致的体系结构改变。
  2. 软件系统外部的需求对软件进行的重配置。

3.3.2 动态演化的类型

软件动态性分为三个级别:

  1. 交互动态性:组件和连接件实例的添加和删除。
  2. 结构动态性:组件结构的修改。
  3. 行为动态性:新的组件类型的定义。

3.3.3 动态软件架构

Perry 在 2000 年提出计算机中动态软件架构(DSA)的概念,强调软件架构在运行时会发生变化的特性。DSA 具有以下特点:

  • 动态性:软件架构的动态性由系统需求、技术、环境、分布等因素的变化导致。
  • 演化:软件架构的演化需要在运行时进行,以适应不断变化的需求。

DSA 演化工具

动态演化的工具需要支持系统在演化过程中对软件架构的一致性检查,并能够对演化过程进行管理。主要有以下几种方法:

  1. 反射机制:通过反射机制,系统可以自我检查和调整。
  2. 基于外部的体系结构演化管理器:如 ArchStudio、Argo 等,提供图形描述和操作手段。
  3. 基于演算:π 演算等,用于描述和分析动态变化的并发系统。
  4. 基于 Java 虚拟机:PKUAS 等,基于 Java 虚拟机的动态体系结构演化。
  5. 基于配置管理:对软件架构的配置信息进行修改,实现动态重配置。

3.3.4 动态软件架构应用实例-PKUAS

PKUAS 是一个符合 Java EE 规范的组件运行支撑平台,支持 3 种标准 EJB 容器。基于 Java 虚拟机, PKUAS 将平台自身的实体划分为 4 种类型。

3.3.5 动态重配置

动态重配置是软件架构动态演化中的重要部分,主要包括:

  1. 简单动作:如任务输入来源的添加和删除。
  2. 任务输入来源的优先级修改。
  3. 组合任务流程中个体修改。
  4. 重新组织任务流程。
  5. 组合任务流程中目标的添加和删除。
  6. 组合任务流程中目标优先级修改。

这些操作需要在不停止系统功能的情况下进行,以确保系统的连续性和稳定性。

3.3.6 动态重配置模式

介绍了四种配置模式:

  1. 主从模式:主组件接收客户端的服务请求,分发工作给从组件。
  2. 中央控制模式:中央控制器控制多个组件。
  3. 客户端/服务器模式:客户端和服务器进行交互。
  4. 分布式控制模式:系统中每个组件都有相同的功能。

这些模式说明了软件模式中组件是如何协作的,以及如何通过执行某个产品线的动态重配置过程从一种配置转化为另一种配置。

3.3.7 PullSE 方法论

PullSE 是一种基于 UML 的软件产品线建立多视图模型的方法,包括部署步骤和技术组件。

4 软件架构演化原则

本节列举了 18 种软件架构可持续演化原则,并针对每个原则设计了相应的度量方案。这些度量方案虽然简单,但能从架构的各个层面提供有价值的信息,帮助对架构进行有效评估。

  1. 演化成本控制原则 ((Evolution Cost Control,ECC)
  • 目的:控制演化成本在预算范围内。
  • 度量方案:CoE < CoRD,其中 CoE 为演化成本,CoRD 为重新开发成本。
  1. 进度可控原则 (Schedule Control)
  • 目的:确保架构演化在预期时间内完成。
  • 度量方案:task=(Task+Task1),时间差 task 越小越好。
  1. 风险可控原则 (Risk Control)
  • 目的:控制演化过程中的各种风险。
  • 度量方案:分别检验经济风险、时间风险、人力风险、技术风险和环境风险。
  1. 主体维持原则 (AIG)
  • 目的:确保架构演化后系统主体行为不变。
  • 度量方案:计算 AIG,AIG=主体规模的变更量/主体规模。
  1. 系统总体结构优化原则 (Optimization of Whole Structure)
  • 目的:优化系统总体结构。
  • 度量方案:检查系统总体结构是否合理,是否最优化。
  1. 平滑演化原则 (Invariant Work Rate,IWR)
  • 目的:确保软件系统的生命周期里演化趋于稳定。
  • 度量方案:计算IWR,IWR=变更量/项目累计。
  1. 目标一致原则 (Objective Conformance)
  • 目的:确保架构演化的阶段性和最终目标一致。
  • 度量方案:task=(Otask-Otask1),Otask 越小越好。
  1. 模块独立演化原则 (LDM)
  • 目的:确保模块自身的演化独立。
  • 度量方案:NRN=|ANR/NR|,NRN 越小越好。
  1. 影响可控原则 (LIM)
  • 目的:通过计算修改的影响范围来评估影响。
  • 度量方案:影响可控原则的度量方案未具体列出。
  1. 复杂性可控原则 (CC)
  • 目的:控制架构演化后的复杂性。
  • 度量方案:CC 两个阈值,方案说明:CC 增长可控。
  1. 有利于重构原则 (RF)
  • 目的:遵循重构原则,使软件更便于重构。
  • 度量方案:检查系统的复杂度指标。
  1. 有利于重用原则 (UR)
  • 目的:提高架构的可重用性。
  • 度量方案:检查模块自身的耦合度、模块之间的耦合度。
  1. 设计原则遵从性原则 (Design Principles Conformance,DPC)
  • 目的:确保架构演化不与设计原则冲突。
  • 度量方案:RCP=|CDP/DP|,RCP 越小越好。
  1. 适应新技术原则 (Technology Independence,TI)
  • 目的:独立于特定技术,适应新技术。
  • 度量方案:TI=1-DDT,其中 DDT=依赖的技术集合/用到的技术集合。
  1. 环境适应性原则 (Platform Adaptability,PA)
  • 目的:适应新的硬件环境与软件环境。
  • 度量方案:结合软件质量中兼容性指标进行度量。
  1. 标准依从性原则 (SCF)
  • 目的:符合相关标准。
  • 度量方案:需人工判定。
  1. 质量向好原则 (Quality Improvement,QI)
  • 目的:提高质量指标或保持质量指标不下降。
  • 度量方案:EQI Q。
  1. 适应新需求原则 (NRQ)
  • 目的:适应新需求,保持架构的适应新需求的能力。
  • 度量方案:RNR=|ANR//NR|,RRN 越小越好。

这些原则和度量方案为软件架构的演化提供了全面的指导和评估方法,确保架构在演化过程中保持高质量和可持续性。

5 软件架构演化评估方法

软件架构演化评估方法用于评估架构在演化过程中的质量和可靠性。评估过程包括对演化过程已知的评估和未知的评估。

5.1 演化过程已知的评估

5.1.1 评估流程

评估的基本思路是将架构度量应用到演化过程中,通过对比演化前后的不同版本的架构进行度量,得到度量结果和变化趋势,并计算架构间质量属性距离,进而对相关质量属性进行评估。

5.1.2 架构演化中间版本度量

度量中间版本的质量属性,其方法和原则包括:

  • 可维护性可靠性:通过计算架构质量属性值(如圈复杂度、扇入扇出度等)来评估。
  • 架构质量属性距离:计算相邻版本架构间质量属性值的差异。
  • 度量结果:综合各版本架构的质量结果,对架构演化相关质量属性进行评估。

5.1.3 架构质量属性距离

  • 可维护性距离计算方法:通过计算演化操作拆分成的原子演化操作序列,评估架构质量属性值的变化。
  • 非相邻版本的架构质量属性距离:通过计算架构质量属性值的差异,分析演化过程中架构质量属性的变化。

5.1.4 架构演化评估

基于度量的架构演化评估方法,通过对比演化前后的软件架构质量,分析架构内部结构的差异以及由此导致的外部质量属性上的变化。

评估过程包括:

  1. 架构修改影响分析:分析架构修改对架构相关质量属性的影响。
  2. 监控演化过程:通过架构演化过程中的中间版本架构进行度量,观察架构相关质量属性随时间推移的变化趋势。
  3. 分析关键演化步骤:分析架构演化过程中质量属性发生较大改变的时刻,找出架构的逻辑依赖关系变化和外部质量属性变化之间的关系。

通过这些评估方法,可以更好地理解和控制软件架构的演化过程,确保架构的质量和可靠性。

5.2 演化过程未知的评估

当演化过程未知时,无法追踪架构在演化过程中的每一步变化,只能根据架构演化前后的度量结果逆向推测出架构发生了哪些改变,并分析这些改变与架构相关质量属性的关联关系。

评估过程

  1. 度量演化前后架构
  • 对演化前后的相邻版本的架构,利用基于度量的架构评估方法分别进行度量,得到架构演化前后的不同版本的度量结果。
  1. 计算质量属性距离
  • 根据度量结果的差异计算它们之间的质量属性距离。
  1. 分析质量属性变化
    • 通过分析架构演化前后质量属性的变化以及质量属性间的距离,可以逆向推测出架构可能发生了哪些演化操作,以及这些演化操作发生的位置和作用的对象。
  2. 推测演化操作
    • 对于每一个演化操作,分别找出其对架构相关质量属性的影响,并分析发生该演化操作的高层驱动原因。
  3. 评估演化驱动因素
    • 最终,找到针对某演化驱动原因的演化操作集合,并分析这些演化操作所产生的架构质量属性变化是否符合预期。

目标:通过这些评估,可以更好地理解和控制软件架构的演化过程,确保架构的质量和可靠性,并为后续的演化提供参考和指导。

6 大型网站系统架构演化实例

大型网站系统架构演化是一个逐步发展的过程,通常从小型网站架构开始,随着用户访问量的增加和业务需求的扩展,逐步演化为更复杂的架构。以下是大型网站系统架构演化的几个主要阶段:

6.1 第一阶段:单体架构

  • 特点:所有资源(应用服务器、数据库、文件服务器)都在一台服务器上。
  • 适用场景:小型网站,访问量较小。

6.2 第二阶段:垂直架构

  • 特点:应用服务器、文件服务器、数据库服务器分离,提升处理能力和存储能力。
  • 适用场景:访问量增加,需要更强的处理能力和存储空间。

6.3 第三阶段:使用缓存改善网站性能

  • 特点:引入缓存机制,减少数据库访问压力,提高访问速度。
  • 适用场景:访问量进一步增加,需要提高响应速度。

6.4 第四阶段:使用服务集群改善网站并发处理能力

  • 特点:增加服务器分担原有服务器的访问及存储压力
  • 适用场景:是解决网站解决高并发、海量数据问题的常用手段

6.5 第五阶段:使用数据库主从分离

  • 特点:数据库读写分离,主数据库处理写操作,从数据库处理读操作。
  • 适用场景:数据库访问压力大,需要提高读写效率。

6.6 第六阶段:使用反向代理和 CDN 加速网站响应

  • 特点:通过反向代理服务器和 CDN 缓存静态内容,加快用户访问速度。
  • 适用场景:用户分布广泛,需要降低延迟。

6.7 第七阶段:使用分布式文件系统和分布式数据库系统

  • 特点:文件系统和数据库系统分布式部署,提高存储和访问能力。
  • 适用场景:数据量巨大,需要更高的存储和访问效率。

6.8 第八阶段:使用NoSQL和搜索引擎

  • 特点:引入 NoSQL 数据库和搜索引擎,处理非关系型数据和复杂查询。
  • 适用场景:数据类型多样,查询需求复杂。

6.9 第九阶段:业务拆分

  • 特点:将网站拆分为多个应用,每个应用独立部署。
  • 适用场景:业务线复杂,需要更高的灵活性和扩展性。

6.10 第十阶段:分布式服务

  • 特点:所有应用和服务分布式部署,提高系统的可扩展性和可靠性。
  • 适用场景:业务规模巨大,需要极高的扩展性和可靠性。

7 软件架构维护

软件架构的维护与演化密不可分,维护需要对软件架构的演化过程进行追踪和控制,以保障软件架构的演化过程能够满足需求。

7.1 软件架构知识管理

软件架构知识管理是对架构设计中所隐含的决策结果进行文档化表示,并在维护过程中帮助维护人员对架构的修改进行完善和参考。

  1. 架构知识的定义
  • 架构知识包括架构设计和架构设计决策。
  1. 架构知识管理的含义
  • 侧重于软件开发和实现过程所涉及的架构静态演化
  • 有助于架构进一步的演化
  1. 架构知识管理的需求
  • 许多架构知识的可获得性能将极大地提升软件开发流程效率。
  1. 架构知识管理的现状
  • 当前尚无关于架构知识管理的完整定义,且架构知识未被整理和存储。

7.2 软件架构修改管理

软件架构修改管理的关键是建立一个隔离区域,保障修改对其他部分影响最小。

7.3 软件架构版本管理

软件架构版本管理为软件架构演化的版本演化控制、使用和评价等提供了可靠的依据,并为架构演化量化度量奠定了基础。

7.4 软件架构可维护性度量实践

本节通过一个 Web 读写系统的实际案例,展示了如何对软件架构的可维护性进行度量和评估。以下是该实践的关键步骤和结果:

7.4.1 组件图解析

从待评估系统的组件图中解析出评估所需的数据,包括组件图的内部组件数目(S)、依赖边数目(E)、依赖入边数目(X)、使用接口数目(R)和提供接口数目(W)。

7.4.2 度量结果

根据解析得到的架构评估数据,分别计算了架构可维护性的 6 个子度量指标的计算公式,得到了各个组件的度量结果。

7.4.3 度量指标分析

  • 圈复杂度 (CCN):表示架构的复杂度,值越大表示越复杂。
  • 扇入扇出度 (FFC):表示组件的独立性,值越大表示独立性越强。
  • 模块间耦合度 (CBO):表示组件间的耦合程度,值越大表示耦合度越高。
  • 模块的响应 (RFC):表示组件的响应能力,值越大表示响应能力越强。
  • 紧内聚度 (TCC):表示组件的内聚程度,值越大表示内聚度越高。
  • 松内聚度 (LCC):表示组件的内聚程度,值越大表示内聚度越低。

7.4.4 度量结果分析

  • 最终结果:综合所有组件结果的平均值,得到整个系统的可维护性度量结果。
  • 图示分析:通过图表展示了各个组件在不同度量指标下的表现,帮助识别系统中的高风险组件。

7.4.5 结论

通过度量和分析,可以识别出系统中需要改进的部分,从而提高系统的可维护性和可扩展性。这种度量方法为软件架构的演化和维护提供了量化的依据。