3软件架构实践(第4版)

质量属性场景

描述与精化

刺激环境响应度量场景优先级

🎯 AI 时代的学习建议:不要只读理论。理解这一章的设计动机(为什么需要这个概念?)和边界条件(什么情况下会失效?)。当 AI 生成的代码涉及这些概念时,你能判断它是否用对了场景。AI 能帮你总结内容,但无法替代你亲手阅读、思考、建立直觉的过程。

第3章 质量属性场景 (Quality Attribute Scenarios)

一、导读

1.1 本章学习目标

在本章结束时,你将能够:

  • 理解质量属性场景的本质,区分场景与模糊需求的差异
  • 掌握场景六要素,准确描述刺激源、刺激、环境、制品、响应和响应度量
  • 构建有效场景,将抽象的质量需求转化为具体可验证的场景
  • 使用场景进行沟通,在利益相关者之间建立共同理解
  • 评估场景质量,识别不完整或模糊的场景描述
  • 应用场景进行架构评估,用场景驱动架构决策
  • 精化场景粒度,从高层场景逐步细化到具体实现
  • 避免场景陷阱,识别常见的场景设计错误

1.2 为什么本章如此重要

质量属性场景是软件架构领域最重要的实践方法之一。它解决了质量需求描述中的一个根本难题:如何将模糊的、主观的质量期望转化为具体的、可验证的技术要求。

在实际项目中,我们经常听到这样的需求:"系统要快"、"系统要安全"、"系统要稳定"。这些表述虽然表达了用户的期望,但对于架构师来说远远不够。多快算快?什么样的安全才算安全?稳定是指不宕机还是指数据不丢失?

质量属性场景提供了一种结构化的方法来精化这些模糊需求。通过定义具体的刺激、环境和响应,场景将抽象的质量概念转化为可以讨论、分析和测试的具体情境。

场景的重要性体现在以下几个方面:

首先,场景是架构设计的输入。没有清晰的场景,架构师无法做出有针对性的设计决策。场景告诉架构师系统需要在什么条件下应对什么挑战,以及什么样的响应是可以接受的。

其次,场景是架构评估的基础。ATAM(架构权衡分析方法)等评估技术都依赖于场景来检验架构是否满足质量要求。通过执行场景,可以发现架构的弱点和风险。

第三,场景是沟通的桥梁。业务人员、开发人员、测试人员和运维人员对质量的理解各不相同。场景提供了一种共同的语言,使各方能够在具体的情境下讨论质量需求。

最后,场景是验收的标准。当项目完成时,如何判断系统是否达到了预期的质量水平?场景提供了可执行的测试用例,使质量验收变得客观和可操作。

本章将深入讲解质量属性场景的构造方法、使用技巧和最佳实践。掌握这一方法,将使你的架构设计更加精准和有效。

1.3 核心问题引导

在阅读本章时,请思考以下问题:

为什么"系统响应时间小于 2 秒"不是一个完整的质量属性场景?

质量属性场景的六个要素分别是什么?缺少任何一个会有什么后果?

如何从一个模糊的质量需求(如"系统要可靠")推导出多个具体场景?

场景的粒度应该如何控制?太粗或太细分别有什么问题?

场景与用例(Use Case)有什么区别和联系?

如何在资源有限的情况下确定场景的优先级?

场景应该在项目的哪个阶段创建?由谁来创建?

场景如何与架构决策建立明确的关联?


二、核心概念详解

3.1 质量属性场景的定义

严格定义:

质量属性场景(Quality Attribute Scenario)是一种结构化的方法,用于精确描述系统在特定条件下对特定刺激的预期响应。它由六个要素组成:刺激源(Source of Stimulus)、刺激(Stimulus)、环境(Environment)、制品(Artifact)、响应(Response)和响应度量(Response Measure)。

通俗地说,质量属性场景就是一个"如果...那么..."的故事,但它比日常语言中的条件句更加精确和完整。它不仅说明发生了什么和系统如何反应,还说明了在什么情况下发生、影响系统的哪些部分、以及如何衡量反应的好坏。

场景 vs 普通需求

让我们对比两种描述方式:

普通需求描述:

"系统应该具有高可用性。"

这种描述的问题:

  • "高"是多高?99% 还是 99.99%?
  • 在什么情况下需要高可用?维护期间呢?
  • 如果不可用,允许中断多久?
  • 如何验证系统是否达到了"高可用"?

质量属性场景描述:

"当生产环境的数据库服务器发生故障时(刺激源+刺激+环境),订单处理服务(制品)应在 30 秒内自动切换到备用数据库(响应),切换过程中已提交的订单不得丢失,未完成的订单处理延迟不超过 5 秒(响应度量)。"

这种描述的优势:

  • 明确了触发条件(数据库故障)
  • 明确了影响范围(订单处理服务)
  • 明确了预期行为(自动切换)
  • 明确了衡量标准(30 秒内、无数据丢失、延迟不超过 5 秒)
  • 可以设计测试来验证

场景的形式化表示

质量属性场景可以用以下模板表示:

【质量属性类型】场景名称

刺激源:<谁或什么产生了刺激>
刺激:<发生了什么事件>
环境:<在什么条件下发生>
制品:<系统的哪些部分受到影响>
响应:<系统如何应对>
响应度量:<如何衡量响应的有效性>

这个模板确保了场景的完整性和可验证性。

3.2 场景六要素详解

质量属性场景的六个要素缺一不可,每个要素都有其特定的作用。

1. 刺激源(Source of Stimulus)

刺激源是产生刺激的实体。它可以是:

  • 人:用户、管理员、攻击者
  • 系统:外部系统、内部组件、第三方服务
  • 环境:定时器、传感器、操作系统
  • 自然:自然灾害、电力中断

示例:

  • "终端用户发起支付请求"
  • "监控系统检测到 CPU 使用率超过 90%"
  • "定时任务触发数据备份"
  • "黑客尝试 SQL 注入攻击"

为什么刺激源重要?

不同的刺激源可能代表不同的信任级别和威胁模型。来自内部用户的请求和来自外部攻击者的请求需要不同的处理策略。明确刺激源有助于设计适当的安全和控制机制。

2. 刺激(Stimulus)

刺激是到达系统的事件或条件变化。它可以是:

  • 正常事件:用户请求、定时任务、数据更新
  • 异常事件:硬件故障、网络中断、恶意攻击
  • 负载变化:流量激增、数据量增长
  • 配置变更:参数调整、功能开关

