Architecture 5 - 逐页中文翻译

说明:以下按页翻译 PPT/PDF 中的主要文字内容。对于仅包含图示、流程图或表格的页面,已尽量翻译可识别的标题、标签和核心含义;图中极小文字若无法可靠识别,则以“图示/表格”说明。


第 1 页

设计软件架构

一种实践方法

李杉杉


第 2 页

关于我

李杉杉,准聘助理教授。

页面主要介绍了李杉杉老师的个人简介、研究方向、论文发表、科研项目与联系方式。

  • 个人主页:software.nju.edu.cn/lss
  • 联系邮箱:lss@nju.edu.cn

第 3 页

目录

  • 架构驱动因素与设计策略
  • 属性驱动设计方法(ADD 3.0)
  • 软件架构文档化
  • 案例研究:酒店定价系统
  • 总结

第 4 页

架构驱动因素与设计策略


第 5 页

软件架构

它是什么?

  • 一个系统的软件架构,是指为了理解和推理该系统所需要的一组结构。
  • 这些结构包括软件元素、元素之间的关系,以及元素和关系各自的属性。

——《Software Architecture in Practice》第四版


第 6 页

软件架构生命周期活动

本课程重点关注:

  • 架构设计
  • 架构文档化

图中还展示了架构生命周期中的其他活动:

  • 架构需求
  • 架构评估
  • 架构实现

第 7 页

架构设计活动

架构设计活动的输入包括:

  • 设计目的
  • 主要功能
  • 质量属性
  • 约束
  • 架构关注点

这些统称为架构驱动因素。

架构师基于这些输入,选择并实例化设计概念,形成候选设计决策,最终产生不同类型的架构结构,包括:

  • 模块结构
  • 组件与连接器结构
  • 分配结构

第 8 页

架构驱动因素

对“做什么”和“为什么做”这类问题进行分类

  • 架构驱动因素是需求中会影响架构形态的一部分。
  • 它们包括:
    • 功能需求
    • 质量属性需求
    • 约束
  • 但其他驱动因素还包括:
    • 正在设计的系统类型
    • 设计目标
    • 关注点
  • 这些都是设计过程的输入。

第 9 页

架构驱动因素

功能驱动因素

  • 功能驱动因素通常涉及主要功能,即直接支持业务目标的功能。
  • 示例:网络管理系统的“市场架构图”(Marketecture)。

第 10 页

架构驱动因素

质量属性驱动因素

  • 质量属性是用户和开发者关心的、可度量的系统特征。
  • 例如:
    • 性能
    • 可用性
    • 可修改性
    • 可测试性
    • 等等
  • 质量属性可以使用“场景技术”来描述。
  • 客户会根据质量属性对系统成功的重要程度进行优先级排序(高、中、低)。
  • 架构师会根据技术风险进行优先级排序(高、中、低)。

第 11 页

架构驱动因素

质量属性驱动因素

网络管理系统“Marketecture”的质量属性场景。

页面中的表格示例展示了不同质量属性场景,例如性能、可修改性、可用性、安全性等,并给出了相关用例与优先级。

其中被重点标出的示例是:

  • 质量属性:可用性
  • 场景:系统运行期间网络管理系统发生故障;系统在少于 30 秒内恢复运行。
  • 优先级:高重要性、高技术风险。

第 12 页

架构驱动因素

约束

系统设计也有会塑造架构的“约束”。这类似于建房子时,预算和土地面积会限制设计方案,例如预算紧张时就不可能建别墅。

时间与预算

  • 影响:如果项目期限只有 3 个月,就无法选择需要 6 个月开发的复杂模块。
  • 示例:优先实现最小可行产品(MVP)功能,而不是复杂精细的功能。

技术限制

  • 影响:如果团队缺乏区块链经验,就应避免加入“基于区块链的证明”这类子需求。
  • 风险:技能缺口可能导致实现延期或失败。

业务规则与法规

  • 强制要求:电子商务系统必须遵守 GDPR 数据隐私法规。
  • 行动:在架构设计期间,应在所有与用户数据相关的模块中嵌入“合规检查”。

第 13 页

架构驱动因素

约束

网络管理系统“Marketecture”的约束示例。

表格中包含的约束类型包括:

  • 必须支持一定数量的并发用户。
  • 用户工作站使用特定操作系统,例如 Windows、OSX 和 Linux。
  • 必须使用已有的关系型数据库服务器。
  • 用户工作站与服务器之间的网络连接不可靠。
  • 未来需要支持移动客户端。
  • 必须支持较大规模的服务器数量。
  • 服务器发送数据的频率有限制。
  • 性能数据采集间隔有要求。
  • 事件数据需要保存一定时间。
  • 开发团队熟悉 Java 技术。

第 14 页

架构驱动因素

系统类型

  • 新领域中的绿地系统
    • 例如 Google、Amazon、WhatsApp。
    • 领域认知较少,创新性更强。
  • 成熟领域中的绿地系统
    • 例如“传统”企业应用、标准移动应用。
    • 领域认知较充分,创新性较弱。
  • 棕地系统
    • 对已有系统进行修改。

第 15 页

架构驱动因素

设计目的 / 设计目标

  • 在开始设计之前,必须先明确为什么要进行设计。设计目标会改变你设计的内容和方式。
  • 如果是售前方案,通常需要快速设计初始解决方案,以便进行估算。
  • 如果是一个定制系统,其时间和成本已经确定,并且发布后可能不会有太多演进。
  • 如果是一个持续演进系统的新增量或新版本。

第 16 页

架构驱动因素

架构关注点

  • 架构关注点是架构设计中需要考虑的额外方面,但它们通常不会以传统需求的形式表达出来。
  • 一般关注点:较宽泛的问题,例如整体系统结构、功能如何映射到模块、模块如何映射到团队,以及代码库组织方式。
  • 具体关注点:更细致的系统内部问题,通常来自之前的设计决策,例如日志记录、API 版本管理。
  • 内部需求:虽然不是客户显式提出的需求,但非常重要。它们可能影响组件设计和交互方式,例如数据安全所需的特定加密方案会影响技术选型。
  • 问题:安全风险、性能瓶颈等问题可能要求进行架构变更。

