作者 | Pierre Pureur, Kurt Bittner
译者 | 王强
策划 | Tina
要点
谈到软件架构,犯错是不可避免的。架构设计的艺术在于试错的时候只用一点时间。做出决定的唯一方法是进行实验并收集可以为这些决策提供信息的数据。
最小可行架构(MVA)由测试架构决策可行性的一些实验组成。这些实验收集反馈,使开发团队能够修改他们的决策。
MVA 也是关于其 MVP 的实验;它们从技术角度测试 MVP 的可行性。如果 MVP 在技术上不可行,那么 MVP 就没有业务价值。
实验不止是要尝试某种东西,看看它是否有效。每个产品版本都是一组关于价值和可支持性的实验。这些实验的反馈有助于开发团队提高产品的价值和可支持性。
架构实验还需要预测“支持和更改”方面的工作。
犯错令人沮丧、浪费资源,有时会让人很尴尬,但……这是不可避免的。尤其是在软件架构方面,如果你从不犯错,意味着你就没充分挑战自我,也没有学到东西。但犯错在心理上太痛苦了,所以大多数人都会避免犯错,主要的逃避方式就是从不检查他们的工作。
有些人认为,如果不构建出整个软件产品,他们就无法测试其架构。但软件架构不是一个单一的东西,它是许多决策的结果,其中每个决策都可以通过实验进行分离和评估。
虽然我们有时无法避免犯错,但我们可以通过运行很多小实验来测试我们的假设,并在错误决策的成本增加之前扭转它们,从而降低犯错的成本。但时间是我们的敌人:你永远没有足够的时间来测试每一个假设,因此搞清楚我们要面对哪些假设就是架构设计的艺术。
成功的架构设计意味着通过实验来测试影响系统架构的决策,即那些如果你犯错就会对你所构建的东西的成功造成“致命”影响的决策。
知道要测试什么只是问题的一半;另一半是设计有效但低成本的实验,以揭示假设中的缺陷。
这是我们称之为最小可行架构 (MVA) 的概念背后的关键思想,它是一组决策,你认为这些决策将使系统或产品的增量,即最小可行产品 (MVP),能够随着时间的推移持续提供价值。
在本文中,我们探讨了良好实验的属性。
MVA 是测试架构决策可行性的实验
在前文中,我们观察到:
了解这些决策是否合理的唯一方法是进行实验和收集数据。这些实验会测试 MVP 的可负担性、可行性、可持续性和可支持性。MVA 反映了开发团队为实现 MVP 的架构目标而做出的种种权衡。由于每个版本都是具有相关 MVA 的 MVP,因此每个版本都是一组关于价值和可支持性的实验。发布新版本的目的是向客户提供价值,并收集有关版本在多大程度上满足了客户需求的反馈,包括当前和系统的整个生命周期内的情况。
如果团队不进行架构实验,那么他们的决策就只是基于各种假设来猜测解决方案到底需要什么内容。如果猜测被证明是错误的,那么由于其影响,逆转它们的代价将非常高昂,甚至可能扼杀产品 / 项目。
例如,团队可能决定使用矢量数据库,使用机器学习技术为金融机构开发专有的欺诈检测服务。根据他们的研究,使用某种向量数据库产品可能会加快 MVP 的开发,而其中一名团队成员对该产品的经验有限。作为一项实验,他们决定使用该产品实现一个小型欺诈检测用例,并衡量生产率的提升幅度。
然而,事实证明,预期的生产率提升并未实现,因为该产品比预期的要难得多。向量数据库的编程接口与团队选择的编程范式不匹配,使用该产品实现性能目标也很有挑战性。根据他们的实验,团队意识到使用向量数据库会延迟甚至可能威胁到 MVP 的交付,因此他们决定不使用该产品。
MVA 也是测试
MVP 技术可行性的实验
可以这样理解 MVA,它由一个或多个实验组成,用于测试产品增量或 MVP 所提供价值的长期可持续性。正如我们在上一篇文章中所观察到的,最小可行产品(MVP)的概念可以帮助团队尽早专注于提供他们认为对客户最有价值的产品,这样他们就可以在投入大量时间和资源之前快速且廉价地评估其产品的市场规模。因此,每个 MVP 都是一组实验,用于测试产品增量为客户带来的价值。
MVA 很重要,因为 MVP 只是障眼法(或一厢情愿的想法),除非你拥有可以支持它的 MVA。我们已经目睹了许多例子,其中业务利益相关者提出了大胆的业务创新,但并未考虑如何或是否可以实现该想法。
MVP 不仅限于初创企业,因为每个应用程序都有一个可以视为 MVP 的初始版本。MVP 是产品开发战略的一个有用组成部分。与单纯的原型不同,MVP 并非简单地以“丢弃”为目标。
我们谈论 MVA 的方式有时会让人觉得它们是与 MVP 分开的实验,但事实并非如此,正如我们在之前的一篇文章中所讨论的那样。当开发团队致力于他们的 MVP 时,他们会不断做出关于产品如何实现其架构目标的架构决策。这些决策就是 MVA。
有效架构实验的特征
实验不仅是要尝试某件事以查看它是否有效;它是一种专门用于确认或拒绝特定假设的测试。假设是团队对其解决方案适用性所提出的问题的潜在答案。实验无法证明某件事是正确的,只能证明某件事是错误的,但这仍然很有用,因为这意味着如果你正确设计实验,就可以判断哪些假设是错误的——在它们引起不愉快的意外之前。
如果你不进行实验,意味着你会假设你已经知道了某些问题的答案。只要情况真的如此,或者只要出错的风险和成本很小,你可能就不需要进行实验。然而,一些大问题只能通过实验来回答。由于你可能无法对所有必须回答的问题都进行实验,意味着你会隐式地接受相关风险,因此你需要在可以进行的实验数量和无法通过实验减轻的风险之间做出权衡。
创建测试 MVP 和 MVA 的实验的挑战在于提出挑战利益相关者和开发人员的业务和技术假设的问题。这些实验必须足够小,以便快速收集反馈,但又足够重要,以应对团队面临的风险。
在 MVA 的语境下,这意味着要面对团队正在做出的架构决策可能被证明是错误的风险。团队执行这一流程是,首先要问自己:“我们做出的哪些决策如果被证明是错误的,将最具破坏性”和“哪些事件更有可能发生”。我们发现这种讨论很有用,但不需要很长;大多数团队都很清楚哪些决策让他们夜不能寐。
正如我们在 另一篇文章 中指出的那样,每个需求,包括驱动架构设计的质量属性需求(QAR),都代表着一个关于价值的假设。明确这些假设并有意识地设计实验有助于团队避免对其解决方案做出很多假设。
有效的架构实验是:
原子的。它们一次处理一个问题。同时进行多个实验会使结果混乱,并且往往会让重要的反馈来得更慢。
及时。它们将风险分解成很多小的、可管理的部分,以便更快获得反馈并简化结果的解释。
明确。它们有明确的成功标准和可衡量的结果。实验不是简单地尝试某件事来看看它是否有效。
为了帮助实现这一点,每个实验都需要:
一个明确的假设。为一家保险公司工作的团队正在考虑使用图像识别软件来检测火灾多发区的房屋在一定距离内是否有植被。他们假设该软件可以检测植被并测量其与建筑物的距离,以使用从卫星拍摄的图像评估火灾风险。
一个明确且可衡量的目标或指标。实验的目标是确定图像识别软件是否可以使用清晰的高分辨率卫星照片检测和识别特定房屋 30 英尺范围内的两棵灌木和一棵树。
运行实验的方法和衡量其成功或失败的机制。由于实验范围有限,并将尝试识别有明确定义的形状,因此它将使用预训练的图像识别模型,该模型只需要有限的训练。实验结果将对比房屋及其周围环境的地面照片,以验证模型的结果。
如果实验失败,则需要执行回滚计划。对于上述示例,由于实验是非破坏性的,不会改变现有数据的状态或内容,因此不需要回滚计划。在某些代码更改的情况下,如果实验失败,就可能需要恢复到以前的代码版本。在其他情况下,实验必须在部署给客户的版本中进行。例如,如果实际使用反馈对于收集决策所需的数据至关重要,团队就需要一种方法来使用 A/B 测试等技术来回滚更改,或者在实验失败时快速重新部署系统。
实验的明确时间表。由于我们的工作周期很短,因此实验需要符合发布的时间限制。在 Scrum 等敏捷方法的背景下,实验需要在一个 Sprint 内完成。如果实验太难在开发和测试发布的时间范围内完成,你必须将其分解为一些较小的实验。
有时实验无法达到预期结果,团队可能会倾向于延长实验时间,以便有时间改进解决方案。这应该是一个新的实验,而不是旧实验的延伸。考虑上述图像识别实验的情况。团队可能会倾向于相信额外的模型训练可以改善结果并使实验成功。但这应该被视为一个单独的实验。
有些实验可能需要团队购买硬件或软件,聘请(即使只是暂时的)具有所需专业知识的人,或购买他们没有的计算资源(如云或测试环境)。在这些情况下,他们可能需要预算和资金批准。
架构回顾可以帮助团队考虑他们是否做了足够的实验,或者可能做了太多的实验。不做实验的问题很明显,但做太多实验也同样糟糕;如果一个决定是否错误并不重要,那么这个决定实际上不是架构性的,而只是一种不同的设计选择。
架构实验还需要预测“支持和变更”工作
我们很重视软件系统中的模块化,因为它使系统更容易扩展和发展。但就像建筑物一样,如果构思或执行不当,对软件系统的连续更改最终可能会压垮系统并降低其长期可行性。良好的软件架构可以预测变化,并使某些类型的变化更容易、破坏性更小。但团队如何知道在预测和缓解未来变化方面要投入多少资金?他们如何知道他们在这方面的工作是否成功?
与其他类型的架构决策一样,唯一的方法是做一些实验,重点评估某些类型变化的成本和影响。例如,考虑一个保险承保系统,该系统处理特定类型的承保资产(例如家用家具)和特定类型的损失事件(例如火灾)。对于开发该系统的团队来说,一种很有用的方法是考虑添加一种新的受保资产(例如艺术品)和一种新的损失事件(例如盗窃)的难易程度。他们可能会发现某些类型的更改很容易,而其他类型的更改则需要全新的系统。
这是房主保险不涵盖汽车的原因之一,因为解决索赔的风险和决策标准差异太大,一个系统无法适用于每种资产和每种风险。了解变更的界限是一项重要的架构决策。
架构工作还必须考虑系统将如何随着时间的推移得到支持。当它失败时,它是否提供了足够的信息来诊断问题?回答这个问题需要了解支持人员的专业知识以及可能导致故障的事件类型。有时,了解这一点的唯一方法是运行旨在导致系统失败的实验,以查看系统如何反应以及在系统失败后需要哪些信息来解决问题。
例如,保险公司的汽车保单系统通常会使用规则引擎为公司客户定制保险并为其定价。配置和测试规则通常是一项具有挑战性且耗时的任务。正如 Thomas Betts 在最近的中所建议的那样,使用大型语言模型(LLM)输入和验证这些规则将是一种让这项任务变得更容易和更快的好方法,前提是保险公司有足够的规则配置示例来训练 LLM。
然而,LLM 的输出有时很难解释,团队应该运行旨在让 LLM 生成“错误”信息的实验,以确保如果在生产中发生这种情况,他们也能诊断出问题。进行这种实验可能会避免系统实施后出现一些令人不快的意外。如果他们无法诊断问题,这可能会说服团队重新考虑他们基于 LLM 的方法。
总 结
软件架构工作并不总是可预测的;系统是复杂的实体,有时会以意想不到的方式运行。有时,了解预期行为和意外行为之间界限的唯一方法是做实验。MVA 的目标之一是提供一种运行架构实验的机制,以便开发团队能够了解他们的架构决策何时以及如何失败。有了更好的信息,开发团队可能会做出不同的选择,或者至少知道他们的假设何时可能失败。
当超出系统限制的风险很低时,开发团队可能会决定接受风险,但即使在这些情况下,他们也应该在设计系统时使其能够优雅地失败,并为支持人员或未来的开发团队成员提供足够的信息来解决问题,而不会因为解决方案而废弃系统的主要部分。
在软件架构中,有时出错是不可避免的;如果你从不犯错,那你就没有充分挑战自我,也没有学到东西。最重要的是尽可能多地用挑战我们假设的实验来测试我们的决定,并以这样的方式构建系统,做到当我们的决定不正确时,系统不会灾难性地失败。
作者介绍
Pierre Pureur是一位经验丰富的软件架构师,拥有丰富的创新和应用开发背景、广泛的金融服务行业经验、广泛的咨询经验和全面的技术基础设施知识。他过去的职位包括担任一家大型金融服务公司的首席企业架构师、领导大型架构团队、管理大型并发应用开发项目和指导创新计划,以及制定战略和业务计划。他是《实践中的持续架构:敏捷和 DevOps 时代的可扩展软件架构》(2021 年)和《持续架构:敏捷和以云为中心的世界中的可持续架构》(2015 年)两本书的合著者,并发表了许多关于这个主题的文章,还在多个软件架构会议上发表演讲。
Kurt Bittner 拥有 30 多年的经验,能够在短时间内以反馈为导向的周期交付可用的软件。他帮助各种各样的组织采用敏捷软件交付实践,包括大型银行、保险、制造和零售组织以及大型政府机构。他曾就职于或服务于 Oracle、HP、IBM 和 Microsoft 等大型软件交付组织。他还是 Forrester Research 的前技术行业分析师,并撰写了大量与敏捷团队和领导力相关的主题文章。
Software Architecture and the Art of Experimentation(https://www.infoq.com/articles/architecture-experimentation/)
声明:本文为 InfoQ 翻译,未经许可禁止转载。