19. 架构重要需求
文章目录
- 第19章 架构重要需求
- 19.1 从需求文档中收集架构重要需求(ASRs)
- 不要抱太大希望
- 从需求文档中找出架构重要需求
- 19.2 通过访谈利益相关者收集架构重要需求
- 19.3 通过理解业务目标收集架构重要需求
- 19.4 在效用树中捕获架构重要需求
- 19.5 变化总会发生
- 19.6 小结
- 19.7 扩展阅读
- 19.8 问题讨论
第19章 架构重要需求
软件开发最重要的一个方面是明确你正在尝试构建的东西是什么。
—Bjarne Stroustrup, creator of C++
架构的存在是为了构建满足需求的系统。这里的 “需求” 并不一定是指使用需求工程所能提供的最佳技术生成的一份有文档记录的目录。相反,我们指的是这样一组特性:如果你的系统不能满足这些特性,那么这个系统就会失败。需求以与软件开发项目一样多的形式存在 —— 从精心编写的规范到主要利益相关者之间的口头共同理解(真实的或想象的)。你的项目需求实践的技术、经济和哲学依据超出了本书的范围。在本书范围内的是,无论需求以何种方式被捕获,它们都确立了成功或失败的标准,而架构师需要了解这些标准。
对架构师来说,并非所有需求都是同等重要的。有些需求对架构的影响比其他需求大得多。一个 “架构重要需求(ASR)” 是一个将对架构产生深远影响的需求 —— 也就是说,如果没有这样的需求,架构很可能会有很大的不同。
如果你不知道 ASR,就不可能设计出一个成功的架构。ASR 通常(但不总是)以质量属性(QA)需求的形式出现 —— 即架构必须为系统提供的性能、安全性、可修改性、可用性、易用性等等。在 第 4 章 至 第 14 章 中,我们介绍了实现质量属性的模式和策略。每次你在架构中选择一个模式或策略来使用时,都是因为需要满足质量属性需求。质量属性需求越困难、越重要,就越有可能对架构产生重大影响,因此也就越有可能是一个 ASR。
架构师必须确定 ASR,通常是在做了大量工作以发现候选 ASR 之后。有能力的架构师知道这一点。事实上,当我们观察有经验的架构师履行他们的职责时,我们会注意到他们做的第一件事就是开始与重要的利益相关者交谈。他们正在收集他们需要的信息,以产生能够响应项目需求的架构 —— 无论这些信息之前是否已经被确定。
本章提供了一些系统的技术来确定 ASR 以及其他将塑造架构的因素。
19.1 从需求文档中收集架构重要需求(ASRs)
寻找候选架构重要需求的一个明显位置是在需求文档或用户故事中。毕竟,我们正在寻找需求,而需求应该(嗯)在需求文档中。不幸的是,情况通常并非如此,尽管需求文档中的信息肯定是有用的。
不要抱太大希望
许多项目不会创建或维护软件工程课程教授或传统软件工程书籍作者喜欢规定的那种需求文档。此外,没有架构师会只是坐着等待需求 “完成” 后才开始工作。架构师必须在需求仍在变化时就开始工作。因此,当架构师开始工作时,质量属性需求很可能是不确定的。即使它们存在且稳定,需求文档通常在两个方面让架构师失望:
-
需求规格说明中找到的大部分信息不会影响架构。正如我们反复看到的,架构主要由质量属性需求驱动或 “塑造”,质量属性需求决定并约束最重要的架构决策。即便如此,大多数需求规格说明的绝大部分内容都集中在系统所需的特性和功能上,而这些对架构的影响最小。最佳的软件工程实践确实规定要捕获质量属性需求。例如,软件工程知识体系(SWEBOK)指出,质量属性需求与其他任何需求一样:如果它们很重要,就必须被捕获,并且应该明确指定且可测试。
但在实践中,我们很少看到对质量属性需求的充分捕获。你有多少次看到过 “系统应具有模块化” 或 “系统应具有高可用性” 或 “系统应满足用户的性能期望” 这样的需求?这些都不是有用的需求,因为它们不可测试;它们不可证伪。但是,从好的方面看,它们可以被视为邀请架构师开始讨论这些领域的真正需求是什么。
-
即使是最好的需求文档中也找不到对架构师有用的很多内容。许多驱动架构的关注点根本不会在正在被指定的系统中作为可观察的事物显现出来,因此也不是需求规格说明的主题。架构重要需求通常源自开发组织本身的业务目标;我们将在 第 19.3 节 中探讨这种联系。开发质量也不在范围内;例如,你很少会看到描述团队合作假设的需求文档。在采购环境中,需求文档代表采购方的利益,而不是开发方的利益。利益相关者、技术环境和组织本身都在影响架构方面发挥作用。当我们在 第 20 章 中讨论架构设计时,我们将更详细地探讨这些需求。
从需求文档中找出架构重要需求
虽然需求文档不能向架构师讲述完整的故事,但它们仍然是架构重要需求的一个重要来源。当然,架构重要需求不会被方便地标记出来;架构师应该预期进行一些调查和挖掘工作以找出它们。
一些具体要寻找的信息类别如下:
- 使用情况:用户角色与系统模式、国际化、语言差异。
- 时间方面:及时性和元素协调。
- 外部元素:外部系统、协议、传感器或执行器(设备)、中间件。
- 网络方面:网络属性和配置(包括其安全属性)。
- 编排方面:处理步骤、信息流。
- 安全属性:用户角色、权限、认证。
- 数据方面:持久性和时效性。
- 资源方面:时间、并发性、内存占用、调度、多用户、多活动、设备、能源使用、软资源(例如缓冲区、队列)以及可扩展性需求。
- 项目管理方面:团队组建计划、技能组合、培训、团队协调。
- 硬件选择方面:处理器、处理器系列、处理器的演进。
- 功能灵活性、可移植性、校准、配置。
- 指定的技术、商业软件包。
任何关于它们计划或预期演进的已知信息也将是有用的信息。
这些类别不仅本身在架构上具有重要意义,而且每一个的可能变化和演进也很可能在架构上具有重要意义。即使你正在挖掘的需求文档没有提到演进,也要考虑前面列表中的哪些项目可能随时间而变化,并相应地设计系统。
19.2 通过访谈利益相关者收集架构重要需求
假设你的项目没有生成一份全面的需求文档。或者也许有需求文档,但在你需要开始设计工作的时候,质量属性需求还没有确定下来。你该怎么办呢?
首先,利益相关者通常不知道他们的质量属性需求实际上是什么。在这种情况下,架构师被要求帮助为系统设定质量属性需求。认识到这种合作需求并鼓励合作的项目比不这样做的项目更有可能成功。珍惜这个机会!不断地纠缠你的利益相关者也不会突然让他们拥有必要的洞察力。如果你坚持要定量的质量属性需求,你可能会得到一些随意的数字,而且至少其中一些需求将很难满足,最终实际上会减损系统的成功。
有经验的架构师通常对类似系统所表现出的质量属性响应有深刻的见解,并且知道在当前情况下哪些质量属性响应是合理预期和可以提供的。架构师通常也可以快速反馈哪些质量属性响应容易实现,哪些可能有问题甚至难以实现。
例如,利益相关者可能要求 24/7 的可用性 —— 谁不想要呢?然而,架构师可以解释这个需求可能要花费多少成本,这将给利益相关者提供信息,以便在可用性和可负担性之间进行权衡。此外,架构师是对话中唯一可以说 “我实际上可以交付一个比你想象中更好的架构 —— 这对你有用吗?” 的人。
访谈相关利益相关者是了解他们所知道的和需要的最可靠方法。再次强调,一个项目应该以系统、清晰和可重复的方式捕获这些关键信息。可以通过许多方法从利益相关者那里收集这些信息。其中一种方法是质量属性研讨会(QAW),如侧边栏中所述。
质量属性研讨会
质量属性研讨会(QAW)是一种在软件架构完成之前,以促进者引导、以利益相关者为中心的方法,用于生成、确定优先级并细化质量属性场景。它强调系统级别的关注点,特别是软件在系统中将发挥的作用。QAW 非常依赖系统利益相关者的参与。
在介绍和概述研讨会步骤之后,QAW 包括以下要素:
- 业务 / 任务介绍:代表系统背后业务关注点的利益相关者(通常是经理或管理代表)花费大约一小时介绍系统的业务背景、广泛的功能需求、约束和已知的质量属性需求。在后续步骤中将要细化的质量属性将主要从本步骤中介绍的业务 / 任务需求中得出。
- 架构计划介绍:虽然可能不存在详细的系统或软件架构,但有可能已经创建了广泛的系统描述、上下文图或其他工件,这些描述了系统的一些技术细节。在研讨会的这个时候,架构师将介绍现有的系统架构计划。这让利益相关者了解现有的架构思路。
- 确定架构驱动因素:促进者将分享他们在前两个步骤中整理的关键架构驱动因素列表,并请利益相关者进行澄清、添加、删除和更正。目的是就一份精简的架构驱动因素列表达成共识,其中包括总体需求、业务驱动因素、约束和质量属性。
- 场景头脑风暴:每个利益相关者表达一个场景,代表他们对系统的关注点。促进者通过指定明确的触发事件和响应来确保每个场景都解决了一个质量属性关注点。
- 场景整合:在场景头脑风暴之后,在合理的情况下整合相似的场景。促进者要求利益相关者识别那些内容非常相似的场景。只要提出这些场景的人同意并且觉得他们的场景在这个过程中不会被淡化,相似的场景就可以合并。
- 场景优先级确定:场景的优先级确定是通过给每个利益相关者分配一定数量的选票来完成的,选票数量等于整合后生成的场景总数的 30%。利益相关者可以将他们的任何数量的选票分配给任何一个场景或场景组合。对选票进行计数,并相应地确定场景的优先级。
- 场景细化:在确定优先级之后,对最重要的场景进行细化和详细阐述。促进者帮助利益相关者将场景放入我们在 第 3 章 中描述的六部分场景形式,即来源 - 触发事件 - 制品 - 环境 - 响应 - 响应度量。随着场景的细化,围绕其满足的问题将会出现,应该被记录下来。这个步骤持续的时间取决于时间和资源的允许。
利益相关者访谈的结果应包括一份架构驱动因素列表和一组由利益相关者(作为一个群体)确定优先级的质量属性场景。此信息可用于以下目的:
- 细化系统和软件需求。
- 理解并澄清系统的架构驱动因素。
- 为架构师随后做出某些设计决策提供理由。
- 指导原型和模拟的开发。
- 影响架构开发的顺序。
我不知道那个需求应该是什么
在采访利益相关者并探寻架构重要需求时,他们常常抱怨 “我不知道那个需求应该是什么”,这种情况并不少见。虽然他们确实有这样的感受,但他们通常也对这个需求有所了解,特别是如果利益相关者在该领域有经验的话。在这种情况下,引出他们的 “某些了解” 远比你自己凭空编造需求要好得多。例如,你可以问:“系统对这个交易请求应该多快做出响应?” 如果回答是 “我不知道”,我的建议是装糊涂。你可以说:“那么……24 小时可以吗?” 通常得到的回应是愤怒和惊讶的 “不!”“那么,1 小时怎么样?”“不!”“5 分钟呢?”“不!”“10 秒钟怎么样?”“嗯,(嘟囔,咕哝)我想我可以接受类似这样的……”
通过装糊涂,你常常可以让人们至少给你一个可接受的值的范围,即使他们不知道需求的确切值应该是多少。而这个范围通常足以让你选择架构机制。对架构师来说,24 小时、10 分钟、10 秒钟和 100 毫秒的响应时间意味着选择非常不同的架构方法。有了这些信息,你现在就可以做出明智的设计决策了。
—RK
19.3 通过理解业务目标收集架构重要需求
业务目标是构建一个系统的存在理由。没有一个组织会毫无理由地构建一个系统;相反,参与其中的人希望推进他们的组织以及他们自己的使命和抱负。常见的业务目标当然包括盈利,但大多数组织所关心的远不止盈利这一点。在其他一些组织中(例如非营利组织、慈善机构、政府部门),盈利是最不被考虑的事情。
业务目标对架构师来说很有意义,因为它们常常直接导致架构重要需求。业务目标和架构之间有三种可能的关系:
- 业务目标常常导致质量属性需求。每一个质量属性需求 —— 比如用户可见的响应时间、平台灵活性、坚如磐石的安全性或者其他十几种需求中的任何一种 —— 都源于某种更高的目的,可以用附加值来描述。想要使一个产品与竞争对手区分开来并让开发组织占领市场份额的愿望可能会导致对看起来异常快速的响应时间的需求。此外,了解一个特别严格的需求背后的业务目标,能使架构师以有意义的方式质疑这个需求 —— 或者调集资源来满足它。
- 业务目标可能影响架构而根本不产生质量属性需求。一位软件架构师告诉我们,几年前他向他的经理提交了一份架构的早期草案。经理指出架构中缺少一个数据库。架构师很高兴经理注意到了这一点,并解释了他(架构师)是如何设计出一种方法,从而避免了使用庞大而昂贵的数据库的需求。然而,经理坚持要求设计中包含一个数据库,因为组织有一个数据库部门,雇用了一些高薪的技术人员,他们目前没有任务,需要工作。没有任何需求规格说明会捕获这样的需求,也没有任何经理会允许这样的动机被捕获。然而,从经理的角度来看,如果那个架构在没有数据库的情况下被交付,就会像没有交付一个重要功能或质量属性一样有缺陷。
- 业务目标对架构没有影响。并非所有的业务目标都会导致质量属性。例如,“降低成本” 的业务目标可以通过在冬天降低设施的恒温器温度或者降低员工的工资或养老金来实现。
图 19.1 说明了本次讨论的主要观点。在图中,箭头表示 “导致”。实线箭头突出了对架构师最有意义的关系。
图 19.1 一些业务目标可能会导致质量属性需求,或者直接导致架构决策,或者导致非架构性的解决方案。
架构师通常通过潜移默化的方式 —— 工作、倾听、交谈以及吸收组织中正在起作用的目标 —— 来了解组织的业务和业务目标。潜移默化并非没有好处,但确定这些目标的更系统的方法既是可能的也是可取的。此外,明确地捕获业务目标是值得的,因为它们常常隐含着架构重要需求,否则这些需求在发现时可能已经太晚或者解决成本太高。
一种实现这一目标的方法是采用 PALM 方法,这需要架构师和关键业务利益相关者一起举办研讨会。PALM 的核心包括以下步骤:
- 引出业务目标。使用本节后面给出的类别来引导讨论,从利益相关者那里捕获这个系统的重要业务目标集合。详细阐述业务目标,并将其表示为业务目标场景。1 合并几乎相同的业务目标以消除重复。让参与者确定所得集合的优先级,以识别出最重要的目标。
- 从业务目标中识别潜在的质量属性。对于每个重要的业务目标场景,让参与者描述一个质量属性和响应度量值,如果将其构建到系统中,将有助于实现该目标。
在捕获业务目标的过程中,准备一组候选业务目标作为谈话的起点会很有帮助。例如,如果你知道许多企业都想获得市场份额,你可以利用这种动机让组织中的合适利益相关者参与进来:“对于这个产品,我们在市场份额方面的雄心是什么,架构如何能为实现这些目标做出贡献?”
我们对业务目标的研究使我们采用了如下列表中所示的类别。这些类别可以作为头脑风暴和引出目标的辅助工具。通过使用类别列表,并询问利益相关者每个类别中可能的业务目标,可以获得一定程度的覆盖保证。
- 组织的成长和连续性
- 实现财务目标
- 实现个人目标
- 对员工负责
- 对社会负责
- 对国家负责
- 对股东负责
- 管理市场地位
- 改进业务流程
- 管理产品的质量和声誉
- 管理环境随时间的变化
19.4 在效用树中捕获架构重要需求
在一个完美的世界中,19.2 节 和 19.3 节 中描述的技术会在你的开发过程早期就被应用:你会采访关键利益相关者,引出他们的业务目标和驱动架构的需求,并让他们为你确定所有这些输入的优先级。当然,遗憾的是,现实世界并不完美。通常情况下,由于组织或业务原因,当你需要这些利益相关者时,你却无法接触到他们。那么你该怎么办呢?
当需求的 “主要来源” 不可用时,架构师可以使用一种称为 “效用树” 的结构。效用树是一种自上而下的表示,展示了你作为架构师认为对系统成功至关重要的与质量属性相关的架构重要需求。
效用树以 “效用” 一词作为根节点。效用是系统整体 “良好程度” 的一种表达。然后,你通过列出系统需要展现的主要质量属性来详细阐述这个根节点。(你可能还记得我们在 第 3 章 中说过,质量属性名称本身并不是很有用。别担心 —— 它们只是作为后续阐述和细化的中间占位符被使用!)
在每个质量属性下,记录该质量属性的具体细化内容。例如,性能可以分解为 “数据延迟” 和 “事务吞吐量”,或者也可以是 “用户等待时间” 和 “网页刷新时间”。你选择的细化内容应该是与你的系统相关的。在每个细化内容下,你可以接着记录具体的架构重要需求,以质量属性场景的形式表示。
一旦架构重要需求以场景的形式被记录下来并放置在树的叶子节点上,你就可以根据两个标准来评估这些场景:候选场景的业务价值和实现它的技术风险。你可以使用任何你喜欢的尺度,但我们发现一个简单的 “H”(高)、“M”(中)和 “L”(低)评分系统对于每个标准来说就足够了。对于业务价值,“高” 表示必须具备的需求,“中” 表示重要但如果省略也不会导致项目失败的需求,“低” 表示满足起来很好但不值得付出太多努力的需求。对于技术风险,“高” 意味着满足这个架构重要需求会让你夜不能寐,“中” 表示满足这个架构重要需求令人担忧但风险不高,“低” 表示你有信心满足这个架构重要需求。
表 19.1 展示了一个医疗领域系统的效用树的一部分示例。每个架构重要需求都标有其业务价值和技术风险的指示。
表 19.1 医疗领域系统的效用树的表格形式
质量属性 | 属性细化 | ASR 场景 |
---|---|---|
性能 | 事务响应时间 | 一个用户在系统处于峰值负载时响应地址变更通知来更新患者的账户,并且该事务在不到 0.75 秒内完成。(高业务价值,高风险)。 |
吞吐量 | 在峰值负载下,系统每秒能够完成150个标准化事务。(中价值,中风险) | |
易用性 | 熟练度训练 | 有两年或以上业务经验的新员工经过一周的培训,可以在不到 5 秒内执行该系统的任何核心功能。(中价值,低风险)。 |
运营效率 | 一名医院收费员在与患者互动的同时为患者启动支付计划,并在没有输入错误的情况下完成该流程。(中价值,中风险)。 | |
可配置性 | 数据可配置性 | 一家医院提高了某项服务的费用。配置团队在一个工作日内完成变更并进行测试;无需更改源代码。(高价值,低风险)。 |
可维护性 | 例行更改 | 一名维护人员遇到响应时间不足的问题,修复了这个错误,并发布了错误修复,所花费的努力不超过 3 个人工日。(高价值,中风险)。 |
一项报告要求需要对生成报告的元数据进行更改。更改在 4 个人工时内完成并进行测试。(中价值,低风险)。 | ||
升级到商业组件 | 数据库供应商发布了一个新的主要版本,该版本在不到 3 个人周的时间内成功进行了测试和安装。(高价值,中风险)。 | |
添加新功能 | 一个追踪血库捐赠者的功能在 2 个人月内被创建并成功集成。(中价值,中风险)。 | |
安全 | 保密性 | 物理治疗师被允许查看患者病历中与骨科治疗相关的部分,但不能查看其他部分或任何财务信息。(高价值,中风险)。 |
抵御攻击 | 系统抵御未经授权的入侵尝试,并在 90 秒内向有关部门报告该尝试。(高价值,中风险)。 | |
可用性 | 无停机时间 | 数据库供应商发布新软件,该软件被热插拔到位,没有停机时间。(高价值,中低风险)。 |
该系统支持患者全年无休(24/7/365)通过网络访问账户。(中价值,中风险)。 |
一旦你填好了效用树,就可以用它来进行重要的检查。例如:
- 没有任何 ASR 场景的 QA(质量属性)或 QA 细化不一定是需要纠正的错误或遗漏,而是表明你应该调查在那个区域是否存在未记录的 ASR 场景。
- 获得(高价值,高风险)评级的 ASR 场景显然是最值得你关注的;这些是重要需求中最为重要的。大量这样的场景可能会让人担心这个系统实际上是否可实现。
19.5 变化总会发生
爱德华・贝拉尔说过:“如果两者都被冻结,那么在水面上行走和根据规格开发软件都很容易。” 本章中的任何内容都不应被认为这种神奇的情况有可能存在。需求(无论是否被捕获)一直在变化。架构师必须适应并跟上变化,以确保他们的架构仍然是正确的,能够为项目带来成功。在 第 25 章 中,我们讨论架构能力时,我们会建议架构师需要成为出色的沟通者,这意味着要成为出色的双向沟通者,既要接收信息也要提供信息。始终与确定 ASR 的关键利益相关者保持沟通渠道畅通,这样你就可以跟上不断变化的需求。本章提供的方法可以重复应用以适应变化。
比跟上变化更好的是领先变化一步。如果你听到 ASR 即将发生变化的风声,你可以采取初步措施进行针对该变化的设计,作为理解其影响的练习。如果这个变化的成本高得令人望而却步,与利益相关者分享这个信息将是一个有价值的贡献,而且他们越早知道越好。更有价值的可能是提出一些在满足目标方面(几乎)同样有效的但又不会超出预算的变更建议。
19.6 小结
架构是由具有架构重要性的需求所驱动的。一个架构重要需求(ASR)必须具备:
- 对架构有深远影响。包含这个需求很可能会导致与不包含它时不同的架构。
- 具有高业务或任务价值。如果架构要满足这个需求(可能以不满足其他需求为代价)那么它对重要的利益相关者必须具有高价值。
架构重要需求可以从需求文档中提取,可以在研讨会(例如,质量属性研讨会(QAW))期间从利益相关者那里捕获,可以在效用树中从架构师那里捕获,或者从业务目标中推导出来。将它们记录在一个地方是很有帮助的,这样可以对列表进行审查、参考,用于证明设计决策的合理性,并在随着时间的推移或在重大系统变更的情况下重新审视。
在收集这些需求时,你应该留意组织的业务目标。业务目标可以用一种常见的、结构化的形式表达,并表示为业务目标场景。可以使用 PALM(一种结构化的引导方法)来引出并记录这些目标。
质量属性(QA)需求的一种有用表示是效用树。这样的图形描述有助于以结构化的形式捕获这些需求,从粗略、抽象的质量属性概念开始,逐渐细化到以场景的形式捕获它们。然后对这些场景进行优先级排序,这个优先级集合作为架构师的 “行动指令”。
19.7 扩展阅读
可在opengroup.org/togaf/获取的开放组架构框架提供了一个完整的模板,用于记录包含大量有用信息的业务场景。尽管我们认为架构师可以使用更轻量级的方法来捕获业务目标,但它值得一看。
质量属性研讨会的权威参考资料是 [Barbacci 03]。
“架构重要需求” 这一术语是由软件架构审查与评估(SARA)小组创造的,作为可在 http://pkruchten.wordpress.com/architecture/SARAv1.pdf 检索到的文档的一部分。
《软件工程知识体系》(SWEBOK)第三版可在此处下载:computer.org/education/bodies-of-knowledge/software-engineering/v3。在我们付印之时,第四版正在开发中。
关于 PALM 的完整描述 [Clements 10b] 可在此处找到:https://resources.sei.cmu.edu/asset_files/TechnicalNote/2010_004_001_15179.pdf。
19.8 问题讨论
1. 采访你所在公司或大学正在使用的业务系统的具有代表性的利益相关者,并为其确定至少三个业务目标。为此,请使用 “扩展阅读” 部分中提到的 PALM 的七部分业务目标场景大纲。
2. 根据你在问题 1 中发现的业务目标,提出一组相应的架构重要需求(ASR)。
3. 为自动取款机(ATM)创建一个效用树。(如果你希望你的朋友和同事提供质量属性方面的考虑和场景,可以采访他们。)考虑至少四种不同的质量属性。确保你在叶节点创建的场景有明确的响应和响应度量。
4. 找到一个你认为高质量的软件需求规格说明。使用彩色笔(如果文档是打印的,就用真正的彩色笔;如果文档是在线的,就用虚拟的彩色笔),将你认为与该系统的软件架构完全无关的所有内容涂成红色。将你认为可能相关但需要进一步讨论和阐述的所有内容涂成黄色。将你确定具有架构重要性的所有内容涂成绿色。当你完成后,文档中除了空白部分之外的每一部分都应该是红色、黄色或绿色。你的文档最终每种颜色大约占多少百分比?结果让你感到惊讶吗?
业务目标场景是一种结构化的七部分表达式,用于捕获业务目标,在意图和用途上与质量属性场景类似。本章的“进一步阅读”部分包含一个参考资料,它详细描述了 PALM 和业务目标场景。 ↩︎
相关文章:

19. 架构重要需求
文章目录 第19章 架构重要需求19.1 从需求文档中收集架构重要需求(ASRs)不要抱太大希望从需求文档中找出架构重要需求 19.2 通过访谈利益相关者收集架构重要需求19.3 通过理解业务目标收集架构重要需求19.4 在效用树中捕获架构重要需求19.5 变化总会发生…...
iOS 再谈KVC、 KVO
故事背景:大厂面试,又问道了基本的kvc kvo的原理和使用,由于转了前端,除了个setter和getter,我全忘记了,其实还是没有理解记忆,下面再看一下kvc 和kvo ,总结一个让人通过理解而无法忘记的方法&a…...

java、excel表格合并、指定单元格查找、合并文件夹
#创作灵感# 公司需求 记录工作内容 后端:JAVA、Solon、easyExcel、FastJson2 前端:vue2.js、js、HTML 模式1:合并文件夹 * 现有很多文件夹 想合并全部全部的文件夹的文件到一个文件夹内 * 每个部门发布的表格 合并全部的表格为方便操作 模…...

最基础版编译运行Java(纯小白)
流程图: ⚠ 需要先安装JDK (Java Development Kit) 1. 写文件 首先写好自己的“文件”,可以用Sublime Text等文本编辑器写,还可以直接新建文本文档写一个.txt文件。 以编写一个HelloWorld程序为例: public class HelloWorld{p…...

六西格玛项目助力,手术机器人零部件国产化稳中求胜——张驰咨询
项目背景 XR-1000型腔镜手术机器人是某头部手术机器人企业推出的高端手术设备,专注于微创手术领域,具有高度的精确性和稳定性。而XR-1000型机器人使用的部分核心零部件长期依赖进口,特别是高精度电机、关节执行机构和视觉系统等,…...

Python爬虫系列(一)
目录 一、urllib 1.1 初体验 1.2 使用urllib下载网页、图片、视频等 1.3 反爬介绍 1.4 请求对象定制 1.5 get请求的quote方法 1.6 多个参数转成ascii编码 1.7 post请求 1.8 综合案例演示 一、urllib 1.1 初体验 # urllib是python默认带的,无需额外下载 i…...
# vim那些事...... vim删除文件全部内容
vim那些事… vim删除文件全部内容 1、在 Vim 中删除整个文件的内容,可以使用以下命令: 1)打开 Vim,并编辑你想要清空的文件。 2)按 Esc 确保你不在插入模式,而在命令模式。 3)输入 gg 跳转到…...
Selinux及防火墙
一,selinux简介: SELinux(Security-Enhanced Linux)是一个Linux内核安全模块,旨在提供强制访问控制(MAC)机制,以增强系统的安全性。由美国国家安全局(NSA)开…...

