《软件架构基础(Fundamentals of Software Architecture)》被誉为和《设计数据密集型应用》一样经典的后端书籍,架构师的入门指南。本篇为该书第一章的读书笔记。

如今,全球范围内“架构师”这一头衔炒得十分火热,但没有真正的指南来帮助开发人员成为软件架构师。

这本书主要有三部分内容:基础、架构风格、技术和软技能。基础部分是关于软件体系结构的一般概念;架构风格部分介绍了不同的架构风格,并以一些架构特征标准进行评价;技术和软技能部分涵盖了很多好的概念,包括做出健康的架构决策、风险分析技术、演讲能力、管理团队关系、谈判、架构师职业规划等。

架构就是关于重要的东西……不管那是什么。—— Ralph Johnson

1. 什么是软件架构

学习架构就像学习艺术一样,读者必须要在特定的背景下去理解它。

在一个动态系统中,不存在一劳永逸的解决方案。

学习架构时,必须放在上下文中理解。架构师做的许多决定都是基于他们所处的实际情况。

例如,在 20 世纪末的主要目标是有效地利用共享资源,因为当时所有的基础设施都是昂贵的商业化产品:操作系统、服务器和数据库等等。如果你在 2002 年告诉主管,“我有一个革命性的架构好主意,每个服务都运行在自己隔离的机器上,有自己的专用数据库……(即描述今天的微服务架构)所以,我需要 50 个 Windows 的许可证,另外 30 个服务器许可证,以及至少 50 个数据库许可证。”在 2002 年想构建这样的微服务架构成本之高难以想象。然而这几年,随着开源运动的兴起,以及 DevOps 的出现,我们可以合理地构建一个如上所述的架构。

整个行业都在努力精确定义“软件架构”,有些称为系统的蓝图,有些定义为开发的路线图。本书关于架构的定义主要从四个方面:

  • 系统的结构(Structure)
  • 系统所支持的架构特性、能力(Architecture characteristics)
  • 架构决策(Architecture decisions)
  • 设计原则(Design principles)

系统的结构指的是系统实现架构风格的类型(如微服务、分层或微内核)。但仅仅通过结构来描述一个架构,并不能完全阐明一个架构。

架构特性多以 “-ility” 结尾(例如 Availability、Scalability)

架构决策定义了系统应该如何构建的规则。例如,架构师可能会做出一个架构决策,即在分层架构中只有业务层和服务层可以访问数据库(见图),限制表现层直接调用数据库。架构决策形成了系统的约束,并指导开发团队什么是允许的,什么是不允许的。

设计原则与架构决策的不同之处在于,设计原则是一个指导方针,而不是一个硬性规定。例如,图示的设计原则指出,开发团队应该在微服务架构中的服务之间传递异步消息来提高性能。一个架构决策永远不可能涵盖服务之间通信的每一个条件和选项,设计原则为首选方法(在本例中,异步消息传递)提供指导,允许开发人员在特定情况下选择更合适的通信协议(如 REST 或 gRPC)。

2. 对架构师的 8 个期待

2.1 做出架构决定

架构师应确定架构和设计原则,用于指导团队、部门或整个企业的技术决策。

架构师应该指导而不是指定技术选择。例如,架构师应该决定开发团队使用基于响应式 (Reactive) 的框架进行开发,从而指导开发团队在 Angular、Elm、React.js、Vue 或其他任何基于响应式的 Web 框架之间做出选择。

架构师偶尔需要做出特定的技术决策,以保留特定的架构特性,如可扩展性、性能或可用性。

架构师经常为找到正确的界线而苦恼。

2.2 持续分析架构

多数架构都会经历结构性衰变,当开发人员进行编码或设计变更时,会影响到所需的架构特性,如性能、可用性和可扩展性。架构师需要评估三年或更长时间前定义的架构在今天的可行性。

另一方面,架构师还常常忘记测试和发布环境。敏捷性有很大的好处,如果团队需要几周的时间来测试变更,而发布又需要几个月的时间,那么架构师就无法实现整体架构的敏捷性。

2.3 紧跟最新趋势

架构师要跟上最新的技术和行业趋势。

开发人员必须掌握他们每天使用的最新技术,以保持代码能力(并保住一份工作!)。架构师有一个更关键的要求,就是要掌握最新的技术和行业趋势。架构师所做的决定往往是长期的,难以改变的,了解和跟踪关键趋势有助于架构师为未来做好准备,做出正确的决定。

2.4 确保遵守各项决定

架构师要不断验证开发团队是否遵循架构师定义、记录和传达的架构决策和设计原则。

考虑这样的场景:架构师做出一个决定,在分层架构中限制对数据库的访问,只限于业务层和服务层(而不是表现层)。这意味着表现层必须经过架构的所有层才能进行最简单的数据库调用。用户界面开发人员可能不同意这个决定,出于性能考虑而直接访问数据库。然而,架构师做出这个架构决策是有特定原因的:控制变化。通过保持各层独立,可以在不影响表现层的情况下进行数据库变更。如果不确保架构决策的合规性,就会发生类似这样的违规行为,架构将无法满足所需的架构特性,应用程序或系统将无法按预期工作。

2.5 多样化的接触和经验

架构师要接触多种多样的技术、框架、平台和环境。

现在的大多数环境都是异构的,一个架构师至少应该知道如何与多个系统和服务对接,不管这些系统或服务是用什么语言、平台和技术编写的。