第 17 页

架构驱动因素

示例中的系统类型、设计目标与关注点

系统类型

  • 成熟领域中的绿地系统。

目标

  • 为系统某个增量的构建做设计准备。

关注点

  • 组织系统结构。
  • 组织代码库。
  • 输入校验。
  • 异常管理。
  • 等等。

第 18 页

设计策略

分解

  • 质量属性驱动因素可以被分解,并分配给分解后的元素。
  • 将大型系统目标拆分为可管理的子任务,就像把一幅 1000 块的拼图按“天空”“山脉”“人物”等区域分开解决。
  • 目的:通过为模块或组件分配明确职责,使抽象需求变得可执行。
  • 要牢记已有约束,并组织分解方式,使其能够适应这些约束。
  • 设计活动的目标,是生成一个既能适应约束,又能实现系统质量目标和业务目标的设计。

第 19 页

设计策略

面向 ASR 进行设计

那些非 ASR 需求怎么办?

  • 对 ASR 的选择意味着对需求进行了优先级排序。
  • A)你仍然可以满足其他需求。
  • B)你可以通过对现有设计稍作调整来满足其他需求。
  • C)在当前设计下无法满足其他需求。
    • a)你已经接近满足这些需求。
    • b)重新确定需求优先级,并重新审视设计。
    • c)你无法满足这些需求。

应该一次性为所有 ASR 设计,还是一次处理一个?

  • 答案取决于经验。
  • 通过经验和学习,你会逐渐形成设计直觉,并运用模式和战术来帮助自己同时应对多个 ASR。

ASR 指 Architecturally Significant Requirements,即“架构显著需求”。


第 20 页

设计策略

生成与测试

  • 将某个具体设计视为一个假设:当前设计假设中有问题的部分会在下一个设计假设中被修正,正确的部分则保留下来。

初始假设从哪里来?

  • 已有系统。
  • 框架,即部分设计。
  • 模式和战术。
  • 设计检查表,用于提供指导和信心。

应用哪些测试?

  • 分析技术。
  • 设计检查表。

下一个假设如何产生?

什么时候结束?

  • 当你拥有一个满足 ASR 的设计时,或者用于设计的预算被耗尽时。
  • 实现你得到的最佳设计假设。

第 21 页

设计决策

设计过程的核心

  • 设计过程包含不同类型的设计决策:
    • 选择要分解的元素。
    • 选择一个或多个能够满足本轮迭代输入的设计概念。
    • 实例化架构元素、分配职责并定义接口。
  • 选择设计决策可能尤其具有挑战性。

第 22 页

设计概念

避免重复造轮子

  • 每次迭代中遇到的大多数子问题,都可以使用已有解决方案来解决,也就是设计概念。
  • 架构师是问题解决者,而不是发明家。
  • 避免“重复造轮子”:没有必要重新设计已经被验证过的解决方案,例如用户权限、分布式缓存。
  • 数据表明,使用经过验证的方法通常会带来更好、更快、风险更低的设计。
  • 设计中的创造性体现在:明智选择、聪明组合、灵活演进。
  • 设计概念有多个类别,有些较抽象,有些更具体。这里考虑:
    • 参考架构
    • 部署模式
    • 架构模式 / 设计模式
    • 战术
    • 外部开发组件,例如框架

第 23 页

设计概念

参考架构

  • 参考架构为应用程序的结构设计提供蓝图。
  • 企业应用领域中的示例包括:
    • 移动应用
    • 富客户端应用
    • 富互联网应用
    • 服务应用
    • Web 应用
  • 拓展阅读:《Application Architecture Guide》。
  • 问题:参考架构是否等同于架构风格?

第 24 页

设计概念

部署模式

  • 部署模式从物理角度为如何组织系统结构提供指导。
  • 关于软件系统部署的良好决策,对于实现可用性等质量属性至关重要。
  • 示例:
    • 2 层、3 层、4 层和 n 层部署。
    • 负载均衡集群。
    • 故障转移集群。
    • 私有云 / 公有云。
    • 等等。

第 25 页

设计概念

战术

什么是战术?

  • 战术是能够影响某个质量属性响应控制方式的设计决策。

以下质量属性都有相应的战术分类:

  • 可用性
  • 互操作性
  • 可修改性
  • 性能
  • 安全性
  • 可测试性
  • 易用性

第 26 页

设计概念

模式

  • 模式是针对反复出现的设计问题的、经过验证的概念性解决方案。模式的思想起源于建筑架构。
  • 已经存在大量模式,数量可达数千种,并且它们被记录在多个模式目录中。
  • 很难在“设计模式”和“架构模式”之间划出清晰边界。
  • 图中示例:三模冗余模式。

第 27 页

设计概念

外部开发组件

  • 这些是可复用的代码解决方案。
    • 例如中间件、框架。
  • 框架是一种可复用的软件元素,它提供通用功能,用于解决一系列应用中反复出现的关注点。
  • Java 中的示例:
关注点 框架 使用方式
本地用户界面 Swing 继承
Web UI Java Server Faces(JSF) XML、注解
组件连接 Spring XML、注解
安全性:认证与授权 Spring Security XML、注解
面向对象 - 关系映射 Hibernate XML、注解

第 28 页

选择路线图

绿地系统的设计概念选择路线图

图中展示了绿地系统设计中的迭代路线:

  1. 第一次迭代:建立初始整体系统结构。
    • 参考架构。
    • 部署模式。
    • 可选的外部开发组件。
  2. 第二次迭代:识别支持主要功能的结构。
    • 架构模式。
    • 可选的外部开发组件。
  3. 第三次及后续迭代:细化已有结构以完全处理剩余驱动因素。
    • 战术。
    • 架构模式。
    • 部署模式。
    • 外部开发组件。

第 29 页

属性驱动设计方法(ADD 3.0)


第 30 页

架构设计方法

  • 已经存在若干架构开发方法:
    • 视点与视角。
    • Microsoft 的软件架构过程。
    • ACDM。
    • RUP。
    • ADD。
  • 其中大多数方法覆盖整个架构生命周期,但对于如何执行设计活动本身,只提供了较少细节。

