天天看点

软件架构(6)-分层架构 从2层到3层到4层的发展历程

作者:架构师狂飙

这篇文章是 软件架构编年史的一部分,这是一系列关于软件架构的文章。在其中,我写下了我在软件架构方面学到的知识、我对它的看法以及我如何使用这些知识。如果您阅读了本系列的前几篇文章,这篇文章的内容可能会更有意义。

分层是根据代码单元在系统中的角色/职责来分离和组织代码单元的常见做法。

在面向对象的程序中,UI、数据库和其他支持代码通常直接写入业务对象。额外的业务逻辑嵌入在 UI 小部件和数据库脚本的行为中。发生这种情况是因为从短期来看,这是使事情顺利进行的最简单方法。

当与领域相关的代码通过如此大量的其他代码扩散时,就变得极其难以查看和推理。对 UI 的表面更改实际上可以更改业务逻辑。更改业务规则可能需要仔细跟踪 UI 代码、数据库代码或其他程序元素。实现一致的、模型驱动的对象变得不切实际。自动化测试很尴尬。由于每个活动都涉及所有技术和逻辑,因此程序必须保持非常简单,否则将变得无法理解。

Eric Evans 2014,领域驱动设计参考

分层是什么意思

在分层系统中,每一层:

  • 取决于它下面的层;
  • 独立于它上面的层,不知道使用它的层。

在分层架构中,层可以以严格的方式使用,其中一个层只知道它正下方的层,或者以更灵活的方式使用,其中一个层可以访问它下面的任何层。Martin Fowler 和我自己的经验都告诉我,第二种情况在实践中似乎效果更好,因为它避免了在中间层创建代理方法(甚至完整的代理类),并且可以退化为 Lasagna 的反模式架构(更多内容见下文)。

有时,这些层的排列方式使领域层完全隐藏了数据源。然而,更常见的是,演示文稿直接访问数据存储。虽然这不太纯粹,但在实践中往往效果更好。

Fowler 2002, 企业应用架构模式

优点是:

  • 我们只需要了解我们正在处理的层之下的层;
  • 每一层都可以由等效的实现替换,而不会影响其他层;
  • 图层是标准化的最佳候选者;
  • 一个层可以被多个不同的高层使用。

缺点是:

  • Layers 不能封装所有东西(添加到 UI 的字段,很可能还需要添加到 DB);
  • 额外的层会损害性能,尤其是在不同的层中。

60 年代和 70 年代

尽管软件开发始于 50 年代,但它实际上是在 60 年代和 70 年代诞生的,正如我们今天所知道的那样,作为构建可以由非开发人员本身的其他人交付、部署和使用的应用程序的活动。

然而,在这一点上,应用程序与今天大不相同。没有 GUI(它只出现在 90 年代初期,可能是 80 年代后期),所有应用程序只能通过 CLI 使用,显示在一个哑终端中,该终端只会将用户键入的任何内容传输到应用程序,这很可能是, 在同一台计算机上使用。

软件架构(6)-分层架构 从2层到3层到4层的发展历程

应用程序非常简单,因此在构建时并未考虑分层,它们在一台计算机上部署和使用,使其成为一个有效的单层应用程序,尽管在某些时候,愚蠢的客户端甚至可能是远程的。虽然这些应用程序 非常简单,但它们 不可扩展,例如,如果我们需要将软件更新到新版本,我们将不得不在每台安装了该应用程序的计算机上执行此操作。

80 和 90 年代的分层

在 20 世纪 80 年代,企业应用程序开始出现,我们开始在一家公司中拥有多个使用台式计算机的用户,这些用户通过网络访问该应用程序。

这时候,多是三层:

  • 用户界面(演示):用户界面,可以是网页、CLI 或本机桌面应用程序;即: 作为客户端(富客户端)的本机 Windows 应用程序,普通用户将在他的台式计算机上使用它,它将与服务器通信以实际使事情发生。客户端将负责应用程序流程和用户输入验证;
  • 业务逻辑(领域):应用存在的逻辑;即: 一个应用程序服务器,它将包含业务逻辑并接收来自本机客户端的请求,对它们采取行动并将数据持久保存到数据存储中;
  • 数据源:数据持久化机制(DB),或与其他应用程序的通信。即:数据库服务器,应用程序服务器将使用它来保存数据。
软件架构(6)-分层架构 从2层到3层到4层的发展历程