业绩代码查询实战——php
一、一级代码显示职员 foreach($data_职员信息 as $key > $value){//$where_查询分类$where_查询通用;//$dat分类one $业绩提成->where($where_查询分类)->order("CreateDate desc")->select();if($value[haschildname]0 && $value[key] !"…...
内网穿透技术选型PPTP(点对点隧道协议)和 FRP(Fast Reverse Proxy)
PPTP(点对点隧道协议)和 FRP(Fast Reverse Proxy)是两种实现内网穿透的技术,但它们的工作原理、使用场景和特点有很大区别。以下是它们的详细比较: PPTP(Point-to-Point Tunneling Protocol&am…...

信号与噪声分析——第三节:随机过程的统计特征
随机过程的定义: 随机过程是一种数学模型,用来描述系统或现象在时间或者空间上随之变化的不确定性。 一个随机过程的数字特征 1.数学期望(统计平均值): 表示为 数学期望是随机过程在时间 t 上的平均值,通常…...

nginx(四):如何在 Nginx 中配置以保留真实 IP 地址
如何在 Nginx 中配置以保留真实 IP 地址 1、概述2、nginx配置示例2.1、配置说明2.2、客户端获取真实IP2.2.1、代码说明 3、插曲4、总结 大家好,我是欧阳方超,可以我的公众号“欧阳方超”,后续内容将在公众号首发。 1、概述 当使用nginx作为…...
docker对nginx.conf进行修改后页面无变化或页面报错
可能是因为没有重启nginx容器 可以执行 docker restart nginx 重启nginx试试 引入了其他的配置文件 本人安装的是docker默认的nginx,自带了一个default.conf的配置文件,并且在nginx.conf中还引入了这个文件,后面我还对nginx.conf添加了一个…...
SpringCloudGateway — 网关路由
Spring Cloud Gateway 是 Spring 提供的一个高效、灵活的 API 网关解决方案,基于 Spring 5、Spring Boot 2 和 Project Reactor,具有高并发和低延迟的特点。它用于在微服务架构中对外提供统一的入口,处理请求的路由、过滤、负载均衡等功能。 …...

docker pull 拉取镜像失败,使用Docker离线包
1、登录并注册Github,然后在Github中搜索并打开“wukongdaily/DockerTarBuilder” 项目,在该项目主页点击“Fork”。 然后点 “Create Fork”,将项目创建到自己的Github主页。 2、接着在自己创建过来的这个项目中点击“Actions” 3、然后…...

轻松理解操作系统 - 轻松了解 inode 是如何管理文件的
Linux 由于其开源、比较稳定等特点统治了服务端领域。也因此,学习Linux 系统相关知识在后端开发等岗位中变得越来越重要,甚至可以说是必不可少的。 因为它的广泛应用,所以在程序员的日常工作和面试中,它都是经常出现的。它的开源特…...

go中Println和Printf的区别
Don’t worry , just coding! 内耗与overthinking只会削弱你的精力,虚度你的光阴,每天迈出一小步,回头时发现已经走了很远。 go中Println和Printf的区别 package mainimport ( "fmt" )//TIP To run your code, right-click the c…...

C++现代教程七之模块
优点 编译时间减少:模块消除了重复解析和编译头文件的需要,从而显著减少了编译时间。特别是在大型项目中,这一点尤为重要。更好的封装性:模块允许更严格的封装,可以明确地控制哪些符号对外可见。这有助于减少命名冲突和…...

AVLTree
1.AVL树的概念 二叉搜索树虽然可以提高查找的效率,但是如果数据有序或者接近有序,二叉搜索树将退化为单支树,查找元素相当于在顺序表中搜索元素,效率低下。为了解决该问题,于是就有了AVLTree。即当向二叉搜索树中插入…...

Java面向对象 C语言字符串常量
1. (1). package liujiawei;public class Phone {String brand;double price;public void call(){System.out.println("手机打电话");}public void play(){System.out.println("手机打游戏");} } public class phonetest {public…...

铭豹扩展坞 USB转网口 突然无法识别解决方法
当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…...

Vue3 + Element Plus + TypeScript中el-transfer穿梭框组件使用详解及示例
使用详解 Element Plus 的 el-transfer 组件是一个强大的穿梭框组件,常用于在两个集合之间进行数据转移,如权限分配、数据选择等场景。下面我将详细介绍其用法并提供一个完整示例。 核心特性与用法 基本属性 v-model:绑定右侧列表的值&…...

React19源码系列之 事件插件系统
事件类别 事件类型 定义 文档 Event Event 接口表示在 EventTarget 上出现的事件。 Event - Web API | MDN UIEvent UIEvent 接口表示简单的用户界面事件。 UIEvent - Web API | MDN KeyboardEvent KeyboardEvent 对象描述了用户与键盘的交互。 KeyboardEvent - Web…...
OpenPrompt 和直接对提示词的嵌入向量进行训练有什么区别
OpenPrompt 和直接对提示词的嵌入向量进行训练有什么区别 直接训练提示词嵌入向量的核心区别 您提到的代码: prompt_embedding = initial_embedding.clone().requires_grad_(True) optimizer = torch.optim.Adam([prompt_embedding...

视觉slam十四讲实践部分记录——ch2、ch3
ch2 一、使用g++编译.cpp为可执行文件并运行(P30) g++ helloSLAM.cpp ./a.out运行 二、使用cmake编译 mkdir build cd build cmake .. makeCMakeCache.txt 文件仍然指向旧的目录。这表明在源代码目录中可能还存在旧的 CMakeCache.txt 文件,或者在构建过程中仍然引用了旧的路…...

云原生安全实战:API网关Kong的鉴权与限流详解
🔥「炎码工坊」技术弹药已装填! 点击关注 → 解锁工业级干货【工具实测|项目避坑|源码燃烧指南】 一、基础概念 1. API网关(API Gateway) API网关是微服务架构中的核心组件,负责统一管理所有API的流量入口。它像一座…...

华为OD机考-机房布局
import java.util.*;public class DemoTest5 {public static void main(String[] args) {Scanner in new Scanner(System.in);// 注意 hasNext 和 hasNextLine 的区别while (in.hasNextLine()) { // 注意 while 处理多个 caseSystem.out.println(solve(in.nextLine()));}}priv…...
jmeter聚合报告中参数详解
sample、average、min、max、90%line、95%line,99%line、Error错误率、吞吐量Thoughput、KB/sec每秒传输的数据量 sample(样本数) 表示测试中发送的请求数量,即测试执行了多少次请求。 单位,以个或者次数表示。 示例:…...
怎么让Comfyui导出的图像不包含工作流信息,
为了数据安全,让Comfyui导出的图像不包含工作流信息,导出的图像就不会拖到comfyui中加载出来工作流。 ComfyUI的目录下node.py 直接移除 pnginfo(推荐) 在 save_images 方法中,删除或注释掉所有与 metadata …...
c# 局部函数 定义、功能与示例
C# 局部函数:定义、功能与示例 1. 定义与功能 局部函数(Local Function)是嵌套在另一个方法内部的私有方法,仅在包含它的方法内可见。 • 作用:封装仅用于当前方法的逻辑,避免污染类作用域,提升…...