第 31 页

为什么需要设计方法?

通过系统化设计确保驱动因素得到满足

  • 架构设计非常难以掌握。
    • 在做设计决策时,需要考虑许多方面。
    • 它需要大量领域知识和对已有解决方案的了解。
  • 设计可以,而且应该,以系统化方式进行。
    • 确保设计决策是围绕驱动因素做出的。
    • 确保设计决策被记录和论证,并使架构师能够对这些决策负责。
    • 为经验较少的人提供指导。
  • 否则,架构设计可能会被看成是由“大师”完成的神秘活动。

第 32 页

为什么需要设计方法?

通过系统化设计确保驱动因素得到满足

  • 设计方法:
    • 将设计过程与元素、关系、属性结合起来,以构建期望的软件架构。
  • 属性驱动设计方法(ADD 3.0)简介:
    • 通过系统化方法创建高质量、可预测、可复用的软件架构。
  • 课程结束时,学习者应该能够理解:
    • 不同类型的架构驱动因素。
    • 什么是设计概念,以及如何做出与设计概念选择相关的决策。
    • 如何使用 ADD 方法以迭代方式设计软件架构。

第 33 页

ADD 简史

追溯其在架构设计中的发展

ADD 1.0:2000 年 1 月

  • 第一个专门关注质量属性、架构结构和视图的设计方法。
  • 缺乏具体实现指导。

ADD 2.0:2006 年 11 月

  • 通过组合模式和战术,将质量属性与设计选择连接起来。
  • 仍存在一些局限,包括输入、每次设计迭代中的元素分解、驱动因素、设计概念,以及初始文档和分析等方面。

ADD 3.0:2016 年

  • 引入应用框架。
  • 从驱动因素开始,到设计决策,再到可用的实现选项。
  • 支持快速设计迭代,每次迭代只处理少量设计决策。
  • 促进参考架构的复用,并推动采用“设计概念目录”。

第 34 页

属性驱动设计 3.0(ADD 3.0)

现代、迭代、经受时间检验

  • 迭代式设计方法:ADD 支持在项目增量(例如 sprint)中进行多轮迭代,通过微迭代实现结构化设计。
  • 稳定且经过工业实践验证:尽管开发实践不断变化,ADD 3.0 仍保持不变,这证明了它的一般适用性。
  • 适应性与一致性:ADD 3.0 可以应用于 DevOps、云原生架构等现代技术,而无需改变方法的核心步骤。

第 35 页

属性驱动设计 3.0(ADD 3.0)

图中展示 ADD 3.0 的总体流程:

输入驱动因素包括:

  • 设计目的
  • 主要功能
  • 质量属性
  • 架构关注点
  • 约束

主要步骤包括:

  1. 审查输入。
  2. 通过选择驱动因素确定迭代目标。
  3. 选择一个或多个系统元素进行细化。
  4. 选择一个或多个能够满足已选驱动因素的设计概念。
  5. 实例化架构元素、分配职责并定义接口。
  6. 草拟视图并记录设计决策。
  7. 分析当前设计,并审查迭代目标和设计目的的达成情况。

输出是经过细化的软件架构设计。


第 36 页

属性驱动设计 3.0(ADD 3.0)

步骤 1:审查输入

在开始一轮设计之前,你需要确保设计过程的输入是可用且正确的。

输入包括:

  • 设计目的
  • 主要功能
  • 质量属性场景
  • 架构约束
  • 关注点
  • 已有架构设计

第 37 页

属性驱动设计 3.0(ADD 3.0)

步骤 1:审查输入

  • 主要功能和质量属性场景需要已经被排序,理想情况下由项目中最重要的干系人完成排序。
  • 如果还没有排序,可以使用各种技术来引出并确定优先级,例如质量属性工作坊和效用树。
  • 要确保驱动因素及其优先级正确,避免“垃圾进,垃圾出”。
  • 检查在原始需求引出过程中是否遗漏了重要干系人。
  • 检查自从优先级排序完成之后,业务条件是否发生了变化。
  • 开始设计。
  • 执行不同的设计迭代,处理:
    • 其他质量属性场景。
    • 用例。
    • 架构关注点。
    • 等等。

第 38 页

属性驱动设计 3.0(ADD 3.0)

步骤 1:审查输入

本页为步骤 1 的图示说明。


第 39 页

属性驱动设计 3.0(ADD 3.0)

步骤 2:通过选择驱动因素确定迭代目标

设计问题会被划分为若干子问题。

一次迭代从决定要解决哪个子问题开始。


第 40 页

属性驱动设计 3.0(ADD 3.0)

步骤 2:通过选择驱动因素确定迭代目标

  • 一轮设计通常由一系列设计迭代组成,每次迭代都聚焦于实现某个特定目标。
  • 这样的目标通常涉及通过设计来满足一部分驱动因素。
  • 例如:
    • 从元素创建结构,以支持某个特定性能场景。
    • 使某个用例能够被实现。
  • 建立一个“大小合适”的迭代目标:
    • 目标可以是处理一个重要驱动因素。
    • 目标可以是处理“分解系统”这个架构关注点。
    • 目标可以是处理一个具有挑战性的质量属性场景。
    • 目标也可以是做出一组决策以满足一组相似驱动因素。
    • 例如一组用例或相关质量属性场景。
    • 目标还可以是做出一组决策以满足一组相关驱动因素。
    • 例如一个用户故事及其相关质量属性场景。

第 41 页

属性驱动设计 3.0(ADD 3.0)

步骤 2:通过选择驱动因素确定迭代目标

ADD:第 1 次迭代

迭代目标与输入

  • 迭代目标:
    • 创建整体系统结构。
  • 需要考虑的输入:
    • 全部输入。

第 42 页

属性驱动设计 3.0(ADD 3.0)

步骤 3:选择一个或多个系统元素进行细化

为了解决子问题,需要做出三类决策之一:

  • 选择需要被分解的部分。

第 43 页

属性驱动设计 3.0(ADD 3.0)

