作者:[美]伦·巴斯等
第2章为什么软件架构重要
如果架构是答案,那么问题是什么?
本章主要从技术角度讨论为什么架构重要。我们将研究13个重要原因。你可以利用它们来推动新架构的创建,或者对已有系统架构进行分析和优化。
1)架构可以抑制或支持系统的质量属性。
2)在架构中做出的决策允许你根据系统的发展进行推理和变更管理。
3)对架构的分析能够提前预测系统的质量。
4)文档化的架构增强了利益相关者之间的沟通。
5)架构是最早的,因此也是最基本的、最难改变的设计决策的载体。
6)架构定义了后续实现的一组约束。
7)架构决定了组织的结构,反之亦然。
8)架构可以为增量开发提供基础。
9)架构是允许架构师和项目经理推理成本和进度的关键制品。
10)架构可以作为一个可转移、可重用模型来创建,它构成了产品线的核心。
11)基于架构的开发将注意力集中在组件的合并上,而不是简单地关注组件的创建。12)通过限制设计的备选范围,架构引导开发人员的创造力,降低设计和系统复杂性。13)架构可以是培训新团队成员的基础。
即使你已经相信架构是重要的并且不必再强调13次,也可以将这13点(构成本章的大纲)视为在项目中使用架构的13种有用方法,或者用于证明架构投入是合理的。
2.1抑制或支持系统的质量属性
系统满足其期望的(或要求的)质量属性的能力实质上是由架构决定的。如果你想不起本书里的其他内容,那么请记住这一点。
这种关系是如此重要,以至于我们用了本书的第二部分来详细阐述这一信息。在此之前,请记住以下例子:
如果你的系统需要高性能,那么你需要关注管理元素基于时间的行为、它们对共享资源的使用以及元素间通信的频率和数量。
如果可修改性很重要,那么你需要关注将责任分配给元素,并限制这些元素的交互(耦合),以便系统的大多数变更只影响到这些元素中的少数。理想情况下,每个变更将只影响单个元素。
如果你的系统必须是高度防护的,那么你需要管理和保护组件间的通信,并控制哪些组件可以访问哪些信息。你可能还需要在架构中引入专门的元素(例如授权机制)来设置一个强大的“边界”以防止入侵。
如果你想让系统安全可靠,你需要设计保障措施和恢复机制。
如果你认为性能的可伸缩性对系统的成功非常重要,那么你需要将资源的使用本地化,以便引入更高容量资源来替换,并且必须避免在资源假设或资源限制中进行硬编码。
如果你的项目需要交付系统增量子集,那么你必须管理组件间的使用。
如果你想让系统中的元素在其他系统中可重用,那么你需要限制元素间的耦合,这样当你提取一个元素时,它不会带出太多与当前环境相关的内容。
针对这些和其他质量属性的策略是非常架构化的。但是,架构本身不能保证系统所需的功能或质量。糟糕的下游设计或实现决策总是会破坏合理的架构设计。就像我们常说的那样(多半是开玩笑):架构给予什么,实现就拿走什么。软件生命周期的所有阶段(从架构设计到编码、实现和测试)的决策都会影响系统质量。因此,质量并不完全是架构设计的一个功能,但它是起点。
2.2推理和变更管理
这是上面观点的推论。
可修改性—可以对系统进行变更的便捷程度,是一个质量属性(在前一节讨论过),但它是如此重要的一个属性,以至于我们在13个原因中专门提到了它。软件开发社区开始认识到这样一个事实:一个典型的软件系统大约80%的总成本发生在初始部署之后。人们使用的大多数系统都处于这个阶段。许多程序员和软件设计师从来没有从事新的开发工作—他们在现有架构和代码体的约束下工作。事实上,所有软件系统在其生命周期中都会发生变更,以适应新特性、新环境,修复bug等。但现实是,这些变更往往充满了困难。
每个架构,无论它是什么,都将可能的变更划分为三类:局部的、非局部的和架构的。局部变更可以通过修改单个元素来完成。例如,在定价逻辑模块中添加新的业务规则。
非局部变更需要对多个元素进行修改,但不会影响底层架构。比如,在定价逻辑模块添加一个新的业务规则,然后在数据库中添加业务规则所需的字段,并根据需要修改用户界面。架构变更会影响元素之间相互作用的基本方式,并可能需要对整个系统进行变更。
例如,将一个系统从单线程改变为多线程。显然,局部变更是最理想的,因此有效的架构中最常见的变更是局部的,因此很容易进行。非局部变更不是那么令人满意,但它们确实有一个优点,那就是它们通常可以分期进行,也就是说,随着时间的推移,以有序的方式展开。例如,你可能首先进行变更以添加新的定价规则,然后进行更改以实际部署新规则。
决定什么时候变更是至关重要的,决定哪些变更路径具有最小的风险,评估变更的影响,决定变更的顺序和优先级,都需要对软件元素的关系、性能和行为有着广泛的了解。这些任务都是架构师工作的一部分。对架构进行推理和分析提供了对预期变更做出决策所必需的洞察力。如果你不采取这一步,并且不注意维护架构的概念完整性,那么你几乎肯定会积累架构债。我们在第23章讨论这个问题。
2.3预测系统质量
这一点是由前两点引出的:架构不仅赋予系统质量属性,而且以可预测的方式进行。
这似乎是显而易见的,但事实并非如此。设计一个架构,做出一系列相当随意的设计决策,构建系统,测试质量属性,并期待最好的结果。哎呀—速度不够快,还不堪一击?开始被黑客攻击。
幸运的是,根据系统架构评估结果就可以对系统进行质量预测。如果我们知道某些类型的架构决策会支持系统中的某些质量属性,那么我们就可以做出那些决策,并理所当然地期望得到相应的质量属性回报。之后,当检查架构时,我们可以确定决策是否已经完成,并自信地预测架构将显示相应的品质。
这一点和前面的一点结合起来,意味着架构在很大程度上决定了系统质量,甚至更好!我们知道它是如何做到的,我们也知道如何让它做到。
即使你有时不执行必要的定量分析建模以确保能够交付符合要求的架构,这种基于质量属性含义的评估对于及早发现潜在的问题也是非常宝贵的。
2.4利益相关者之间的沟通
在第1章中提到,架构是一种抽象,这是有用的,因为它代表了整个系统的简化模型(与整个系统的无限细节相反),你可以记住它,团队里的其他人也可以记住它。架构是系统的公共抽象,大多数(如果不是全部的话)的利益相关者可以将它作为创建相互理解、协商、形成共识和彼此交流的基础。架构(或至少部分架构)是非常抽象的,大多数非技术人员,特别是在架构师的指导下,都可以理解它。而且这种抽象可以被细化为足够丰富的技术规范,以指导实现、集成、测试和部署。
软件系统的每一个利益相关者(客户、用户、项目经理、编码人员、测试人员等)都与受架构影响的不同系统特征有关。例如:
用户关心系统是否快速、可靠且在需要时可用。
客户(为系统付费的人)关心架构可以按计划和预算实施。
管理者关心架构(除了成本和进度方面之外)是否最大限度允许团队独立工作,以有纪律和受控的方式进行交互。
架构师关心实现所有这些目标的策略。
架构提供了可以表达、协商和解决不同问题的通用语言,甚至对于大型复杂系统也是这样的。如果没有这样的通用语言,就很难充分理解大型系统,从而导致做出影响质量的早期决策。正如我们将在第21章中看到的,架构分析既依赖于某个层面的沟通,又增强了这个沟通。
关于架构文档的第22章更深入地介绍了利益相关者及其关注的问题。
“当我按下这个按钮时会发生什么”:架构作为利益相关者沟通的工具
项目审查没完没了地进行。政府资助的项目落后于计划,超出了预算,而且项目大到足以引起美国国会的注意。现在政府正在通过马拉松式的一对一评审来弥补过去的疏忽。承包商最近接受了一次买断,但情况也没改善。那是第二天的下午,会议议程要求展示软件架构。这位年轻的架构师(系统总架构师的学徒)勇敢地解释了大规模系统的软件架构如何能够满足实时、分布式、高可靠性的要求。他有一个扎实的陈述和一个扎实的架构。这是合情合理的。听众是大约30名政府代表,他们在这个棘手的项目中承担着不同的管理和监督角色,他们已经厌倦了。他们中的一些人甚至在想,也许应该进入房地产业,而不是忍受另一场马拉松式的“让我们终于把事情做对了”的评审。
幻灯片以半正式的框线符号展示了系统运行时的主要软件元素。年轻的架构师说,这些名字都是首字母缩写,未经解释,没有任何语义。这些线显示了数据流、消息传递和流程同步。正如架构师所解释的那样,这些元素在内部是冗余的。“如果发生故障,”他用激光笔标出其中一条线说,“就会沿着这条路径触发一个重启装置,当……”
“当按下模式选择按钮时会发生什么?”一位听众打断了他的话。他是代表这个系统的用户的政府与会者。
“您能再说一遍吗?”架构师问。
他说:“模式选择按钮,当你按它的时候会发生什么?”
“嗯,这会触发设备驱动程序中的一个事件,在这里,”架构师开始用激光笔,“然后读取注册表并解释事件代码。如果是模式选择,它向黑板发出信号,黑板又向订阅了该事件的对象发出信号……”
“不,我是说系统做了什么。”提问者打断了他,“它会重置显示器吗?如果在系统重新配置时出现这种情况会发生什么?”
架构师看起来有点惊讶,甩掉了激光笔。这不是一个架构问题,但由于他是一个架构软件架构实践师,因此对需求很熟悉,所以他知道答案。他说:“如果命令行处于设置模式,显示器将重置。否则,一个错误消息将被显示在控制台上,但信号将被忽略。”他把激光笔放回去,说:“我刚才说的重启机制……”
“嗯,我只是想知道,”用户代表说,“因为我从你的图表上看到,显示器正在向目标位置模块发送信号。”“会发生什么?”另一位听众对第一个提问者问道,“你真的希望用户在重新配置时获得模式数据吗?”在接下来的45min,架构师看着观众占用着他的时间争论在各种深奥的状态下系统的正确行为应该是什么—这是一个绝对必要且应该在需求制定的时候就应该明确的问题,但是,不知出于什么原因没有明确。争论的焦点不是架构,但架构(以及它的图形化呈现)引发了争论。
很自然地,我们可以把架构看作交流的基础—在架构师和开发人员之外的一些利益相关者之间进行交流,例如,管理人员使用架构来创建团队并分配资源。但是用户呢?毕竟,架构对用户是不可见的,为什么他们要把架构作为理解系统的工具?
事实是他们确实如此。在这个例子中,提问者已经坐了两天的时间查看了所有关于功能、操作、用户界面和测试的图表。尽管他很累,想回家,但第一张关于架构的幻灯片让他意识到自己有些东西不懂。参加了许多架构评审使我确信,以一种新的方式来看待系统会刺激人们的思维,并带来新的问题。
对于用户来说,架构通常是一种新的方式。用户提出的问题本质上是与行为有关的,在几年前的一个令人难忘的架构评审中,用户代表对系统将要做什么更感兴趣,而不是它将如何做,而且很自然地是这样。在那之前,用户与供应商的唯一联系是后者营销人员。架构师是用户可以接近的第一个合法的系统专家,他们会毫不犹豫地抓住这个机会。
当然,详细和彻底的需求规范将改善这一点,但由于各种原因,需求并不总是明确或可用的。如果缺少这样的需求规范,架构规范通常有助于引发问题并提高需求清晰度。认识到这种可能性要比抵制它更为明智。
有时,这样的演练会暴露出不合理的需求,然后可以重新审视这些需求的效用。这种类型的评审强调需求和架构之间的协同作用,通过在整个评审会议中为年轻的架构师提供处理这类信息的机会,可以让故事中的年轻架构师摆脱困境。而用户代表也不会觉得像离开了水的鱼,在一个明显不合适的时间问他的问题。—PCC
2.5早期设计决策
软件架构是关于系统的早期设计决策的体现,这些早期约束对于系统后续开发、部署和维护具有巨大的影响。这也是对这些影响系统的重要设计决策进行详细评审的最早时间点。
在任何规程中的任何设计都可以看作一系列决策。在作画时,甚至在开始作画之前,艺术家就开始决定画布和材料—油彩、水彩还是蜡笔。一旦开始作画,就会相应做出其他的决定:第一条线在哪里,它的宽度是多少,它的形状是什么?所有这些早期的决策都对最终画面的外观有很大的影响,并且每个决策都限制了接下来的许多决策。每一个单独的决策可能看起来都是无关紧要的,但早期的决策尤其具有不成比例的重要性,因为它们影响和限制了接下来的许多事情。
架构设计也是如此。架构设计也可以看作一系列的决策。就现在必须改变的额外决策而言,改变这些早期的决策将会引起连锁反应。是的,有时架构必须重构或重新设计,但这不是一项轻松的任务,因为一片雪花就可能引发雪崩。
软件架构体现了哪些早期设计决策?想想看:
系统是运行在一个处理器上还是分布在多个处理器上?软件是分层的吗?如果是,分几层?每层做什么?组件间是同步通信还是异步通信?它们是通过控制流或数据流交互,还是两者兼而有之?流经系统的信息会被加密吗?使用哪种操作系统?选择哪种通信协议?
想象一下,如果你不得不改变其中一个或其他相关决策,而这样的决策一开始就决定了架构的某些结构及其交互方式,那么改变决策将是一场噩梦。
2.6实现约束
如果你希望实现是符合架构的,那么它必须符合架构规定的设计决策,包括必须具有架构所规定的元素集,元素之间必须以架构所规定的方式相互交互,并且每个元素必须按照架构规定履行其职责。每一个规定都是对实现者的约束。
元素构建者必须熟悉元素对应的规范,他们可能不了解整体架构权衡点—架构(或架构师)只是以满足权衡的方式约束元素构建者。性能约束分配是一个经典的例子,架构师常常将一个大功能的性能约束分配给涉及的软件单元。如果每个单元都满足约束,那么整体也将满足。而每个组成部分的实现者可能不知道整体性能约束,而只知道他们自己的。
相反,架构师不需要精通算法设计的所有方面或复杂的编程语言。当然,他们应该有足够的知识,避免设计出难以实现的东西。架构师是负责建立、分析和执行架构决策并进行权衡的人。
2.7对组织结构的影响
架构不仅规定了正在开发系统的结构,而且深刻影响开发项目的结构(有时是整个组织的结构)。在一个大型项目中,划分工作的通常方法是将系统的不同部分分配给不同的组。这个所谓的工作分解结构在第1章中有所体现。因为架构包含了系统的最广泛的分解,所以它通常被用作工作分解结构的基础。工作分解结构反过来决定了计划、调度和预算的单位,团队间的沟通渠道,配置控制和文件系统结构,集成和测试计划及程序,甚至项目的细节,比如项目内部网如何组织,公司野餐时谁和谁坐在一起。团队根据接口规范彼此沟通。当组建运维团队时,也将依据软件结构中的特定元素—数据库、业务规则、用户界面、设备驱动程序等进行相应分工。
建立工作分解结构的一个副作用是冻结了软件架构的某些方面。负责其中一个子系统的组可能会拒绝将其职责分到其他组。如果这些职责已经在合同中确认,改变职责可能会变得昂贵,甚至会引起诉讼。
因此,一旦架构达成一致,出于管理和业务上的原因,对其进行重大修改就变得非常昂贵。所以对于大型系统,在做出具体选择之前,一定要分析其软件架构。
2.8赋能增量开发
一旦定义了架构,它就可以作为增量开发的基础。第一个增量可以是一个骨架系统,其中至少包含一些基础设施—元素的初始化、通信、共享数据、访问资源、报告错误、日志活动等,但系统的大部分应用功能并不存在。
构建基础设施和构建应用功能可以同时进行。设计和构建一个小的基础设施来支持少量端到端的功能,不断重复,直到完成。
许多系统先构建成骨架系统,然后使用插件、包或扩展库进行扩展。比如R语言、VisualStudioCode和大多数Web浏览器。每当添加扩展时,就增加了额外功能。这种方法需要确保系统在产品生命周期的早期就能执行。随着扩展的持续增加,早期版本不断被更完善的版本所取代,系统越来越逼近最终目标。在某些情况下,这些是最终功能的低保真版本或原型;在其他情况下,它们可能是替代品(surrogate),以适当的速度消耗和生成数据,但几乎不做其他事情。除此之外,这允许在产品生命周期的早期识别潜在的性能(和其他)问题。
这种做法在21世纪初通过AlistairCockburn的思想和他的“行走骨架”概念而受到关注。最近,它被那些采用MVP(最低可行产品)作为风险降低策略的人所采用。
增量开发的好处包括减少项目中的潜在风险。如果架构是针对一个系统家族的,那么基础设施可以在整个家族中重用,从而降低每个系统的成本。
2.9成本和进度估算
成本和进度估算是项目经理的一个重要工具。它们帮助项目经理获取必要的资源,并监控项目的进展。架构师的职责之一是帮助项目经理在项目生命周期的早期开展成本和进度估算。虽然自顶向下的估算对于设定目标和分配预算是有用的,但是基于自底向上对系统各部分的理解的成本估算通常比纯粹基于自顶向下系统知识的估算更准确。
正如我们所说的,项目的组织和工作分解结构几乎总是基于它的架构。对工作项目负责的每个团队或个人对从事的工作能够比项目经理做出更准确的估算,在实现这些估算的过程中,也会有更多的自主权。但是最好的成本和进度估算通常是在自顶向下的估算(由架构师和项目经理创建)和自底向上的估算(由开发人员创建)之间达成一致。这一过程中通过讨论和协商产生的估算要比使用任何一种方法精确很多。
对系统需求进行审查和验证是很有帮助的。你对范围了解越多,成本和进度估算就越准确。
第24章深入探讨了架构在项目管理中的作用。
2.10可转移、可重用模型
在软件生命周期中执行重用越早,获得的好处就越大。代码重用是好事,而架构重用为具有类似需求的系统提供了巨大的重用机会。当架构决策可以跨多个系统重用时,前面描述的所有早期决策结果也会转移到那些系统中。
产品线或产品家族是使用同一组共享资产(软件组件、需求文档、测试用例,等等)构建的一组系统。这些资产中最主要的是面向整个产品线设计的架构。产品线架构师选择一个架构(或一系列紧密相关的架构),该架构服务于产品线的所有成员,定义了什么是固定的,什么是可变的。
产品线代表了一种强大的多系统开发方法,在上市时间、成本、生产率和产品质量方面能得到数量级的回报。架构的力量处于这种方法的核心。与其他资本投资类似,产品线的架构是开发组织的共享资产。
2.11架构允许合并独立开发的元素
早期的软件范例把编码作为主要的活动,以代码行来衡量进度,而基于架构的开发通常把重点放在组合或组装可能分开开发的元素,甚至是彼此独立开发的元素上。这种组合是可能的,因为架构定义了可以合并到系统中的元素。架构根据它们与环境的交互方式、它们接收和放弃控制的方式、它们消费和生成的数据、它们访问数据的方式以及它们进行软件架构实践通信和资源共享所使用的协议来约束可能的替换(或添加)。我们将在第15章详细阐述这些观点。
现成的商业组件、开源软件、公开可用的App和网络服务都是独立开发的元素。将许多独立开发的元素集成到系统的复杂性和普遍性催生了整个软件工具行业,如ApacheAnt、ApacheMaven、MSBuild和Jenkins。
对于软件,有以下收益:
缩短投放市场的时间(使用别人的现成解决方案比自己开发更容易)。
提高可靠性(广泛使用的软件更利于消除bug)。
更低的成本(软件供应商在客户群中分摊开发成本)。
增加灵活性(如果你想购买的元素不是极端特别的,就可能有多个来源,从而增加议价空间)。
一个开放系统为软件元素定义了一组标准—它们如何运转,它们如何与其他元素交互,它们如何共享数据,等等。开放系统支持甚至鼓励许多不同的供应商能够生产元素。这可以避免“绑定供应商”,即只有单个供应商能够提供元素并因此收取额外费用。开放系统是通过定义元素及其交互的架构实现的。
2.12限制设计的备选范围
随着架构解决方案不断增加,尽管软件元素能以或多或少无限的方式组合,但如果我们主动选择较少的元素并限制其相互关系,则可以最小化正在构建系统的设计复杂性。
软件工程师不是一个创造性的和自由至上的艺术家。相反,工程是关乎规程的,而规程在一定程度上是限制已证实方案的替代词汇。这些已证实方案包括战术和模式,这些将在第二部分广泛讨论。重用现成的元素也是限制设计词汇的另一种方法。
将你的设计词汇限制为经过验证的解决方案可以产生以下好处:提高重用性。
更有规律、更简单的设计更容易理解和沟通,并带来更可靠的可预测结果。更容易分析,更有信心。更短的选择时间。更广泛的互操作性。
史无前例的设计是有风险的。经过验证的设计是可验证的。这并不是说软件设计永远不能创新或提供新的和令人兴奋的解决方案,当然可以,但这些解决方案的发明不应该只是为了新奇,当现有的解决办法不足以解决眼前问题时,就应该寻求创新方案。
软件的特性取决于架构战术或模式的选择。选择对于特定问题更合适的战术和模式能改进最终解决方案,可能通过使仲裁冲突的设计约束变得更容易,加深人们对设计环境的理解,帮助发现需求中的不一致性。我们将在第二部分讨论架构战术和模式。
2.13培训的基础
架构,包括对元素如何相互作用以实现所需行为的描述,可以作为新项目成员了解系统的第一课。这进一步证明软件架构的一个重要用途是支持和鼓励不同利益相关者之间的交流,并为所有这些人提供一个公共参考点。
模块视图是向人们展示项目结构(如谁做什么,哪个团队被分配到系统的哪个部分,等等)的绝佳方法。组件和连接器视图是解释系统如何工作和完成其任务的极佳选择。分配视图显示为新项目成员分配一个适合他的项目开发或部署环境。
2.14进一步阅读
GregorHohpe所著的TheSoftwareArchitectElevator:RedefiningtheArchitect’sRoleintheDigitalEnterprise描述了架构师与组织内外各级人员交互的独特能力,并促进利益相关者沟通[Hohpe20]。
关于架构和组织的论文的鼻祖是文献[Conway68]。Conway定律指出:“设计系统的组织……只能设计出这些组织沟通结构的复制品。”
Cockburn在《敏捷软件开发》(AgileSoftwareDevelopment:TheCooperativeGame)中描述了“行走骨架”的概念[Cockburn06]。
开放系统架构标准的一个很好的例子是AUTOSAR,它是为汽车工业开发的(autosar.org)。
有关构建软件产品线的详细处理,请参见文献[Clements16]。基于特性的产品线工程是一种现代的、以自动化为中心的构建产品线的方法,它将范围从软件扩展到系统工程。一个很好的总结可以在文献[INCOSE19]中找到。
2.15问题讨论
1.如果你对本书没有任何印象,那你记住了什么?
2.针对本章阐述的架构为何重要的13个原因,采取相反的立场:提出一组环境,在这些环境下,架构对于实现对应结果是不必要的。证明你的立场。(尝试为这13个原因中的每一个想出不同的情况。)
3.本章认为架构带来了许多切实的好处。在一个特定的项目中,你如何衡量这13点中的每一点所带来的好处?
4.假设你想向组织引入以架构为中心的实践,你的管理层对此持开放观点,但想知道这样做的投资回报率。你会如何回应?
5.根据一些对你有意义的标准来排列本章中列出的13个原因。证明你的答案。或者,如果你只能选择其中两三个来促进架构在一个项目中的使用,你会选择哪几个,为什么?
推荐阅读:
《软件架构实践(原书第4版)》
图书届奥斯卡Jolt大奖获奖作品,全球10余个国家出版。卡内基梅隆等名校教材,IEEE杂志10佳图书,软件架构图书事实标准。
往期推荐:
谈谈ChatGPT的低成本“平替”实现路线
华为官宣进军ERP的背后透露出哪些信息,华为会成功么
招商银行数据分析平台的前世今生
NB的GPT4,王炸更新,解封了!
技术琐话
以分布式设计、架构、体系思想为基础,兼论研发相关的点点滴滴,不限于代码、质量体系和研发管理。
本文链接:https://my.lmcjl.com/post/6909.html
4 评论