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 页
选择路线图
绿地系统的设计概念选择路线图
图中展示了绿地系统设计中的迭代路线:
- 第一次迭代:建立初始整体系统结构。
- 参考架构。
- 部署模式。
- 可选的外部开发组件。
- 第二次迭代:识别支持主要功能的结构。
- 架构模式。
- 可选的外部开发组件。
- 第三次及后续迭代:细化已有结构以完全处理剩余驱动因素。
- 战术。
- 架构模式。
- 部署模式。
- 外部开发组件。
第 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 的总体流程:
输入驱动因素包括:
- 设计目的
- 主要功能
- 质量属性
- 架构关注点
- 约束
主要步骤包括:
- 审查输入。
- 通过选择驱动因素确定迭代目标。
- 选择一个或多个系统元素进行细化。
- 选择一个或多个能够满足已选驱动因素的设计概念。
- 实例化架构元素、分配职责并定义接口。
- 草拟视图并记录设计决策。
- 分析当前设计,并审查迭代目标和设计目的的达成情况。
输出是经过细化的软件架构设计。
第 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 应用于不同系统语境
根据系统类型裁剪设计方法
软件系统设计可以分为三类:
- 成熟领域中的绿地系统设计,即领域充分了解。
- 新颖领域中的绿地系统设计,即该领域的基础设施和知识基础尚不成熟。
- 为已有系统进行变更的设计,即棕地系统设计。
第 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 页
讨论问题
- 在 ADD 的步骤 2 中,如果为迭代选择的目标范围过大,可能会发生什么?
- 在成熟领域的绿地系统设计中,第 4.3.1 节建议先识别支持主要功能的结构,再处理包括质量属性在内的其他驱动因素。为什么提出这个建议?是否可以在考虑主要功能如何得到支持之前,先为质量属性进行设计?
- 如果架构师决定针对系统所有用例都执行 ADD 迭代,会产生什么后果?
- 如果不执行 ADD 的步骤 6,而是把所有文档活动都留到以后,会有什么风险?