步骤 3:选择一个或多个系统元素进行细化

  • 细化可以表示:
    • 将元素分解为更细粒度的元素,即自顶向下方法。
    • 将元素组合为更粗粒度的元素,即自底向上方法。
    • 改进之前已经识别出的元素。
  • 对于绿地开发,可以从以下步骤开始:
    • 建立系统上下文。
    • 选择唯一可用的元素,即系统本身,并通过分解对其进行细化。
  • 对于已有系统,或者绿地系统后续设计迭代:
    • 细化之前迭代中已经识别出的元素。
    • 需要充分理解系统中的元素。
  • 步骤 2 通常先于步骤 3。在某些情况下,这两个步骤的顺序可以颠倒。

第 44 页

属性驱动设计 3.0(ADD 3.0)

步骤 3:选择一个或多个系统元素进行细化

由于案例示例是一个绿地系统,因此唯一需要分解的元素就是系统本身。


第 45 页

属性驱动设计 3.0(ADD 3.0)

步骤 4:选择一个或多个满足已选驱动因素的设计概念

为了解决子问题,需要做出三类决策之一:

  • 识别并选择能够支持分解的已有解决方案。

第 46 页

属性驱动设计 3.0(ADD 3.0)

步骤 4.1:识别设计概念

参考架构备选方案

  • 移动应用。
  • 富客户端应用。
  • 富互联网应用。
  • 服务应用。
  • Web 应用。

分布式部署模式备选方案

  • 2 层。
  • 3 层。
  • 4 层。

第 47 页

属性驱动设计 3.0(ADD 3.0)

步骤 4.2:选择设计概念

本页引入“设计概念选择”这个子步骤。


第 48 页

属性驱动设计 3.0(ADD 3.0)

步骤 4.2:选择设计概念

基本选择方法

  • 创建优缺点表,列出每个备选设计概念的优势和劣势,以支持基于驱动因素进行选择。
  • 页面展示了一个用于支持备选方案选择的表示例。

第 49 页

属性驱动设计 3.0(ADD 3.0)

步骤 4.2:选择设计概念

深入分析方法

  • CBAM:一种定量方法,使用效用-响应曲线、成本收益分析和投资回报率(ROI)来选择架构策略。
  • SWOT:评估备选方案的优势、劣势、机会和威胁。

图示:效用-响应曲线。


第 50 页

属性驱动设计 3.0(ADD 3.0)

步骤 4.2:选择设计概念

基于原型的选择

  • 当分析无法给出结论时,可以创建一次性原型。
  • 与分析相比,创建原型的成本可能较高,成本比例大约在 10:1 到 5:1 之间。
  • 某些场景会强烈促使你创建原型,例如项目涉及公司中的新兴技术或新技术,或者存在技术集成不确定性。
  • 决定是否创建原型时,应该考虑若干方面。

第 51 页

属性驱动设计 3.0(ADD 3.0)

步骤 4.2:选择设计概念

  • 选择了两个参考架构。
  • 分布式部署模式备选方案:
    • 3 层架构。

第 52 页

属性驱动设计 3.0(ADD 3.0)

步骤 5:实例化架构元素、分配职责并定义接口

为了解决子问题,需要做出三类决策之一:

  • 基于已有解决方案创建元素,并建立这些元素的职责和接口。

第 53 页

属性驱动设计 3.0(ADD 3.0)

步骤 5:实例化架构元素、分配职责并定义接口

本页展示步骤 5 的图示或示例。


第 54 页

属性驱动设计 3.0(ADD 3.0)

步骤 6:草拟视图并记录设计决策

“蓝图”会被进一步细化。

这一步可以与步骤 5 并行完成。

注意:这不是完整正式的文档,而是草图。


第 55 页

属性驱动设计 3.0(ADD 3.0)

步骤 6:草拟视图并记录设计决策

  • 当你实例化设计概念时,通常会创建草图。
  • 这些草图是架构的初始文档。
  • 应该捕获这些草图,并在之后进一步补充完善。
  • 如果使用非正式记法,要保持一致。
  • 要养成记录以下内容的习惯:
    • 分配给元素的职责。
    • 已做出的相关设计决策。
  • 在设计过程中进行记录,可以避免以后不得不依赖记忆。

第 56 页

属性驱动设计 3.0(ADD 3.0)

步骤 7:分析当前设计,并审查迭代目标和设计目的的达成情况

在这一点上,需要分析已经做出的决策以及整体设计过程中的进展,从而决定是否还需要更多迭代。


第 57 页

属性驱动设计 3.0(ADD 3.0)

步骤 7:分析当前设计,并审查迭代目标和设计目的的达成情况

  • 设计看板。

第 58 页

属性驱动设计 3.0(ADD 3.0)

步骤 2:通过选择驱动因素确定迭代目标

ADD:第 2 次迭代

  • 迭代目标:
    • 识别支持主要功能的元素。
  • 输入:
    • 主要用例。

第 59 页

属性驱动设计 3.0(ADD 3.0)

步骤 3:选择一个或多个系统元素进行细化

由于功能通常由分布在系统各层中的元素共同支持,因此这里的元素就是上一次迭代中识别出的不同层。


第 60 页

属性驱动设计 3.0(ADD 3.0)

步骤 4:选择一个或多个满足已选驱动因素的设计概念

为了解决子问题,需要做出三类决策之一:

  • 识别并选择能够支持分解的已有解决方案。

第 61 页

属性驱动设计 3.0(ADD 3.0)

步骤 4:选择设计概念

设计概念

  • 领域对象。
  • 外部开发组件。

第 62 页

属性驱动设计 3.0(ADD 3.0)

步骤 5:实例化架构元素、分配职责并定义接口

  • 逻辑视图。

第 63 页

属性驱动设计 3.0(ADD 3.0)

步骤 5:实例化架构元素、分配职责并定义接口

  • 一旦元素被识别出来,就可以通过动态分析来定义接口。
  • 示例:UC-1。

第 64 页

属性驱动设计 3.0(ADD 3.0)

步骤 7:分析当前设计,并审查迭代目标和设计目的的达成情况

  • 设计看板。

第 65 页

属性驱动设计 3.0(ADD 3.0)

步骤 2:通过选择驱动因素确定迭代目标