随着可用性上下文的这种转变,分层开始成为一种实践,尽管它只是在 1990 年代(Fowler 2002)随着客户端/服务器系统的兴起才开始成为一种普遍的实践。这实际上是一个两层应用程序,其中客户端是用作应用程序接口的富客户端应用程序,而服务器将具有业务逻辑和数据源。

这种架构模式解决了 可扩展性 问题,因为多个用户可以独立使用该应用程序,我们只需要另一台台式计算机,在其中安装客户端应用程序即可。然而,如果我们有几百个,甚至只有十分之几的客户端,并且我们想要更新应用程序,这将是一个非常复杂的操作,因为 我们必须一个一个地更新客户端。

90年代中期后的分层

大约在 1995 年到 2005 年间,随着向云环境的普遍转变,应用程序用户、应用程序复杂性和基础设施复杂性的增加,我们最终看到了分层方案的演变,这种分层的典型实现可能是:

  • 本机浏览器应用程序,呈现和运行用户界面,向服务器应用程序发送请求;
  • 一个应用服务器,包含表现层、应用层、领域层和持久层;
  • 数据库服务器,应用程序服务器将使用它来持久保存数据。

这是一种三层架构模式,也称为n-tier。它是一个 可扩展的 解决方案, 解决了更新客户端的问题,因为用户界面存在并在服务器上编译,尽管它是在客户端浏览器上呈现和运行的。

软件架构(6)-分层架构 从2层到3层到4层的发展历程

2000年代初之后的分层

2003 年,埃里克·埃文斯 (Eric Evans) 出版了他的标志性著作《 领域驱动设计:解决软件核心的复杂性》。在那本书中发表的许多关键概念中,还有一个软件系统分层的愿景:

软件架构(6)-分层架构 从2层到3层到4层的发展历程
  • 用户界面
  • 负责绘制用户用来与应用程序交互的屏幕,并将用户的输入转换为应用程序命令。值得注意的是,“用户”可以是人类,也可以是其他应用程序,这完全对应于 Ivar Jacobson 的 EBI 架构中的 Boundary 对象(稍后将详细介绍);
  • 应用层
  • 编排域对象以执行用户所需的任务。它不包含业务逻辑。这与 Ivar Jacobson 的 EBIArchitecture 中的交互器有关,除了 Jacobson 的交互器是与 UI 或实体无关的任何对象;
  • 领域层
  • 这是包含所有业务逻辑、实体、事件和包含业务逻辑的任何其他对象类型的层。显然和EBI的Entity对象类型有关。这是系统的核心;
  • 基础设施
  • 支持以上层的技术能力,即。持久性或消息传递。

反模式:烤宽面条架构

软件架构(6)-分层架构 从2层到3层到4层的发展历程

Lasagna Architecture是常用于指代 Layered Architecture 的反模式的名称。它发生在:

  • 我们决定使用严格的分层方法,其中一个层只知道紧挨着它的下一层。在这种情况下,我们最终将创建代理方法,甚至代理类,只是为了让我们通过中间层而不是直接使用我们需要的层;
  • 我们在创建完美系统的冲动中导致项目 过度抽象;
  • 小的更新会在应用程序的所有区域产生反响,例如,整理单个层可能是一项风险巨大、回报微薄的艰巨任务。
  • 我们最终得到了太多层,这增加了整个系统的复杂性;
  • 我们最终得到太多层,这既增加了复杂性又损害了整个系统的性能;
  • 我们根据其层(即 UI、域、数据库)明确地组织我们的单体,而不是通过其子域/组件(即产品、支付、结账)组织它,破坏了领域概念的模块化和封装。

结论

分层架构是另一种提供关注点分离、封装和解耦的方法,它通过按代码单元在应用程序中的功能角色对代码单元进行分组。

然而,就像生活中的大多数事情一样,太多会适得其反!所以经验法则是:只使用我们需要的层,我们需要的层,仅此而已!我们绝不能因追逐不存在的建筑圣杯而忘乎所以。确实存在的是一种需求,并且最适合该需求。这是精益的一部分,顺便说一句。

此外,请务必注意,这种自上而下的分层方法已经过时。这不再是我们在现代软件开发中应该做的事情,应用层有了新的更好的思考方式。我将在接下来的帖子中讨论。

参考资料:https://herbertograca.com/2017/08/03/layered-architecture/

继续阅读