示例:

  • "用户提交订单"
  • "主数据库连接失败"
  • "并发用户数从 1000 突增到 10000"
  • "SSL 证书即将过期"

刺激的分类

根据性质,刺激可以分为:

  • 预期刺激:系统设计时考虑到的正常情况
  • 意外刺激:未预料到的异常情况
  • 良性刺激:不会损害系统的变化
  • 恶意刺激:试图破坏系统的行为

完整的场景集应该覆盖各种类型的刺激,特别是那些可能导致系统失败的意外和恶意刺激。

3. 环境(Environment)

环境是刺激发生时的系统状态和外部条件。它包括:

  • 运行模式:正常模式、启动模式、降级模式、恢复模式
  • 负载条件:低负载、正常负载、峰值负载、过载
  • 资源状态:资源充足、资源紧张、资源耗尽
  • 外部条件:网络状况、依赖服务状态、时间约束

示例:

  • "系统在正常负载下运行"
  • "系统刚完成部署,正在预热"
  • "系统处于降级模式,非核心功能已关闭"
  • "网络连接不稳定,丢包率达到 5%"

为什么环境重要?

同样的刺激在不同环境下可能有完全不同的含义和处理方式。例如,数据库故障在正常负载下可能可以通过重试解决,但在峰值负载下可能需要立即切换到备用系统。

4. 制品(Artifact)

制品是受刺激影响的系统部分。它可以是:

  • 整个系统:刺激影响系统的所有部分
  • 子系统/模块:刺激只影响特定模块
  • 组件/服务:刺激只影响某个服务
  • 数据:刺激只影响数据存储或处理
  • 接口:刺激只影响 API 或通信协议

示例:

  • "订单处理服务"
  • "用户认证模块"
  • "支付网关接口"
  • "用户会话数据"

制品的粒度

制品的粒度应该与场景的目的相匹配:

  • 架构级场景:制品通常是子系统或主要组件
  • 设计级场景:制品可以是模块或类
  • 实现级场景:制品可以是函数或数据结构

在架构设计阶段,我们主要关注架构级场景。

5. 响应(Response)

响应是系统对刺激采取的行动。它应该描述:

  • 检测:系统如何感知刺激的发生
  • 处理:系统执行什么操作来应对
  • 结果:处理后系统处于什么状态

示例:

  • "记录错误日志并发送告警通知"
  • "切换到备用数据库并重试失败的请求"
  • "拒绝新请求并返回友好的错误页面"
  • "启动额外的服务实例以应对负载增长"

响应的完整性

一个好的响应描述应该包含:

  • 即时响应:刺激发生后立即采取的行动
  • 后续响应:长期或延迟采取的行动
  • 恢复行动:系统如何恢复到正常状态

例如,对于数据库故障场景:

  • 即时响应:检测到连接失败,记录错误
  • 后续响应:切换到备用数据库,重试失败的操作
  • 恢复行动:修复主数据库,重新同步数据,切换回主数据库

6. 响应度量(Response Measure)

响应度量定义了如何评估响应的有效性。它应该是:

  • 可测量的:有明确的数值或布尔判断
  • 可验证的:可以通过测试或监控来验证
  • 有意义的:与业务目标或用户体验相关

示例:

  • "切换时间在 30 秒以内"
  • "无数据丢失"
  • "99% 的用户请求不受影响"
  • "CPU 使用率降至 70% 以下"

度量的类型

响应度量可以分为:

  • 时间度量:响应时间、恢复时间、处理时间
  • 数量度量:数据丢失量、受影响用户数、错误率
  • 质量度量:数据一致性级别、服务降级程度
  • 资源度量:CPU 使用率、内存占用、带宽消耗

度量与 SLA/SLO

响应度量通常与服务等级协议(SLA)或服务等级目标(SLO)相关联。SLA 是对用户的承诺,SLO 是内部的目标。场景的响应度量应该与这些业务指标保持一致。

3.3 场景的构造方法

构造高质量的质量属性场景需要遵循一定的方法和步骤。

步骤一:识别关键质量属性

首先,确定系统最关键的质量属性。这可以通过以下方式:

  • 利益相关者访谈:了解各方的质量期望
  • 业务分析:识别支撑业务目标的关键质量
  • 竞品分析:参考同类系统的质量表现
  • 历史经验:从过往项目中总结教训

通常,一个系统有 3-5 个最关键的质量属性。不要试图为所有质量属性都编写场景,聚焦最重要的几个。

步骤二:头脑风暴刺激

针对每个质量属性,头脑风暴可能的刺激。可以使用以下技巧:

  • 正常路径:系统正常使用时的刺激
  • 异常路径:出错时的刺激
  • 边界条件:极限情况下的刺激
  • 恶意行为:攻击者的刺激

例如,对于性能属性:

  • 正常:用户发起常规请求
  • 异常:依赖服务响应缓慢
  • 边界:并发用户数达到设计上限
  • 恶意:DDoS 攻击

步骤三:定义环境和制品

为每个刺激确定典型的环境条件和影响的系统部分。考虑:

  • 系统在什么运行模式下?
  • 负载水平如何?
  • 资源状况怎样?
  • 哪些组件会受到影响?

步骤四:描述响应和度量

定义系统应该如何响应,以及如何衡量响应的有效性。确保:

  • 响应是具体的行动,而非模糊的描述
  • 度量是可验证的数值或条件
  • 度量与业务价值相关

步骤五:审查和完善

审查场景的完整性和质量:

  • 六要素是否齐全?
  • 描述是否清晰无歧义?
  • 度量是否可验证?
  • 场景是否现实可行?

场景构造示例

让我们为一个电商系统构造几个场景。

场景 1:性能场景

【性能】高峰期订单提交

刺激源:终端用户
刺激:提交订单请求
环境:促销活动期间,系统负载为正常水平的 5 倍
制品:订单创建服务及其依赖的库存服务和支付服务
响应:系统接受订单请求,异步处理库存扣减和支付,立即返回订单确认
响应度量:P95 响应时间 < 3 秒,订单创建成功率 > 99.5%

场景 2:可用性场景

【可用性】支付服务故障

刺激源:第三方支付网关
刺激:支付服务返回超时错误
环境:正常运营时段,系统负载正常
制品:订单支付模块
响应:系统记录错误,向用户显示友好提示,提供稍后重试选项,后台定时重试未完成的支付
响应度量:用户可见的错误信息清晰易懂,后台重试成功率 > 95%,最终支付完成率 > 98%