最好方法之一是让架构师延伸自己的舒适区,只关注单一技术或平台是一个安全的避风港,一个好的软件架构师应该积极寻找机会,以获得多种语言、平台和技术的经验,关注技术广度而不只是技术深度。

2.6 具备业务领域知识

一个架构师要有一定的业务领域专业知识。

有效的软件架构师不仅了解技术,还了解业务问题。如果没有业务领域的知识,就很难理解业务问题、目标和需求,很难设计出满足业务需求的有效架构。

最成功的架构师是那些拥有广泛的、实践性的技术知识,再加上对某一特定领域的深刻了解的人。这些软件架构师能够使用这些利益相关者所能理解的领域知识和语言,与主管和业务用户进行有效的沟通。

2.7 具备人际交往能力

架构师应具备卓越的人际交往能力,包括团队合作、促进和领导能力。

拥有卓越的领导力和人际交往能力是大多数开发人员和架构师难以企及的期望。作为技术专家,开发人员和架构师喜欢解决技术问题,而不是人的问题。

架构师不仅要为团队提供技术指导,还要带领开发团队完成架构的实施。无论架构师的角色和头衔是什么,领导能力是成为一个软件架构师不可或缺的。

2.8 理解和驾驭企业政治

架构师要了解企业的政治氛围,并能驾驭政治。

在一本关于软件架构的书中谈论谈判和驾驭办公室政治,可能看起来比较奇怪。主要的一点是,几乎架构师的每一个决策都会受到挑战。由于涉及到成本或工作量(时间)的增加,架构决策会受到产品、项目经理、开发和业务利益相关者的挑战,因为他们觉得自己的方法更好。无论在哪种情况下,架构师都必须驾驭公司的政治,并应用基本的谈判技巧来获得批准。

架构师不像开发,可以自行设计代码结构、类、设计模式甚至是语言而不需要批准,架构师做出广泛而重要的决策,必须为几乎每一个决策进行论证和争取。

3. 架构师和其它的交集

3.1 工程实践

将软件开发过程与软件工程实践分开是有益的。所谓过程,我们指的是如何组建和管理团队,如何进行会议以及工作流组织,指的是人们如何组织和互动的机制。而**软件工程实践则是指那些已经说明了的、可重复效益的与过程无关的实践。**例如,持续集成是一种经过验证的工程实践,它不依赖于特定的过程。

注重工程实践很重要:

  • 首先,软件开发缺乏许多比较成熟的工程学科的特点。例如,土木工程可以比软件工程更准确地预测结构变化。
  • 其次,**软件开发的一个致命弱点是估算–多少时间,多少资源,多少钱?**这种困难一部分在于陈旧的会计无法适应软件开发的探索性;但另一部分是因为我们传统上不擅长估算,部分原因是因为 unknown unknowns。

unknown unknowns 是软件系统的克星:没有人知道会出现的东西,却又意外地出现了。例如:某个意外的 bug 出现。

所有的架构都会因为 unknown unknowns 而变成迭代式的,敏捷只是认识到了这一点,并且更早去做了。(All architectures become iterative because of unknown unknowns, Agile just recognizes this and does it sooner.)

迭代流程更符合软件架构的本质,试图使用像瀑布这样的陈旧流程来构建微服务这样的现代系统的团队会发现,一个陈旧的流程忽视了软件如何结合在一起的现实,会产生大量的摩擦。

如图所示,软件系统的架构由需求和所有其他架构特征组成

采用敏捷工程实践,如持续集成、自动机器供应和类似的实践,使构建弹性架构变得更容易。这也说明了架构与工程实践是如何相互交织在一起的。

3.2 运维/DevOps

架构和相关领域之间最近最明显的交集发生在 DevOps 的出现。许多公司认为运维是与软件开发是分离的,在 20 世纪 90 年代和 2000 年代设计的架构都假设架构师无法控制运维,架构师们被迫围绕引入的限制进行防御性设计。因此,他们构建了能够在内部处理规模、性能、弹性和其他一系列能力的架构。这种设计的副作用是大大增加了架构的复杂性。

微服务风格架构的构建者们意识到,通过在架构和运维之间建立一个联络点,架构师可以简化设计,依靠运维来处理他们最擅长的事情。因此,意识到资源的挪用导致了意外的复杂性,架构师和运维合作创建了微服务。

3.3 流程

软件架构与软件开发过程大多是正交的(相互不可替代的),大多数关于软件架构的书籍都忽略了软件开发过程。例如,在过去的几十年里,由于软件的性质,许多公司都采用了敏捷开发方法。架构师在敏捷项目中得到更快的反馈,这使得架构师可以更积极地进行实验。

所有的架构都会变成迭代式的,这只是时间问题。为此,我们要在整个过程中假设敏捷方法论的基线,并允许适当的例外。例如,许多单体架构因为年龄、政治或其他与软件无关的因素而使用旧流程的情况还是很常见的。

3.4 数据

很大一部分严肃的应用程序开发包括外部数据存储,通常采用关系型(或越来越多的 NoSQL)数据库的形式。然而,许多关于软件架构的书籍只对架构的这一重要方面进行了轻描淡写的处理。代码和数据具有共生关系:两者缺一不可。

4. 软件架构法则

软件架构第一定律: 软件架构中的所有东西都是一种权衡。(Everything in software architecture is a trade-off.)

我们对软件架构的定义超越了结构的范畴,包含了原则、特性等,架构的范围比单纯的结构更广,体现在我们的软件架构第二定律中: 为什么比怎么做更重要。(Why is more important than how.)