ADD:第 3 次迭代

  • 迭代目标:
    • 处理质量属性 QA-3:
    • 网络管理系统在运行期间发生故障。
    • 系统在少于 30 秒内恢复运行。

第 66 页

属性驱动设计 3.0(ADD 3.0)

步骤 3:选择一个或多个系统元素进行细化

由于该场景涉及整个系统的故障,因此所选择的元素是第一次迭代中识别出的各个层。


第 67 页

属性驱动设计 3.0(ADD 3.0)

步骤 4:选择设计概念

  • 推荐先从战术开始,然后再进入模式或技术选择。

第 68 页

属性驱动设计 3.0(ADD 3.0)

步骤 5:实例化架构元素、分配职责并定义接口

本页展示步骤 5 在第 3 次迭代中的示例或图示。


第 69 页

属性驱动设计 3.0(ADD 3.0)

步骤 7:分析当前设计,并审查迭代目标和设计目的的达成情况

  • 设计看板。

第 70 页

属性驱动设计 3.0(ADD 3.0)

设计过程终止标准

  • 设计过程会跨越多次迭代持续进行,直到:
    • 已经为所有驱动性的架构需求做出设计决策,即达到设计目标;或者
    • 最重要的技术风险已经得到缓解;或者
    • 分配给架构设计的时间被耗尽,但这种情况并不理想。

第 71 页

属性驱动设计 3.0(ADD 3.0)

必要时进行迭代

设计会被逐步产生。

注意:这可能只是一个局部架构设计,并不是“大前期设计”(BDUF)。


第 72 页

将 ADD 应用于不同系统语境

根据系统类型裁剪设计方法

软件系统设计可以分为三类:

  1. 成熟领域中的绿地系统设计,即领域充分了解。
  2. 新颖领域中的绿地系统设计,即该领域的基础设施和知识基础尚不成熟。
  3. 为已有系统进行变更的设计,即棕地系统设计。

第 73 页

将 ADD 应用于不同系统语境

在成熟领域中设计绿地系统

成熟领域中的绿地系统

  • 用于从零开始设计系统,适用于桌面应用、移动应用、Web 企业应用和微服务等成熟领域。

初始迭代目标

  • 建立整体系统结构。
  • 选择参考架构、模式和框架。
  • 优先考虑非功能约束和质量属性。

下一次迭代目标

  • 识别支持主要功能的结构。
  • 将用例分配给元素。
  • 分解参考架构中的元素。
  • 规划团队分工。

后续迭代

  • 针对剩余驱动因素细化结构。
  • 使用战术、模式、组件和最佳实践,例如模块化、低耦合。

路线图收益

  • 指导初始设计,并帮助早期估算。
  • 使用已知组件遵循明确路线图,可以降低风险,并从一开始就支持质量目标。

第 74 页

将 ADD 应用于不同系统语境

在新颖领域中设计绿地系统

在没有参考架构的情况下开始

没有现有模型或可复用组件,设计需要从第一原则开始。

使用原型和一般设计概念

通过模式、战术以及关注质量属性的原型来指导设计。

应对新兴挑战

关注性能、可伸缩性和安全性。新颖领域需要灵活的迭代目标。


第 75 页

将 ADD 应用于不同系统语境

为已有系统设计,即棕地系统

多种重新设计目标

棕地架构设计通常由维护、重构或解决质量问题驱动。

首先理解已有架构

在进行分解或迭代规划之前,关键是识别系统元素及其交互。

评估后的设计迭代

一旦理解了架构,ADD 步骤就类似于绿地系统设计,只是会以增量方式针对新的驱动因素进行设计。


第 76 页

将 ADD 应用于不同系统语境

设计以替换遗留应用

遗留技术与技术债

旧系统可能依赖过时技术,或者积累了难以管理的技术债。

使用绞杀者榕树模式

引入代理,将调用路由到遗留系统,同时逐步替换组件。

迭代式替换

每次 ADD 迭代中的设计目标,针对特定服务或组件进行迁移。


第 77 页

软件架构文档化


第 78 页

架构文档化

即使是最好的架构,如果需要使用它的人:

  • 不知道它是什么;
  • 无法充分理解它,以便使用、构建或修改它;
  • 误解它并错误应用它;

那么它也是无用的。

架构团队投入的所有努力、分析、艰苦工作和富有洞察力的设计,都将被浪费。


第 79 页

用途与受众

架构文档必须:

  • 足够透明且易获取,使新员工能够快速理解。
  • 足够具体,能够作为构建系统的蓝图。
  • 包含足够信息,能够作为分析基础。

架构文档既是规定性的,也是描述性的。

  • 对某些受众而言,它规定了应该为真的内容,对尚未做出的决策施加约束。
  • 对另一些受众而言,它描述了已经为真的内容,回顾关于系统设计已经做出的决策。

理解干系人如何使用架构文档至关重要。

  • 这些用途决定了应该捕获哪些信息。

第 80 页

架构文档的三种用途

教育

  • 向人们介绍系统。
  • 新团队成员。
  • 外部分析者或评估者。
  • 新架构师。

干系人之间沟通的主要载体

  • 尤其是架构师与开发者之间。
  • 尤其是架构师与未来架构师之间。

系统分析与构建的基础

  • 架构告诉实现者应该实现什么。
  • 每个模块都有必须提供的接口,也会使用其他模块的接口。
  • 文档可以作为登记和沟通未解决问题的容器。
  • 架构文档是架构评估的基础。

第 81 页

记法

非正式记法

  • 使用通用绘图和编辑工具来描绘视图,通常是图形化的。
  • 描述的语义由自然语言说明。
  • 不能进行形式化分析。

半形式化记法

  • 标准化记法,规定图形元素和构造规则。
  • 但缺乏对这些元素含义的完整语义处理。
  • 可以应用初步分析。
  • 在这个意义上,UML 属于半形式化记法。

形式化记法

  • 使用具有精确语义的记法描述视图,通常具有数学基础。
  • 可以对语法和语义进行形式化分析。
  • 架构描述语言(ADL)属于这一类。
  • 通过相关工具支持自动化。

第 82 页

选择记法