场景 3:安全性场景

【安全性】SQL 注入攻击

刺激源:恶意攻击者
刺激:在搜索框中输入 SQL 注入代码
环境:系统正常运行,WAF(Web 应用防火墙)已启用
制品:商品搜索功能及其数据库查询层
响应:系统检测并阻止恶意输入,记录安全事件,不暴露任何数据库信息,向安全团队发送告警
响应度量:注入尝试 100% 被阻止,无敏感信息泄露,告警在 5 分钟内发出

场景 4:可修改性场景

【可修改性】添加新的支付方式

刺激源:产品经理
刺激:要求集成新的支付渠道(如数字货币)
环境:系统已上线运营,有稳定的用户群
制品:支付模块及其接口定义
响应:开发人员只需实现新的支付适配器并配置,无需修改现有支付逻辑,经过测试后可独立部署
响应度量:开发工作量 < 5 人天,不影响现有支付功能,部署无需停机

3.4 场景的分类

质量属性场景可以根据不同的维度进行分类。

按质量属性分类

这是最常见的分类方式:

  • 性能场景:关注响应时间、吞吐量
  • 可用性场景:关注故障处理和恢复
  • 安全性场景:关注威胁防护
  • 可修改性场景:关注变更的难易程度
  • 可测试性场景:关注测试的支持程度
  • 可部署性场景:关注部署的便利性

按刺激类型分类

  • 正常刺激场景:系统预期会收到的刺激
  • 异常刺激场景:错误或故障导致的刺激
  • 恶意刺激场景:攻击者故意产生的刺激

按生命周期阶段分类

  • 运行时场景:系统运行时发生的场景
  • 开发时场景:开发和测试期间的场景
  • 部署时场景:部署和升级期间的场景

按粒度分类

  • 系统级场景:涉及整个系统
  • 子系统级场景:涉及某个子系统
  • 组件级场景:涉及单个组件

按优先级分类

  • 关键场景:必须满足,否则系统不可接受
  • 重要场景:应该满足,对系统价值有较大影响
  • 期望场景:最好满足,但不是必须的

3.5 场景的精化与演化

场景不是一次性产物,而是随着项目进展不断精化和演化的。

场景精化的层次

Level 1: 业务愿景
  "系统需要高性能"

Level 2: 质量属性目标
  "订单提交响应时间 < 2 秒"

Level 3: 质量属性场景
  "当用户在正常负载下提交订单时,订单服务应在 2 秒内返回确认"

Level 4: 具体测试用例
  "使用 JMeter 模拟 1000 并发用户提交订单,测量 P95 响应时间"

从 Level 1 到 Level 4,场景越来越具体,越来越可验证。

场景与架构决策的关联

每个场景应该能够追溯到具体的架构决策:

场景:订单提交响应时间 < 2 秒
  ↓
架构决策:
  - 采用异步处理模式
  - 引入 Redis 缓存热点数据
  - 数据库读写分离
  - 服务水平扩展至 3 个实例

这种关联使得架构决策有据可依,也使得场景有了实现的保障。

场景的演化

随着项目的推进,场景可能会:

  • 新增:发现新的质量需求
  • 修改:业务变化导致需求调整
  • 废弃:某些场景不再相关
  • 拆分:大场景拆分为更小的子场景
  • 合并:相似场景合并以减少冗余

场景应该像代码一样进行版本管理,记录变更历史和理由。

3.6 场景的优先级排序

资源总是有限的,不可能对所有场景投入同等的精力。需要对场景进行优先级排序。

优先级评估维度

业务价值:场景对业务目标的重要程度

风险程度:场景不满足的后果严重性

实现难度:满足场景所需的工作量

发生频率:场景触发的频繁程度

优先级矩阵

可以使用二维矩阵进行排序:

高业务价值    低业务价值
高发生频率     优先实现      计划实现
低发生频率     谨慎评估      可选实现

MoSCoW 方法

另一种常用的优先级分类方法:

  • Must have:必须有,否则系统不可接受
  • Should have:应该有,对系统很重要
  • Could have:可以有,如果资源允许
  • Won't have:本次不会有,留待未来

场景优先级示例

对于一个电商系统:

场景业务价值发生频率优先级
订单提交性能高高Must
支付服务故障恢复高低Must
SQL 注入防护高低Must
添加新支付方式中低Should
报表生成性能低低Could

三、程序员的视角

3.1 在架构设计中的应用

质量属性场景在日常开发中有多种应用场景。

场景一:需求澄清

当产品经理提出模糊的质量需求时,使用场景进行澄清:

产品经理:"系统要快。"

架构师:"能具体一点吗?让我用场景来确认:
- 谁发起请求?普通用户还是管理员?
- 什么类型的请求?浏览商品还是提交订单?
- 在什么负载下?平时还是促销期间?
- 多快算快?2 秒还是 5 秒?
- 多少比例的请求需要满足这个速度?95% 还是 99%?"

通过这些问题,将模糊需求转化为具体场景。

场景二:技术方案评估

当比较不同技术方案时,用场景作为评估标准:

方案 A:使用关系型数据库
方案 B:使用 NoSQL 数据库

评估场景:
1. 高并发读取场景:10000 QPS,P95 < 100ms
   - 方案 A:需要复杂的缓存层,难以保证
   - 方案 B:原生支持高并发,容易满足
   → 方案 B 胜出

2. 复杂查询场景:多表关联聚合
   - 方案 A:SQL 原生支持,简单高效
   - 方案 B:需要应用层组装,复杂且慢
   → 方案 A 胜出

综合权衡后做出选择。

场景三:代码审查

从场景角度审查代码:

审查点:这段代码是否满足性能场景?
- 是否有不必要的循环或查询?
- 是否正确使用了缓存?
- 是否有潜在的 N+1 查询问题?

审查点:这段代码是否满足可用性场景?
- 是否有适当的异常处理?
- 是否有重试机制?
- 失败时是否有降级策略?

场景四:测试设计

将场景转化为测试用例:

场景:支付服务故障时,订单仍能创建

测试用例:
1. Mock 支付服务返回超时
2. 提交订单请求
3. 验证订单创建成功,状态为"待支付"
4. 验证用户收到友好提示
5. 验证后台有重试任务创建

3.2 常见陷阱与误区

陷阱一:场景过于模糊

表现:场景描述中使用"快速"、"稳定"、"安全"等模糊词汇,没有具体度量。

后果:

  • 无法验证是否满足
  • 不同人有不同理解
  • 验收时产生争议

