所以,你对软件架构感兴趣。也许你是一名开发者,想要迈向职业生涯的下一个阶段;也许你是一名项目经理,希望了解软件架构如何发挥作用。你可能也是一名“意外的架构师”:虽然并没有“软件架构师”的正式头衔,但已经在做出架构决策(定义如下)……或许只是“尚未”拥有这个头衔。
为什么要深入研究软件架构?也许你已经参与过许多项目,希望更深入地理解系统的整体架构,以及其中的各种权衡。如果是这样,软件架构无疑是你的下一个职业发展方向。
本书正是为你而写的。它概述了“软件架构师”这一极其多元化的职业。
软件架构师必须深入理解和分析软件系统的复杂性,并在信息不完整的情况下做出关键的权衡决策。如今,许多担心生成式 AI 可能逐步取代他们的软件开发者,正在考虑转向软件架构,因为这一角色更难以被替代。软件架构师的职责正是 AI 无法胜任的:在复杂且不断变化的环境中评估权衡并做出决策。
架构就像艺术,只有在特定环境下才能被理解。架构师的决策基于其所处的现实环境。例如,20 世纪末的软件架构的主要目标之一是高效利用共享基础设施和资源,因为当时的操作系统、应用服务器和数据库服务器等商业软件都非常昂贵。
在 2002 年,尝试构建微服务架构几乎是不可能的昂贵设想。试想你走进 2002 年的数据中心,对运维主管说:“嘿,我有一个革命性的架构理念,每个服务都运行在自己的独立服务器上,并配备专属数据库。我需要 50 个 Windows 许可证,另外 30 个应用服务器许可证,以及至少 50 个数据库服务器许可证。”这在当时简直是天方夜谭。而如今,我们之所以能够实现这样的架构,得益于开源技术的兴起以及 DevOps 运动带来的工程实践革新。所有架构都是其时代背景的产物——在阅读本书时,请始终记住这一点。
定义软件架构
那么,什么是软件架构?图 1-1 展示了我们对软件架构的理解方式。这一定义包含四个维度:软件架构由一种 架构风格 作为起点,结合必须支持的 架构特性、用于实现系统行为的 逻辑组件,以及支撑整个架构的 架构决策 组成。系统的结构由图中粗黑线表示,它们支撑着整个架构。
我们将按照架构师分析这些维度的顺序快速介绍它们,而后续章节会提供更详细的讲解。
架构特性(见图 1-2)定义了系统的能力(通常简称为“-ilities”)以及衡量其成功的标准——简而言之,即系统应该具备的功能。架构特性至关重要,因此本书专门用了几章来探讨如何理解和定义它们。
虽然架构特性定义了系统的能力,但逻辑组件则决定了系统的行为。设计逻辑组件是架构师的关键结构性活动之一。在图 1-3 中,逻辑组件构成了应用程序的领域、实体和工作流。
一旦架构师分析了系统所需的架构特性和逻辑组件(后续章节将详细介绍),他们就有足够的信息来选择合适的架构风格,作为实现解决方案的起点(见图 1-4)。
定义软件架构的第四个维度是架构决策,它规定了系统应如何构建的规则。例如,在分层架构中,架构师可能会决定只有业务层(Business)和服务层(Services)可以访问数据库(见图 1-5),从而限制表示层(Presentation)直接调用数据库。架构决策构成了系统的约束,并指导开发团队明确哪些操作是允许的,哪些是不允许的。
我们在第 21 章讨论了架构决策以及如何简洁地记录它们。
软件架构法则
在撰写本书第一版时,我们怀揣着一个雄心勃勃的目标:希望找到一些在软件架构中普遍适用的原则,并将其归纳为“软件架构法则”。在写作过程中,我们一直在寻找这些普遍真理,最初预计能找到 10 到 15 条。然而,出乎意料的是,在第一版中,我们最终只确定了两条,而在撰写第二版时又发现了第三条。忠于我们的初衷,这三条法则确实具有广泛的适用性,并为软件架构师提供了重要的思考视角。
我们在不断的探索过程中总结出了第一条软件架构法则,它揭示了为什么这些普遍真理如此难以捉摸:
软件架构的第一法则:
软件架构中的一切都是权衡(Trade-off)。
在架构设计中,没有任何决策可以简单地归入“好”或“坏”的范畴。软件架构师在做决策时必须考虑众多变量,而这些变量在不同情况下会呈现不同的取值。因此,权衡取舍是架构决策的本质。
如果你认为某个决策没有权衡,只是因为你还没有发现其中的权衡点……至少现在还没有。
推论 1
你无法只做一次权衡分析就一劳永逸。
推论 2
团队喜欢标准化,但架构师无法通过一次“权衡大会”来确定所有架构默认选项。
比如,选择哪种架构风格、各部分如何通信、如何管理共享功能等问题,都不能一劳永逸地决定。因为每种情况都需要重新评估权衡因素。(我们曾见过一些团队试图这样做,比如默认在所有分布式工作流中使用编排(choreography),但后来发现它在某些场景下有效,而在其他场景下却是一场灾难。关于这一点,请参考“编排与协调”一节的讨论。)
软件架构不仅仅是结构元素的组合,因此我们的多维定义包含了架构原则、架构特性等内容。这一点体现在第二条软件架构法则:
软件架构的第二法则:
“为什么”比“如何”更重要。
作为一名经验丰富的架构师,如果有人向我展示一个我从未见过的架构,我可以很快理解它的运作方式(how) ,但我可能难以理解**为什么(why)**之前的架构师或团队会做出这些决策。架构决策通常是在特定上下文中做出的,因此很难做出普适的通用决策。
理解“为什么”某个架构决策被做出,意味着要理解架构师所考虑的权衡因素。这些因素构成了该决策的背景,使其在众多可能的选择中脱颖而出。这也引出了第三条软件架构法则:
软件架构的第三法则:
大多数架构决策不是非黑即白的,而是存在于两个极端之间的某个光谱上。
在本书中,我们不仅会强调架构师做出某些决策的原因,还会探讨相关的权衡因素。同时,我们将在第 21 章介绍如何高效地记录这些关键决策。
读者在阅读本书时,会不断看到这些法则的体现。我们建议在评估软件架构决策时始终牢记这三条法则。此外,在第 27 章,我们还将通过更多示例回顾这些法则的应用。
在明确了软件架构的定义后,让我们进一步探讨架构师的角色。
架构师的期望
软件架构师的角色范围广泛,可以从充当专家级程序员到定义整个公司的战略技术方向。因此,尝试给这个角色下一个固定的定义是徒劳的。但我们可以明确的是,人们对软件架构师有着一系列核心期望。无论其职位、头衔或具体职责如何,我们总结出了架构师应该具备的 八项核心能力:
- 做出架构决策
- 持续分析架构
- 跟进行业最新趋势
- 确保架构决策的执行
- 理解多种技术、框架、平台和环境
- 了解业务领域
- 领导团队并具备人际交往能力
- 理解并适应组织内部政治
成功的软件架构师必须理解并践行这些期望。本节将依次探讨每一项能力。
1. 做出架构决策
架构师需要定义架构决策和设计原则,以指导团队、部门或整个企业的技术决策。
这里的关键字是 “指导(Guide)” 。架构师的职责是引导技术选择,而不是直接指定。例如,决定前端开发使用 React.js 是一个技术决策,而非架构决策。相反,架构师应该指导开发团队采用**基于响应式(reactive-based)**的前端框架,例如 Angular、Elm、React.js、Vue 等,让团队在架构边界内做出合适的技术选择。
当然,在某些情况下,为了保持特定的架构特性(如可扩展性、性能或可用性),架构师确实需要做出具体的技术决策。如何在指导技术选择和直接决策之间找到平衡,是架构师经常面临的挑战。因此,第 21 章将专门讨论架构决策的制定。
2. 持续分析架构
架构师需要持续评估当前架构及技术环境,并提出改进方案。
架构活力(Architecture Vitality)是指一个架构在定义三年或更久之后,是否仍然适用于当前的业务和技术环境。许多架构师并没有足够关注这一点,导致架构随时间推移而出现结构性衰退(Structural Decay) 。这种衰退通常发生在开发人员对代码或设计进行修改时,影响了架构的核心特性,例如性能、可用性和可扩展性。
此外,架构师往往忽略了测试和发布环境的重要性。代码修改速度快是一种敏捷性,但如果需要数周进行测试、数月才能发布,那么架构本身就无法真正实现敏捷。
架构师需要从技术变更和业务需求的双重角度进行整体分析,以确保架构的可持续性。这种能力是应用程序保持长期可用性的关键,尽管它很少出现在职位描述中。
3. 跟进行业最新趋势
架构师需要紧跟技术和行业趋势。
开发人员需要不断更新他们的技术知识,以保持竞争力并确保就业安全。而对于架构师来说,这一点更为关键,因为架构决策往往具有长期影响且难以更改。理解技术趋势,能让架构师做出未来仍然适用的决策。
例如,近年来架构师需要学习云存储和云部署技术。而在撰写本书的第二版时,生成式 AI 已经对开发生态系统的许多方面产生了深远影响。
跟踪趋势并保持技术前沿是一项挑战,尤其对架构师而言。在第 2 章,我们将讨论如何高效获取和利用最新的行业资源。
4. 确保架构决策的执行
架构师需要确保开发团队遵循既定的架构决策和设计原则。
确保合规性意味着持续验证开发团队是否按照架构师定义、记录和传达的架构规则进行开发。
例如,假设你作为架构师,决定在分层架构中,只有 业务层(Business Layer) 和 服务层(Services Layer) 能访问数据库,而 表现层(Presentation Layer) 不得直接访问数据库(详见第 10 章)。这一决策的目的是防止数据库变更影响表现层。然而,一名 UI 开发人员认为这样影响性能,便绕过架构规则,直接让表现层访问数据库。
如果架构师不监督架构决策的执行,就会发生这样的违规行为,导致架构无法提供预期的系统特性,甚至造成系统失败。因此,在第 6 章,我们将讨论如何使用**自动化适配函数(Automated Fitness Functions)**和其他工具来测量架构合规性。
了解多样化的技术
架构师应当具备多种技术、框架、平台和环境的经验。
并不是每个架构师都需要在每个框架、平台和编程语言上都成为专家,但他们至少应该对多种技术有所了解。如今,大多数环境都是异构的,因此,架构师至少应该知道如何与多个系统和服务进行接口,不论它们使用的是哪种语言、平台或技术。
满足这一期望的最佳方法之一是跳出舒适区,积极寻找机会,在多种语言、平台和技术上积累经验。架构师应关注技术广度而非技术深度。技术广度包括你了解但不深入的东西,结合你非常熟悉的技术领域。例如,了解10种不同缓存产品的优缺点比仅精通其中一种产品更有价值。
了解业务领域
架构师应当具备一定程度的业务领域专业知识。
有效的软件架构师了解架构要解决的业务问题、目标和需求,这些共同构成了问题空间的业务领域。如果不了解业务需求,设计出有效的架构会变得非常困难。想象一下,如果你是某大银行的架构师,却不了解“平均方向性指数”、“偶然合同”、“利率反弹”或“非优先债务”等常见金融术语,你将无法与利益相关者和业务用户沟通,并很快失去可信度。
我们所知道的最成功的架构师,通常既有广泛的技术知识,又在特定领域拥有强大的知识。他们能够用利益相关者熟悉和理解的语言与C级高管和业务用户进行交流,给人一种他们知道自己在做什么并且有能力创建有效且正确架构的信心。
具备人际交往能力
架构师应当具备卓越的人际交往能力,包括团队合作、引导和领导能力。
作为技术人员,开发人员和架构师往往更喜欢解决技术问题,而非人际问题,因此卓越的领导力和人际交往能力是一个艰巨的期望。然而,正如Gerald Weinberg所著名所说:“不管他们怎么告诉你,问题总是人与人之间的问题。”架构师提供的指导不仅仅是技术性的——还包括领导开发团队实施架构的过程。无论角色或职称如何,领导力至少占据成为一名有效软件架构师所需能力的一半。
目前,软件架构师数量众多,竞争有限的职位。那些具备强大领导力和人际交往能力的人会从人群中脱颖而出。反之,我们也认识一些优秀的技术架构师,但他们在领导团队、指导和辅导开发人员,或者沟通思想和架构决策时存在困难。毫无疑问,这些架构师在找工作时会面临很多困难。
理解和应对政治
架构师应当了解企业的政治环境,并能够应对其政治。
在一本关于软件架构的书中讨论办公室政治可能显得有些奇怪,但谈判技巧对这个角色至关重要。为了说明这一点,考虑两个情境。
在第一个情境中,一位开发人员决定利用某种设计模式来简化一段复杂的代码。这是一个很好的决定,开发人员无需为此寻求批准。编程方面如代码结构、类设计、设计模式选择,甚至是语言选择,都是编程艺术的一部分。
在第二个情境中,负责大型客户关系管理(CRM)系统的架构师在控制其他系统的数据库访问、保护某些客户数据以及修改数据库模式时遇到了困难。这些问题都源于其他太多系统使用了CRM数据库。因此,架构师决定创建应用程序孤岛,每个应用的数据库只能由拥有该数据库的应用程序访问。这个决定将使架构师对客户数据、安全性和变更具有更好的控制。
然而,与第一个情境中的开发人员决策不同,架构师可以预期几乎公司里的每个人都会对他们的决策提出挑战(CRM应用团队可能是例外)。其他应用程序需要CRM数据,如果它们不能直接访问数据库,必须通过远程访问请求CRM系统的数据。产品负责人、项目经理和业务利益相关者可能会反对增加他们的成本或工作量,而开发人员可能会觉得他们的方案更好。几乎每个架构师做出的决策都会遭到挑战。
无论反对意见如何,架构师都必须应对组织政治,并运用谈判技巧来获得大多数决策的批准。这可能会非常令人沮丧;大多数软件架构师从开发人员起步,习惯了做决策无需批准甚至审查。作为架构师,他们终于能够做出广泛且重要的决策,但他们必须为几乎每一个决策提供充分的理由并进行争取。谈判技巧,像领导力一样,是至关重要的,我们已经为此专门编写了一整章(第25章)。
路线图
本书分为三部分:
第一部分:基础 第一部分定义了软件架构的关键组件,重点介绍架构结构的两个关键元素:架构特性和逻辑组件。分析这些元素需要不同的技术,我们将在书中深入探讨。通过这些活动的输出,软件架构师将获得足够的信息,以选择合适的架构风格,为实现的整体理念提供支撑。
第二部分:架构风格 第二部分提供了一系列架构风格,即软件架构的命名拓扑。我们展示了每种风格中的结构和通信差异,并提供了一个广泛对比的基础,包括数据拓扑、团队和物理架构等方面。
第三部分:技术与软技能 第一部分和第二部分集中讨论了工作中的技术方面,但软件架构师的角色很大一部分涉及传统上被称为软技能的内容:这些技能更多地涉及与他人的互动,而非技术。具有讽刺意味的是,软技能往往是初入架构师角色的人最难掌握的,因为通往软件架构师的路径通常更多依赖于技术而非人际交往能力。然而,一旦担任这一角色,架构师会发现这些技能至关重要。因此,本书的第三部分将介绍一些关键的软技能,帮助你在这一角色中取得成功。