权衡

  • 通常,越形式化的记法创建和理解所需时间与成本越高,但歧义更少,并且提供更多分析机会。
  • 相反,非正式记法更容易创建,但提供的保证更少。
  • 不同记法对于表达不同类型的信息有优劣之分。
  • UML 类图无法帮助你推理可调度性;序列图也不能告诉你系统按时交付的可能性。
  • 选择记法和表示语言时,应清楚自己需要捕获和推理的重要问题。

第 83 页

视图

  • 视图使我们能够将软件架构划分为若干有意义且可管理的系统表示。
  • 架构文档化原则:
    • 文档化一个架构,就是文档化相关视图,然后添加适用于多个视图的文档内容。

第 84 页

哪些视图?选择你需要的视图!

  • 不同视图支持不同目标和用途。
  • 本课程不主张某一种固定视图或固定视图集合。
  • 你应该文档化哪些视图,取决于你预计如何使用这些文档。
  • 每个视图都有成本和收益;你应该确保维护一个视图的收益大于其成本。

第 85 页

模块视图概述

元素

  • 模块:软件的实现单元,提供一组内聚的职责。

关系

  • “是……的一部分”:定义子模块与聚合模块之间的部分/整体关系。
  • “依赖于”:定义两个模块之间的依赖关系。具体模块视图会进一步说明这种依赖的含义。
  • “是一种”:定义更具体模块与更一般模块之间的泛化/特化关系。

第 86 页

模块视图概述

约束

  • 不同模块视图可能施加特定拓扑约束,例如限制模块之间的可见性。

用途

  • 作为代码构建的蓝图。
  • 进行变更影响分析。
  • 规划增量开发。
  • 进行需求可追踪性分析。
  • 沟通系统功能和代码库结构。
  • 支持工作分配、实现计划和预算信息的定义。
  • 展示系统需要管理的信息结构。

第 87 页

模块视图

如果一个软件架构文档没有至少一个模块视图,那么它几乎不可能是完整的。


第 88 页

组件与连接器视图概述

元素

  • 组件:主要处理单元和数据存储。组件通过一组端口与其他组件进行交互,这种交互通过连接器实现。
  • 连接器:组件之间的交互通道。连接器具有一组角色或接口,用于表明组件如何在交互中使用该连接器。

关系

  • 附着关系:组件端口与连接器角色关联起来,形成由组件和连接器组成的图。
  • 接口委托:在某些情况下,组件端口会与内部子架构中的一个或多个端口相关联。连接器角色也存在类似情况。

第 89 页

组件与连接器视图概述

约束

  • 组件只能附着到连接器,不能直接附着到其他组件。
  • 连接器只能附着到组件,不能直接附着到其他连接器。
  • 附着关系只能建立在兼容端口和角色之间。
  • 接口委托只能定义在两个兼容端口之间,或两个兼容角色之间。
  • 连接器不能孤立存在;连接器必须附着到组件。

用途

  • 展示系统如何工作。
  • 通过指定运行时元素的结构与行为来指导开发。
  • 帮助推理运行时系统质量属性,例如性能和可用性。

第 90 页

C&C 视图的记法

  • UML 组件很适合表示 C&C 组件。

C&C 指 Component-and-Connector,即组件与连接器。


第 91 页

C&C 视图的记法

  • UML 连接器不足以表示许多 C&C 连接器。
  • UML 连接器不能具有子结构、属性或行为描述。
  • 可以使用 UML 连接器,即一条线,表示“简单”的 C&C 连接器。
  • 许多常用的 C&C 连接器具有众所周知、与具体应用无关的语义和实现,例如函数调用或数据读取操作。
  • 可以使用构造型来表示连接器类型。
  • 连接器角色不能用 UML 连接器显式表示。
  • UML 连接器元素不允许包含接口。
  • 可以给连接器两端加标签,并使用这些标签来标识必须在其他地方记录的角色描述。
  • 可以使用 UML 组件表示“丰富”的 C&C 连接器,或者通过在线状 UML 连接器上添加标签来说明复杂连接器的含义。

第 92 页

分配视图概述

元素

  • 软件元素和环境元素。
  • 软件元素具有对环境提出的属性要求。
  • 环境元素具有向软件提供的属性。

关系

  • 分配到:软件元素被映射或分配到环境元素。属性依赖于具体视图。

第 93 页

分配视图概述

约束

  • 随视图不同而变化。

用途

  • 推理性能、可用性、安全性和安全保障。
  • 推理分布式开发以及团队工作分配。
  • 推理对软件版本的并发访问。
  • 推理系统安装的形式与机制。

第 94 页

质量视图

  • 质量视图可以针对特定干系人或特定关注点进行裁剪。
  • 质量视图通过从结构视图中提取相关部分,并将这些部分组合在一起而形成。

第 95 页

质量视图:示例

安全视图

  • 展示具有安全角色或安全职责的组件、这些组件如何通信、安全信息的数据仓库,以及与安全相关的数据仓库。
  • 该视图的上下文信息会展示系统环境中的其他安全措施,例如物理安全。
  • 安全视图的行为部分:
    • 展示安全协议如何运行,以及人在何处、如何与安全元素交互。
    • 捕获系统如何响应特定威胁和漏洞。

通信视图

  • 对于全球分布且异构的系统尤其有帮助。
  • 展示所有组件到组件之间的通道、各种网络通道、服务质量参数值以及并发区域。
  • 用于分析某些性能和可靠性问题,例如死锁或竞态条件检测。
  • 该视图的行为部分可以展示网络带宽如何被动态分配。

第 96 页

质量视图:示例

异常或错误处理视图

  • 可以帮助说明并突出错误报告与解决机制。
  • 展示组件如何检测、报告和解决故障或错误。
  • 帮助识别错误来源以及针对每类错误的适当纠正措施。

可靠性视图

  • 对复制和切换等机制建模。
  • 描绘时序问题和事务完整性。

性能视图

  • 展示有助于推断系统性能的架构方面。
  • 展示网络流量模型、操作最大延迟等内容。

第 97 页

选择视图

如果你知道以下信息,就可以确定需要哪些视图、什么时候创建它们,以及包含多少细节:

  • 有哪些人可用,以及他们具备什么技能。
  • 必须遵守哪些标准。
  • 手头有多少预算。
  • 进度安排如何。
  • 重要干系人的信息需求是什么。
  • 驱动性的质量属性需求是什么。
  • 系统的大致规模是多少。