避免方法:

  • 每个场景必须包含响应度量
  • 度量必须是可测量的数值
  • 与利益相关者确认度量的合理性

陷阱二:场景过于理想化

表现:场景假设所有条件都是最优的,不考虑异常情况。

例如:

  • "在网络正常的情况下,请求应在 1 秒内响应"
  • "在所有依赖服务都可用时,系统应正常工作"

后果:

  • 忽略了真正的挑战
  • 无法发现架构弱点
  • 生产环境中频繁出问题

避免方法:

  • 重点设计异常场景
  • 考虑依赖故障、网络问题、资源限制
  • 模拟真实的生产环境条件

陷阱三:场景与实际脱节

表现:场景是在会议室里凭空想象的,没有基于真实的业务需求和技术约束。

后果:

  • 场景不能反映真实需求
  • 架构决策偏离实际
  • 资源浪费在不重要的场景上

避免方法:

  • 与真实用户和业务方沟通
  • 分析生产环境的日志和监控数据
  • 参考行业基准和竞品表现

陷阱四:场景过多过细

表现:为每个小细节都编写场景,导致场景数量庞大。

后果:

  • 管理和维护成本高
  • 重点不突出
  • 团队疲于应付

避免方法:

  • 聚焦关键质量属性
  • 每个属性 3-5 个代表性场景
  • 定期清理过时场景

陷阱五:场景一次性使用

表现:场景只在设计阶段创建,之后就不再更新和使用。

后果:

  • 场景与实际系统脱节
  • 场景失去指导意义
  • 知识未能传承

避免方法:

  • 将场景纳入文档体系
  • 在迭代中持续更新场景
  • 用场景指导测试和验收

3.3 与其他层级的联系

与业务战略的联系

场景将业务目标转化为技术要求:

业务目标:提升用户满意度
  ↓
质量目标:提高系统响应速度
  ↓
场景:P95 页面加载时间 < 2 秒
  ↓
架构决策:CDN 加速、前端优化、后端缓存

与项目管理的联系

场景影响项目计划和资源分配:

  • 估算:满足场景需要的工作量
  • 排期:高优先级场景先实现
  • 风险:难以满足的场景是高风险项
  • 验收:场景是验收的依据

与测试的联系

场景直接指导测试设计:

  • 测试用例:每个场景对应多个测试用例
  • 测试数据:场景定义了测试的条件和数据
  • 验收标准:场景的响应度量就是验收标准
  • 自动化:场景可以转化为自动化测试脚本

与运维的联系

场景帮助运维团队理解系统行为:

  • 监控指标:场景的响应度量成为监控指标
  • 告警阈值:场景定义了何时需要告警
  • 应急预案:场景描述了故障时的预期行为
  • 容量规划:场景提供了负载基准

四、代码实战

4.1 示例一:场景驱动的架构设计

下面我们用 Java 展示如何根据质量属性场景设计系统架构。

java
/**
 * 场景驱动的订单系统设计
 * 
 * 关键场景:
 * 1. 性能场景:高峰期订单提交 P95 < 2 秒
 * 2. 可用性场景:支付服务故障时订单仍能创建
 * 3. 安全性场景:防止重复提交订单
 */

import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicLong;

// ==================== 领域模型 ====================

class Order {
    private final String orderId;
    private final String userId;
    private final List<OrderItem> items;
    private OrderStatus status;
    private final long createdAt;
    
    public Order(String orderId, String userId, List<OrderItem> items) {
        this.orderId = orderId;
        this.userId = userId;
        this.items = items;
        this.status = OrderStatus.CREATED;
        this.createdAt = System.currentTimeMillis();
    }
    
    // Getters
    public String getOrderId() { return orderId; }
    public String getUserId() { return userId; }
    public List<OrderItem> getItems() { return Collections.unmodifiableList(items); }
    public OrderStatus getStatus() { return status; }
    public long getCreatedAt() { return createdAt; }
    
    public void setStatus(OrderStatus status) {
        this.status = status;
    }
    
    @Override
    public String toString() {
        return "Order{" +
                "orderId='" + orderId + '\'' +
                ", userId='" + userId + '\'' +
                ", status=" + status +
                ", createdAt=" + createdAt +
                '}';
    }
}

class OrderItem {
    private final String productId;
    private final int quantity;
    private final double price;
    
    public OrderItem(String productId, int quantity, double price) {
        this.productId = productId;
        this.quantity = quantity;
        this.price = price;
    }
    
    public String getProductId() { return productId; }
    public int getQuantity() { return quantity; }
    public double getPrice() { return price; }
}

enum OrderStatus {
    CREATED,       // 已创建
    PAYING,        // 支付中
    PAID,          // 已支付
    FAILED,        // 失败
    CANCELLED      // 已取消
}

// ==================== 场景一:性能优化 - 异步处理 ====================

/**
 * 异步订单处理器
 * 
 * 场景:高峰期订单提交 P95 < 2 秒
 * 策略:接收请求后立即返回,后台异步处理库存和支付
 */
class AsyncOrderProcessor {
    private final ExecutorService executor;
    private final OrderRepository orderRepository;
    private final InventoryService inventoryService;
    private final PaymentService paymentService;
    private final AtomicLong orderCounter;
    
    public AsyncOrderProcessor(
            OrderRepository orderRepository,
            InventoryService inventoryService,
            PaymentService paymentService) {
        this.orderRepository = orderRepository;
        this.inventoryService = inventoryService;
        this.paymentService = paymentService;
        this.orderCounter = new AtomicLong(0);
        
        // 使用线程池进行异步处理
        this.executor = Executors.newFixedThreadPool(10);
    }
    
    /**
     * 创建订单(快速返回)
     * 
     * 响应度量:P95 响应时间 < 2 秒
     */
    public CompletableFuture<Order> createOrder(String userId, List<OrderItem> items) {
        String orderId = generateOrderId();
        Order order = new Order(orderId, userId, items);
        
        // 立即保存订单状态为 CREATED
        orderRepository.save(order);
        
        // 异步处理后续流程
        CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
            try {
                processOrderAsync(order);
            } catch (Exception e) {
                handleOrderFailure(order, e);
            }
        }, executor);
        
        // 立即返回订单,不等待异步处理完成
        return CompletableFuture.completedFuture(order);
    }
    
    private void processOrderAsync(Order order) {
        // 步骤 1:检查并扣减库存
        boolean stockReserved = inventoryService.reserveStock(
                order.getItems().stream()
                    .map(item -> new InventoryReservation(item.getProductId(), item.getQuantity()))
                    .toList()
        );
        
        if (!stockReserved) {
            order.setStatus(OrderStatus.FAILED);
            orderRepository.update(order);
            return;
        }
        
        // 步骤 2:发起支付
        order.setStatus(OrderStatus.PAYING);
        orderRepository.update(order);
        
        boolean paymentSuccess = paymentService.processPayment(
                order.getOrderId(),
                order.getItems().stream().mapToDouble(OrderItem::getPrice).sum()
        );
        
        if (paymentSuccess) {
            order.setStatus(OrderStatus.PAID);
        } else {
            order.setStatus(OrderStatus.FAILED);
            // 释放库存
            inventoryService.releaseStock(order.getItems().stream()
                    .map(item -> new InventoryReservation(item.getProductId(), item.getQuantity()))
                    .toList());
        }
        
        orderRepository.update(order);
    }
    
    private void handleOrderFailure(Order order, Exception e) {
        order.setStatus(OrderStatus.FAILED);
        orderRepository.update(order);
        // 记录错误日志,发送告警
        System.err.println("Order processing failed: " + order.getOrderId() + ", error: " + e.getMessage());
    }
    
    private String generateOrderId() {
        return "ORD-" + System.currentTimeMillis() + "-" + orderCounter.incrementAndGet();
    }
    
    public void shutdown() {
        executor.shutdown();
    }
}

// ==================== 场景二:可用性 - 熔断降级 ====================

/**
 * 带熔断器的支付服务客户端
 * 
 * 场景:支付服务故障时订单仍能创建
 * 策略:支付服务不可用时,订单状态设为"待支付",后台重试
 */
class ResilientPaymentService implements PaymentService {
    private final PaymentService realPaymentService;
    private final CircuitBreaker circuitBreaker;
    
    public ResilientPaymentService(PaymentService realPaymentService) {
        this.realPaymentService = realPaymentService;
        this.circuitBreaker = new CircuitBreaker(5, 30); // 5 次失败后熔断,30 秒后重试
    }
    
    @Override
    public boolean processPayment(String orderId, double amount) {
        try {
            return circuitBreaker.execute(() -> realPaymentService.processPayment(orderId, amount));
        } catch (CircuitBreakerOpenException e) {
            // 熔断器打开,记录订单为待支付,稍后重试
            System.out.println("Payment service unavailable, order " + orderId + " marked as pending");
            return false; // 返回 false 但不失败订单
        }
    }
}

class CircuitBreaker {
    private final int failureThreshold;
    private final long retryDelayMs;
    private int failureCount;
    private long lastFailureTime;
    private boolean isOpen;
    
    public CircuitBreaker(int failureThreshold, long retryDelaySeconds) {
        this.failureThreshold = failureThreshold;
        this.retryDelayMs = retryDelaySeconds * 1000;
        this.failureCount = 0;
        this.isOpen = false;
    }
    
    public synchronized <T> T execute(Callable<T> callable) throws Exception {
        if (isOpen) {
            if (System.currentTimeMillis() - lastFailureTime > retryDelayMs) {
                // 半开状态,允许一次试探
                System.out.println("Circuit breaker half-open, allowing probe request");
                isOpen = false;
            } else {
                throw new CircuitBreakerOpenException("Circuit breaker is open");
            }
        }
        
        try {
            T result = callable.call();
            onSuccess();
            return result;
        } catch (Exception e) {
            onFailure();
            throw e;
        }
    }
    
    private synchronized void onSuccess() {
        failureCount = 0;
        isOpen = false;
    }
    
    private synchronized void onFailure() {
        failureCount++;
        lastFailureTime = System.currentTimeMillis();
        if (failureCount >= failureThreshold) {
            isOpen = true;
            System.out.println("Circuit breaker opened after " + failureCount + " failures");
        }
    }
}

class CircuitBreakerOpenException extends RuntimeException {
    public CircuitBreakerOpenException(String message) {
        super(message);
    }
}

// ==================== 场景三:安全性 - 防重复提交 ====================

/**
 * 防重复提交拦截器
 * 
 * 场景:防止用户重复提交同一订单
 * 策略:使用唯一令牌机制
 */
class IdempotencyInterceptor {
    private final Map<String, Long> processedRequests;
    private static final long TTL_MS = 3600000; // 1 小时过期
    
    public IdempotencyInterceptor() {
        this.processedRequests = new ConcurrentHashMap<>();
    }
    
    /**
     * 检查请求是否已处理
     * @return true 如果是新请求,false 如果是重复请求
     */
    public boolean isNewRequest(String idempotencyKey) {
        long now = System.currentTimeMillis();
        
        // 清理过期记录
        processedRequests.entrySet().removeIf(entry -> now - entry.getValue() > TTL_MS);
        
        // 检查是否已处理
        Long previousTime = processedRequests.putIfAbsent(idempotencyKey, now);
        
        if (previousTime != null) {
            System.out.println("Duplicate request detected for key: " + idempotencyKey);
            return false;
        }
        
        return true;
    }
}

// ==================== 辅助接口和类 ====================

interface OrderRepository {
    void save(Order order);
    void update(Order order);
    Order findById(String orderId);
}

interface InventoryService {
    boolean reserveStock(List<InventoryReservation> reservations);
    void releaseStock(List<InventoryReservation> reservations);
}

interface PaymentService {
    boolean processPayment(String orderId, double amount);
}

class InventoryReservation {
    private final String productId;
    private final int quantity;
    
    public InventoryReservation(String productId, int quantity) {
        this.productId = productId;
        this.quantity = quantity;
    }
    
    public String getProductId() { return productId; }
    public int getQuantity() { return quantity; }
}

// ==================== 测试 ====================