最低限度上,架构文档中至少应包含:

  • 至少一个模块视图。
  • 至少一个 C&C 视图。
  • 对于较大系统,至少一个分配视图。

第 98 页

选择视图的方法

步骤 1:构建干系人 / 视图表

  • 行:列出项目软件架构文档的干系人。
  • 列:枚举适用于系统的视图。
  • 以 ADD 设计工作所建议的结构和视图作为候选列表的起点。
  • 包括目前设计工作已经产生的视图或视图草图。
  • 某些视图适用于每个系统,例如分解视图、使用视图和工作分配视图;而另一些视图只适用于某些系统,例如各种 C&C 视图、分层视图。
  • 填写每个单元格,以描述该干系人需要从该视图中获得多少信息:无、只需概览、中等细节、高细节。

第 99 页

选择视图的方法

步骤 2:合并视图以减少视图数量

  • 在表中寻找边缘视图,也就是只需要概览,或者服务很少干系人的视图。
  • 将每个边缘视图与另一个拥有更强受众基础的视图合并。
  • 以下视图通常可以自然合并:
    • 各种 C&C 视图。因为 C&C 视图都展示各种类型组件和连接器之间的运行时关系,因此往往容易合并。
    • 部署视图与 SOA 视图或通信进程视图。SOA 视图展示服务,通信进程视图展示进程;在两种情况下,这些都是部署到处理器上的组件。
    • 分解视图与工作分配视图、实现视图、使用视图或分层视图。被分解的模块构成工作、开发和使用的单位。此外,这些模块也会填充分层结构。

第 100 页

选择视图的方法

步骤 3:确定优先级并分阶段完成

  • 分解视图,即模块视图之一,是特别适合早期发布的视图。
  • 高层分解通常较容易设计。
  • 项目经理可以开始组建开发团队、安排培训、决定哪些部分外包,并开始制定预算和进度。
  • 不需要最大程度地满足所有干系人的全部信息需求。
  • 提供 80% 的信息通常已经很有帮助,也可能足以让干系人完成工作。
  • 如果部分信息已经足够,应与干系人确认。
  • 不需要完成一个视图之后才开始另一个视图。
  • 人们可以基于概览级信息继续推进工作。
  • 广度优先的方法通常最好。

第 101 页

构建文档包

文档包由以下部分组成:

  • 视图。
  • 视图之外的文档信息。

第 102 页

文档化一个视图

第 1 节:主要呈现

  • 主要呈现展示该视图中的元素和关系。
  • 主要呈现应该使用该视图的词汇,包含你希望传达的系统信息。
  • 主要呈现通常是图形化的。
  • 它可能是使用简单绘图工具、以非正式记法绘制的图;也可能是从设计或建模工具导入的半形式化或形式化记法图。
  • 如果主要呈现是图形化的,一定要包含解释记法的图例。
  • 缺少图例是实践中文档化最常见的错误。
  • 有时主要呈现也可以是文本形式,例如表格或列表。
  • 如果文本按照某些风格规则呈现,这些规则也应该被说明,或通过引用纳入,就像图形记法中的图例一样。

第 103 页

文档化一个视图

第 2 节:元素目录

  • 元素目录至少要详细说明主要呈现中描绘的那些元素。
  • 例如,如果图中显示元素 A、B、C,那么元素目录需要解释 A、B、C 分别是什么。
  • 如果与该视图相关的元素或关系在主要呈现中被省略,则应在目录中引入并解释。
  • 目录的组成部分包括:
    • 元素及其属性:本节命名视图中的每个元素,并列出该元素的属性。
    • 关系及其属性:每个视图都有特定关系类型,用来描绘视图中元素之间的关系。
    • 元素接口:本节记录元素接口。
    • 元素行为:本节记录主要呈现中不明显的元素行为。

第 104 页

文档化一个视图

第 3 节:上下文图

  • 上下文图展示该视图中描绘的系统或系统部分如何与其环境相关联。
  • 上下文图的目的是描绘视图的范围。
  • 环境中的实体可以是人、其他计算机系统,或物理对象,例如传感器或受控设备。

第 4 节:可变性指南

  • 可变性指南展示如何使用该视图所示架构中的任何变化点。

第 5 节:理由说明

  • 理由说明解释视图中反映的设计为什么会这样形成。
  • 本节目标是解释设计为什么如此,并提供有说服力的论证,说明该设计是合理的。
  • 在本视图中选择某种模式时,应在这里进行论证:说明所选模式解决了什么架构问题,以及为什么选择它而不是其他模式。

第 105 页

视图模板

本页展示视图文档模板。


第 106 页

记录视图之外的信息

文档控制信息

  • 列出发布组织、当前版本号、发布日期和状态、变更历史,以及提交文档变更请求的流程。
  • 这些信息通常记录在文档前置部分。

第 107 页

记录视图之外的信息

第 1 节:文档路线图

文档地图告诉读者文档中包含哪些信息,以及在哪里可以找到这些信息。

范围与摘要

  • 说明文档目的,并简要概括覆盖内容。

文档组织方式

  • 对文档中的每一节,简短说明其中可找到的信息。

视图概览

描述架构师在文档包中包含的视图。对于每个视图,说明:

  • 视图名称,以及它实例化了什么模式,如果有的话。
  • 视图的元素类型、关系类型和属性类型。
  • 构建该视图所使用的语言、建模技术或分析方法。

干系人如何使用文档

  • 本节展示各种干系人如何使用文档来处理其关注点。
  • 可包含简短场景,例如:“维护人员希望知道某项拟议修改可能改变哪些软件单元。”
  • 为了符合 ISO/IEC 42010-2007,必须至少考虑用户、采购方、开发者和维护者的关注点。

第 108 页

记录视图之外的信息

第 2 节:如何记录一个视图

  • 解释你用于记录视图的标准组织方式,可以采用本部分描述的方式,也可以使用自己的方式。