public class ScenarioDrivenDesign {
    public static void main(String[] args) throws Exception {
        System.out.println("===== 场景驱动设计演示 =====\n");
        
        // 模拟依赖
        OrderRepository orderRepo = new InMemoryOrderRepository();
        InventoryService inventoryService = new MockInventoryService();
        PaymentService paymentService = new MockPaymentService();
        
        // 创建异步处理器
        AsyncOrderProcessor processor = new AsyncOrderProcessor(
                orderRepo, inventoryService, paymentService
        );
        
        // 场景一:测试快速创建订单
        System.out.println("--- 场景一:高峰期订单提交 ---");
        List<OrderItem> items = Arrays.asList(
                new OrderItem("PROD-1", 2, 99.9),
                new OrderItem("PROD-2", 1, 199.9)
        );
        
        long startTime = System.currentTimeMillis();
        Order order = processor.createOrder("USER-123", items).get();
        long elapsed = System.currentTimeMillis() - startTime;
        
        System.out.println("订单创建耗时: " + elapsed + "ms");
        System.out.println("订单 ID: " + order.getOrderId());
        System.out.println("订单状态: " + order.getStatus());
        System.out.println("(注意:订单已创建,但支付和库存扣减在后台异步进行)\n");
        
        // 等待异步处理完成
        Thread.sleep(2000);
        
        // 场景二:测试支付服务故障
        System.out.println("--- 场景二:支付服务故障 ---");
        PaymentService failingPaymentService = new AlwaysFailingPaymentService();
        ResilientPaymentService resilientPaymentService = new ResilientPaymentService(failingPaymentService);
        
        boolean result = resilientPaymentService.processPayment("ORDER-TEST", 100.0);
        System.out.println("支付结果: " + result);
        System.out.println("(注意:支付失败但订单未失败,标记为待支付)\n");
        
        // 场景三:测试防重复提交
        System.out.println("--- 场景三:防重复提交 ---");
        IdempotencyInterceptor interceptor = new IdempotencyInterceptor();
        
        String idempotencyKey = "ORDER-SUBMIT-123";
        boolean first = interceptor.isNewRequest(idempotencyKey);
        boolean second = interceptor.isNewRequest(idempotencyKey);
        
        System.out.println("第一次提交: " + (first ? "允许" : "拒绝"));
        System.out.println("第二次提交: " + (second ? "允许" : "拒绝"));
        
        processor.shutdown();
    }
}

// ==================== 模拟实现 ====================

class InMemoryOrderRepository implements OrderRepository {
    private final Map<String, Order> orders = new ConcurrentHashMap<>();
    
    @Override
    public void save(Order order) {
        orders.put(order.getOrderId(), order);
        System.out.println("Order saved: " + order.getOrderId());
    }
    
    @Override
    public void update(Order order) {
        orders.put(order.getOrderId(), order);
        System.out.println("Order updated: " + order.getOrderId() + ", status: " + order.getStatus());
    }
    
    @Override
    public Order findById(String orderId) {
        return orders.get(orderId);
    }
}

class MockInventoryService implements InventoryService {
    @Override
    public boolean reserveStock(List<InventoryReservation> reservations) {
        System.out.println("Reserving stock for " + reservations.size() + " items");
        return true; // 模拟成功
    }
    
    @Override
    public void releaseStock(List<InventoryReservation> reservations) {
        System.out.println("Releasing stock for " + reservations.size() + " items");
    }
}

class MockPaymentService implements PaymentService {
    @Override
    public boolean processPayment(String orderId, double amount) {
        System.out.println("Processing payment for order " + orderId + ": $" + amount);
        return true; // 模拟成功
    }
}

class AlwaysFailingPaymentService implements PaymentService {
    @Override
    public boolean processPayment(String orderId, double amount) {
        System.out.println("Payment service failed for order " + orderId);
        throw new RuntimeException("Payment service unavailable");
    }
}

这个示例展示了如何根据三个质量属性场景设计系统:

性能场景:使用异步处理,订单创建立即返回

可用性场景:使用熔断器,支付服务故障时不导致订单失败

安全性场景:使用幂等性令牌,防止重复提交

4.2 示例二:场景验证框架

下面我们用 Python 实现一个简单的场景验证框架。

python
"""
质量属性场景验证框架
用于定义、执行和验证质量属性场景
"""

from dataclasses import dataclass, field
from typing import Callable, List, Optional, Any
from enum import Enum
import time


class ScenarioStatus(Enum):
    """场景执行状态"""
    PENDING = "pending"       # 待执行
    RUNNING = "running"       # 执行中
    PASSED = "passed"         # 通过
    FAILED = "failed"         # 失败


@dataclass
class QualityAttributeScenario:
    """质量属性场景定义"""
    name: str
    quality_attribute: str  # 性能、可用性、安全性等
    
    # 六要素
    source: str           # 刺激源
    stimulus: str         # 刺激
    environment: str      # 环境
    artifact: str         # 制品
    response: str         # 响应
    response_measure: str # 响应度量
    
    # 验证相关
    test_function: Optional[Callable] = None
    status: ScenarioStatus = ScenarioStatus.PENDING
    actual_result: Optional[Any] = None
    expected_result: Optional[Any] = None
    execution_time: float = 0.0
    
    def __str__(self):
        return f"""
【{self.quality_attribute}】{self.name}
  刺激源: {self.source}
  刺激: {self.stimulus}
  环境: {self.environment}
  制品: {self.artifact}
  响应: {self.response}
  响应度量: {self.response_measure}
  状态: {self.status.value}
"""


class ScenarioValidator:
    """场景验证器"""
    
    def __init__(self):
        self.scenarios: List[QualityAttributeScenario] = []
    
    def add_scenario(self, scenario: QualityAttributeScenario):
        """添加场景"""
        self.scenarios.append(scenario)
    
    def execute_scenario(self, scenario: QualityAttributeScenario) -> bool:
        """执行单个场景"""
        print(f"\n执行场景: {scenario.name}")
        print("-" * 50)
        
        scenario.status = ScenarioStatus.RUNNING
        start_time = time.time()
        
        try:
            if scenario.test_function:
                result = scenario.test_function()
                scenario.actual_result = result
                
                # 验证结果
                if scenario.expected_result is not None:
                    passed = result == scenario.expected_result
                else:
                    # 如果没有预期结果,假设返回 True 表示通过
                    passed = result is True or result is None
                
                scenario.status = ScenarioStatus.PASSED if passed else ScenarioStatus.FAILED
            else:
                # 没有测试函数,标记为待实现
                scenario.status = ScenarioStatus.FAILED
                raise NotImplementedError("Test function not implemented")
                
        except Exception as e:
            scenario.status = ScenarioStatus.FAILED
            scenario.actual_result = str(e)
            print(f"场景执行失败: {e}")
        
        finally:
            scenario.execution_time = time.time() - start_time
            print(f"执行时间: {scenario.execution_time:.3f}s")
            print(f"状态: {scenario.status.value}")
            
            return scenario.status == ScenarioStatus.PASSED
    
    def execute_all(self) -> dict:
        """执行所有场景"""
        results = {
            "total": len(self.scenarios),
            "passed": 0,
            "failed": 0,
            "details": []
        }
        
        for scenario in self.scenarios:
            passed = self.execute_scenario(scenario)
            
            if passed:
                results["passed"] += 1
            else:
                results["failed"] += 1
            
            results["details"].append({
                "name": scenario.name,
                "status": scenario.status.value,
                "execution_time": scenario.execution_time
            })
        
        return results
    
    def report(self) -> str:
        """生成报告"""
        lines = [
            "\n" + "=" * 60,
            "质量属性场景验证报告",
            "=" * 60,
        ]
        
        for scenario in self.scenarios:
            lines.append(str(scenario))
        
        results = {s.name: s.status.value for s in self.scenarios}
        passed = sum(1 for s in self.scenarios if s.status == ScenarioStatus.PASSED)
        
        lines.extend([
            "-" * 60,
            f"总计: {len(self.scenarios)} 个场景",
            f"通过: {passed}",
            f"失败: {len(self.scenarios) - passed}",
            f"通过率: {passed / len(self.scenarios) * 100:.1f}%",
            "=" * 60,
        ])
        
        return "\n".join(lines)


# ==================== 示例场景 ====================

def test_response_time():
    """测试响应时间场景"""
    start = time.time()
    
    # 模拟处理
    time.sleep(0.1)
    
    elapsed = time.time() - start
    # 要求响应时间 < 0.5 秒
    return elapsed < 0.5


def test_fault_tolerance():
    """测试容错场景"""
    try:
        # 模拟依赖服务调用
        raise ConnectionError("Service unavailable")
    except ConnectionError:
        # 系统应该捕获异常并降级
        return True  # 降级成功
    return False


def test_idempotency():
    """测试幂等性场景"""
    processed = set()
    
    # 第一次提交
    key = "request-123"
    if key in processed:
        return False  # 不应该被识别为重复
    
    processed.add(key)
    
    # 第二次提交
    if key in processed:
        return True  # 正确识别为重复
    
    return False


if __name__ == "__main__":
    validator = ScenarioValidator()
    
    # 添加性能场景
    perf_scenario = QualityAttributeScenario(
        name="高峰期订单提交",
        quality_attribute="性能",
        source="终端用户",
        stimulus="提交订单请求",
        environment="促销活动期间,系统负载为正常水平的 5 倍",
        artifact="订单创建服务",
        response="系统接受订单请求,立即返回确认",
        response_measure="P95 响应时间 < 2 秒",
        test_function=test_response_time,
        expected_result=True
    )
    validator.add_scenario(perf_scenario)
    
    # 添加可用性场景
    avail_scenario = QualityAttributeScenario(
        name="支付服务故障",
        quality_attribute="可用性",
        source="第三方支付网关",
        stimulus="支付服务返回超时错误",
        environment="正常运营时段",
        artifact="订单支付模块",
        response="系统降级处理,订单标记为待支付",
        response_measure="订单创建成功率 > 99%",
        test_function=test_fault_tolerance,
        expected_result=True
    )
    validator.add_scenario(avail_scenario)
    
    # 添加安全性场景
    security_scenario = QualityAttributeScenario(
        name="防止重复提交",
        quality_attribute="安全性",
        source="终端用户",
        stimulus="短时间内多次点击提交按钮",
        environment="网络延迟较高",
        artifact="订单提交接口",
        response="系统识别并拒绝重复请求",
        response_measure="重复请求 100% 被阻止",
        test_function=test_idempotency,
        expected_result=True
    )
    validator.add_scenario(security_scenario)
    
    # 执行所有场景
    results = validator.execute_all()
    
    # 生成报告
    print(validator.report())
    
    print("\n详细结果:")
    for detail in results["details"]:
        print(f"  {detail['name']}: {detail['status']} ({detail['execution_time']:.3f}s)")

这个框架提供了:

场景定义:结构化的场景表示,包含六要素

场景执行:自动执行测试函数并记录结果

结果验证:比较实际结果与预期结果

报告生成:生成详细的验证报告


五、深入思考

5.1 历史背景

质量属性场景的概念起源于 20 世纪 90 年代的软件架构研究。

起源

  • 1996 年:Len Bass、Paul Clements 和 Rick Kazman 在《Software Architecture in Practice》第一版中首次系统性地提出了质量属性场景的概念
  • 1998 年:他们在 SEI(软件工程研究所)开发了 ATAM(架构权衡分析方法),场景成为该方法的核心组成部分

发展

  • 2000s:场景方法被广泛应用于工业界,成为架构评估的标准实践
  • 2005 年:ISO/IEC 25010 质量标准发布,吸收了场景思想
  • 2010s:敏捷开发兴起,场景方法与用户故事结合,形成"质量故事"实践
  • 2015 年:DevOps 普及,场景扩展到部署和运维领域

影响

质量属性场景的影响超越了软件架构领域:

  • 系统工程:被应用于硬件和嵌入式系统
  • 产品管理:用于定义非功能性需求
  • 测试工程:指导性能和安全性测试设计
  • 项目管理:作为风险评估和优先级排序的工具

关键人物

  • Len Bass, Paul Clements, Rick Kazman:场景方法的创始人
  • Mary Shaw:软件架构教育的先驱,推广了场景在教学中的应用
  • Grady Booch:统一建模语言(UML)的创造者之一,将场景纳入建模方法

5.2 未解决的问题

场景的形式化验证

目前,场景的验证主要依靠测试和经验。能否开发出形式化方法,数学地证明架构满足特定场景的要求?这对于安全关键系统尤为重要。

场景的自动生成

能否从业务需求或用户故事中自动推导出质量属性场景?这需要自然语言处理和领域知识的结合。

场景的动态更新

当前的场景是静态定义的。在运行时,系统能否根据实际表现动态调整场景的优先级或度量标准?

场景与 AI 的结合

AI 系统(如机器学习模型)的质量属性(如公平性、可解释性)如何用场景描述?传统的场景方法是否需要扩展?

大规模场景管理

在大型系统中,场景数量可能达到数百甚至数千。如何有效地组织、检索和维护这些场景?

5.3 延伸阅读

《Software Architecture in Practice》(第 4 版) - Len Bass, Paul Clements, Rick Kazman

本书对质量属性场景有最权威的讲解,包括场景的构造方法和在 ATAM 中的应用。

《Evaluating Software Architectures: Methods and Tools》 - Paul Clements, Rick Kazman, Linda Northrop

详细介绍 ATAM 方法,场景是该方法的核心组成部分。