第 3 节:系统概览

  • 用简短文字描述系统功能、用户,以及任何重要背景或约束。
  • 为读者提供对系统及其目的的一致心理模型。
  • 这也可以指向项目的系统运行概念文档。

第 109 页

记录视图之外的信息

第 4 节:视图之间的映射

  • 帮助读者理解视图之间的关联,可以让读者深入理解架构如何作为统一概念整体运行。
  • 架构中不同视图元素之间的关联通常是多对多的。
  • 视图到视图之间的关联可以用表格捕获。
  • 表格应命名两个视图中元素之间的对应关系。
  • 示例:
    • 从组件与连接器视图映射到模块视图时,可使用“由……实现”。
    • 从模块视图映射到组件与连接器视图时,可使用“实现”。
    • 从分解视图映射到分层视图时,可使用“包含于”。

第 110 页

记录视图之外的信息

第 5 节:理由说明

  • 记录适用于多个视图的架构决策。
  • 记录导致系统级重要决策的背景约束、组织约束或重大需求。
  • 记录采用哪些基础架构模式的决策。

第 6 节:目录

  • 一组参考材料,用于帮助读者快速找到更多信息。
  • 术语索引。
  • 词汇表。
  • 缩写列表。

第 111 页

文档化行为

  • 行为文档通过描述该视图中架构元素如何相互交互,来补充每个视图。
  • 行为文档使我们能够推理:
    • 系统发生死锁的可能性。
    • 系统在期望时间内完成任务的能力。
    • 最大内存消耗。
    • 等等。
  • 在我们的视图模板中,行为有自己的位置,即元素目录中的一个部分。

第 112 页

文档化行为的记法

面向轨迹的语言

  • 轨迹是活动或交互的序列,用于描述系统在特定状态下对特定刺激的响应。
  • 一条轨迹描述系统结构元素之间某个特定的活动或交互序列。
  • 示例:
    • 用例。
    • 序列图。
    • 通信图。
    • 活动图。
    • 消息序列图。
    • 时序图。
    • 业务流程执行语言。

第 113 页

用例图

本页展示用例图示例。


第 114 页

用例描述

本页展示用例描述示例。


第 115 页

序列图

本页展示序列图示例。


第 116 页

通信图

本页展示通信图示例。


第 117 页

活动图

本页展示活动图示例。


第 118 页

文档化行为的记法

综合性语言

  • 综合性模型展示结构元素的完整行为。
  • 给定这种类型的文档,可以推断从初始状态到最终状态的所有可能路径。
  • 状态机形式化方法表示架构元素的行为,因为每个状态都是可能导致该状态的所有历史的抽象。
  • 状态机语言允许你用交互约束和对内部及环境刺激的定时响应,来补充系统元素的结构描述。

第 119 页

状态机

本页展示状态机示例。


第 120 页

状态机

本页展示另一个状态机示例。


第 121 页

文档化变化速度快于文档速度的架构

  • 如果架构会在运行时变化,或者由于高频发布与部署周期而变化,那么架构变化速度可能远快于文档周期。
  • 没有人会等待新的架构文档被编写、评审和发布之后再行动。
  • 在这种情况下:
    • 记录系统所有版本都成立的内容。像记录任何架构一样记录这些不变量。这可能使你的架构文档更像是对约束或准则的描述,任何合规版本都必须遵守这些约束或准则。
    • 记录架构允许如何变化。这通常意味着增加新组件,以及用新实现替换组件。记录这些内容的位置称为可变性指南。

第 122 页

在敏捷开发项目中记录架构

  • 采用模板或标准组织方式来捕获设计决策。
  • 当且仅当某个视图有明确且强烈的干系人群体时,才计划记录该视图。
  • 当某个视图模板或视图之外信息模板中的信息可用时,可以按任意顺序填写相应部分。但只有当写下这些信息能让下游人员工作更容易、更便宜或更可能成功时,才需要这样做。
  • 不必先创建架构设计文档,再创建更细粒度的设计文档。只需要产生足够的设计信息,使你能够继续进入编码阶段。
  • 不必觉得必须填写模板中的所有部分,更不必一次性全部填写。对于不需要记录的信息,可以写“N/A”,例如因为你会口头传达这些信息。
  • 敏捷团队有时会在白板前进行简短讨论并形成模型。拍下照片,把它作为主要呈现即可。

第 123 页

总结


第 124 页

属性驱动设计 3.0(ADD 3.0)

本页回顾 ADD 3.0。


第 125 页

选择路线图

绿地系统的设计概念选择路线图

本页回顾绿地系统的设计概念选择路线图。


第 126 页

总结

  • 架构设计将驱动因素转化为结构。
  • 架构驱动因素包括功能需求、质量属性和约束,也包括目标、关注点和系统类型。
  • ADD 是一种将架构设计结构化的方法,使架构设计能够系统化地进行。
  • 设计概念是创建设计的构建块。重要类型包括:
    • 参考架构。
    • 部署模式。
    • 架构模式。
    • 战术。
    • 外部开发组件,例如框架。
  • ADD 可以以敏捷方式执行:使用初始文档(草图)和设计看板来追踪设计进展。

第 127 页

总结

  • 你应该理解文档写作的用途以及文档面向的受众。
  • 架构文档是各种干系人之间沟通的手段,不仅用于向管理链条上传达信息、向开发者下达信息,也用于与同级人员沟通。
  • 架构是一个复杂制品,最好通过聚焦视图来表达。
  • 必须选择要记录的视图,选择用于记录这些视图的记法,并选择一组既最小又足够的视图。
  • 不仅要记录架构结构,还必须记录行为。

第 128 页

讨论问题

  1. 在 ADD 的步骤 2 中,如果为迭代选择的目标范围过大,可能会发生什么?
  2. 在成熟领域的绿地系统设计中,第 4.3.1 节建议先识别支持主要功能的结构,再处理包括质量属性在内的其他驱动因素。为什么提出这个建议?是否可以在考虑主要功能如何得到支持之前,先为质量属性进行设计?
  3. 如果架构师决定针对系统所有用例都执行 ADD 迭代,会产生什么后果?
  4. 如果不执行 ADD 的步骤 6,而是把所有文档活动都留到以后,会有什么风险?

第 129 页

谢谢