《Writing Effective Use Cases》 - Alistair Cockburn

虽然主要讲用例,但其中的场景写作技巧对质量属性场景也有借鉴意义。

"Quality Attribute Scenarios: A Method for Specifying and Analyzing Quality Attributes"(论文) - Len Bass et al.

场景方法的原始论文,详细介绍了理论基础和实践指南。

《Agile Modeling》 - Scott Ambler

介绍了如何在敏捷环境中使用轻量级场景方法。


六、实验笔记

实验一:为真实系统编写质量属性场景

目标:练习将模糊的质量需求转化为具体的质量属性场景。

步骤:

选择一个你熟悉的系统(可以是开源项目、公司内部系统或个人项目)

采访至少 2 位利益相关者(用户、产品经理、开发人员等),收集他们对系统质量的期望

将收集到的模糊需求整理为初步的质量属性列表

为每个关键质量属性编写 3-5 个质量属性场景

确保每个场景都包含完整的六要素

与利益相关者评审场景,确认准确性和完整性

根据反馈修改场景

预期结果:

  • 一份利益相关者访谈记录
  • 至少 15 个完整的质量属性场景(覆盖至少 5 个质量属性)
  • 场景评审会议纪要
  • 修订后的场景文档

场景质量检查清单:

  • [ ] 六要素是否齐全?
  • [ ] 刺激源是否明确?
  • [ ] 刺激是否具体?
  • [ ] 环境条件是否清晰?
  • [ ] 制品是否准确定位?
  • [ ] 响应是否是具体行动?
  • [ ] 响应度量是否可验证?
  • [ ] 场景是否现实可行?

思考题:

在访谈过程中,利益相关者最难表达的是哪类质量需求?为什么?

哪些场景在评审时被修改最多?反映了什么问题?

场景编写过程中,你发现了哪些之前未被注意到的质量需求?

实验二:场景驱动的架构评估

目标:使用质量属性场景评估现有架构。

步骤:

获取一个系统的架构文档(或自行绘制)

准备一组质量属性场景(可以使用实验一的结果)

对每个场景,分析:

a. 当前架构是否能满足该场景?

b. 如果能,是通过什么机制实现的?

c. 如果不能,缺口在哪里?

d. 需要什么样的架构改进?

识别架构的风险点和敏感点

提出架构改进建议

估算改进所需的工作量

评估模板:

场景:[场景名称]

架构分析:
- 相关组件:[列出受影响的组件]
- 当前机制:[描述当前如何处理此类场景]
- 满足程度:[完全满足 / 部分满足 / 不满足]

风险评估:
- 风险等级:[高 / 中 / 低]
- 风险描述:[详细说明]

改进建议:
- 建议方案:[描述改进措施]
- 预期效果:[改进后的表现]
- 工作量估算:[人天]

预期结果:

  • 一份完整的架构评估报告
  • 至少 10 个场景的详细分析
  • 架构风险清单
  • 改进建议和优先级排序

思考题:

哪些场景最容易暴露出架构弱点?

架构改进建议中,哪些是短期可以做到的,哪些需要长期规划?

如果资源有限,只能实施一项改进,你会选择哪一项?为什么?


七、本章小结

质量属性场景是将模糊的质量需求转化为具体、可验证要求的结构化方法。

核心要点:

场景六要素:

- 刺激源(Source):谁或什么产生了刺激

- 刺激(Stimulus):发生了什么事件

- 环境(Environment):在什么条件下发生

- 制品(Artifact):系统的哪些部分受到影响

- 响应(Response):系统如何应对

- 响应度量(Response Measure):如何衡量响应的有效性

场景的价值:

- 精确描述质量需求,消除歧义

- 驱动架构设计,使决策有据可依

- 作为评估标准,检验架构是否满足要求

- 促进沟通,在利益相关者之间建立共同理解

场景构造方法:

- 识别关键质量属性

- 头脑风暴可能的刺激

- 定义环境和制品

- 描述响应和度量

- 审查和完善

场景的分类:

- 按质量属性:性能、可用性、安全性等

- 按刺激类型:正常、异常、恶意

- 按粒度:系统级、子系统级、组件级

- 按优先级:关键、重要、期望

场景的演化:

- 场景不是一次性产物,需要持续更新

- 场景应与架构决策建立关联

- 场景可以转化为测试用例

场景与普通需求的对比:

维度普通需求质量属性场景
精确度模糊精确
可验证性难以验证可测量
完整性常缺少上下文六要素齐全
沟通效果易产生歧义清晰明确
驱动设计间接直接

场景的最佳实践:

  • 聚焦关键质量属性,不要试图覆盖所有
  • 每个属性 3-5 个代表性场景
  • 场景应由多方利益相关者共同参与
  • 场景应随项目进展持续更新
  • 场景应与测试和验收关联

八、习题

基础题

列出质量属性场景的六个要素,并简要说明每个要素的作用。

将以下模糊需求转化为质量属性场景:

a) "系统要快"

b) "系统要稳定"

c) "系统要安全"

解释为什么"系统在正常情况下响应时间应小于 2 秒"不是一个完整的质量属性场景。缺少的要素是什么?

区分以下刺激类型:正常刺激、异常刺激、恶意刺激,并各举一个例子。

什么是响应度量?为什么它是场景中最重要的要素之一?

进阶题

为一个在线银行系统设计质量属性场景,覆盖以下属性:

a) 性能

b) 安全性

c) 可用性

每个属性至少 2 个场景,确保六要素完整。

分析以下场景的问题,并提出改进建议:

```

【性能】用户登录

刺激源:用户

刺激:登录

环境:正常

制品:登录模块

响应:快速响应

响应度量:快

```

假设你要评估一个微服务架构的系统,请设计一套场景来评估其可修改性。至少包含 5 个场景,涵盖代码修改、配置变更、服务替换等方面。

挑战题

设计一个场景优先级评估模型:

a) 定义评估维度(如业务价值、风险程度、实现难度、发生频率)

b) 为每个维度设计评分标准

c) 用一个具体案例演示如何使用该模型对 10 个场景进行排序

d) 分析排序结果的合理性

研究 ATAM(架构权衡分析方法)中的场景应用:

a) ATAM 如何使用场景进行架构评估?

b) 什么是效用树(Utility Tree)?它与场景有什么关系?

c) 设计一个简化的 ATAM 评估流程,用场景驱动整个评估过程

d) 用一个开源项目为例,执行这个简化流程并报告结果

3/10质量属性
0%