架构师必修课 | 架构简史:系统架构模式的演进(一)

架构师必修课 | 架构简史:系统架构模式的演进(一)

编码文章call10242025-04-15 10:58:4110A+A-

作为电商交易系统10多年的开发,我深知一个合适的架构对应用的重要性,无论是整体系统架构还是单个模块、业务功能。在我看来,架构并不是什么深奥的东西,只是前人对系统设计的经验的积累;别人通过趟坑,总结出的最佳实践,沉淀出的一套解决问题的方法论。

学架构,你不需成为六边形战士,不需要拥有所有这些架构的实践经验,但是,至少对它有所了解,例如 N-Layered(N层架构), DDD(领域驱动设计), Hexagon(六边形架构), Onion(洋葱架构), Clean Architecture(整洁架构);深入了解这些架构的历史、应用和它们之间的区别,必定能够让你在开发领域脱颖而出,让你作为技术管理者拥有更强的技术领导力。

本文涉及:

  • 23 种设计模式历史
  • 多层架构
  • 领域驱动设计
  • 六边形架构

篇幅有限,Onion、Clean Architecture 这这两种架构,我下篇文章安排,点赞、收藏、关注不迷路~

起源于设计模式

回到过去,那时候没有这么多复杂的架构。你只需要了解 23种设计模式,你就算一个合格的架构师!然而,随着计算机性能的提高,互联网用户量暴增、用户需求量也随之水涨船高,这就导致业务系统复杂性也随之增加。

这样的设计模式,作为架构演进的过渡产物的确很有帮助,但是效果并不是太好。如果你有过C#经验,并且开发过 ASP MVC 项目,你一定对黄色框标为“Model”心有余悸,因为他可能对你产生过误导,是的!它很容易让你误解为它只是数据传输对象(DTO)。

其实这里的 Model 指的是DomainModel,也被称之为“领域模型”。“领域模型”是在软件开发中用于捕捉和表示业务领域概念的一种模型。它通过定义实体、它们之间的关系和业务规则,提供了对系统中的实际业务问题的抽象。这种模型有助于开发团队更好地理解和共享业务需求,从而更有效地构建软件系统。领域模型可以使开发人员和业务专家之间的沟通更加流畅,减少误解,并为系统设计提供坚实的基础,以满足业务的需求。

这三种模式中,视图负责用户交互和界面展示,控制器更像是中间人充当中介,协调用户输入和模型之间的交互。然而,模型就变得异常臃肿,因为所有业务逻辑都被集中在模型层实现。这种情况下,模型不仅需要处理数据存储和状态管理,还要承担大量的业务逻辑负担。这或许会导致模型层难以维护和理解。

在那个时期,设计模式显然不足以解决问题。因此,必须出现一些新的想法。我们如何处理复杂性?没错,分而治之。我们已经在MVC中采用了这种方法,所以我们只需要再做一次。

2002年:多层架构(N-Layered)

理想的软件架构并非凭空想象而出现。和所有事物一样,理想的软件架构是通过试错逐步演进而来的。

在软件开发架构方面开创先河,对未来几十年的开发者产生深远影响的人被称为马丁·福勒。他的观点可以概括为:

《企业应用架构模式》是由马丁·福勒等人合著的著作,详细描述了多层架构的概念和实践。这本书深入研究了如何有效地组织和设计企业级应用程序,以满足复杂的业务需求。其中涵盖的多层架构概念旨在将应用程序划分为几个独立的层次,如表示层、业务逻辑层和数据访问层,以便更好地实现分离关注点、提高可维护性和灵活性。通过对各种模式的详细阐述,这本书为软件架构师和开发人员提供了实用的指南,帮助他们在构建大型企业级应用时做出明智的设计决策。

他的想法很简单,将所有相关代码组合在一起并调用这些层,如下图:

然而,并不像上图描述那么简单,本书中还有更多的其他内容。作者知道不一致性可能有多有害。

不一致性的危害,它可能导致系统行为的不可预测性,使得难以理解和调试代码。其次,不一致性可能导致模块之间的集成问题,使得不同部分的协同变得困难。此外,系统的维护和扩展变得复杂,因为缺乏一致性可能会导致修改某一部分代码时影响其他部分,增加了错误的引入风险。最终,不一致性可能导致团队成员之间的沟通障碍,因为他们可能对系统的行为和实现产生不同的理解,增加了协同工作的难度。因此,通过限制和指导来维持一致性,可以降低这些潜在害处。

为了防止我们在多层架构中陷入误区,他制定了一套多层架构的规范:

  • 我们可以按照自己的方式命名每个层,可以根据需要设计任意数量的层。
  • 我们可以在中间添加层。
  • 我们可以在同一层添加多个组件。
  • 但是我们需要确保在层之间存在清晰的层次结构,它们以一种相互引用的方式进行引用。

我们可以设计成这样:

也可以设计成这样:

它不仅帮助我们开发人员梳理出了不同层之间的关系和职责,而且最终帮助我们构建代码。尽管多层架构的规则非常灵活,但实际上,3 层对于大多数项目来说已经足够了。

  • 用户界面(UI):负责与用户进行交互。
  • 业务逻辑层(BLL):代表业务概念,规定应用程序的操作并使其相对于其他应用程序或者模块,具有自己独立的业务功能。
  • 数据访问层(DAL):在内存中持久保存数据并维护应用程序的状态。

在这里,我们明确区分了业务逻辑和用户界面。数据库的重要性不亚于业务规则,因此它有了自己的独立的一层。实际上,书中告诉读者:所有外部调用、外部技术、外部依赖,也都可以放在最后一层。

如果你对那些彩色的矩形和箭头代表什么感到困惑,不用担心,很简单。这些层次只是你解决方案中的项目,箭头表示这些项目之间的依赖关系。

每个层通过其 API 调用下面的层,通常以接口的方式暴露出去。注意:每个类的访问修饰符也是非常重要的。

这一切的一切,从现在看来都是理所当然,很浅显易懂,但是正如牛顿说的那样:““我之所以看得更远,是因为我站在巨人的肩膀上。”

2003年:领域驱动设计(DDD-Domain Driven Design)

在2003年,一位更加年轻的、46岁的波士顿开发者埃里克·埃文斯出版了他的著作《领域驱动设计:软件核心复杂性的应对之道》:

实际上,领域驱动设计(DDD)是一个比较大的课题,应该有一系列的文章对他进行深度挖掘,本文我们不会深入讨论,只关注它引入的所有架构变化。

埃文斯同意了福勒的所有观点,即项目依赖应该是单向的。然而,他也提到,低级模块调用高级模块是可以的,只要不违反依赖方向规则。这可以通过回调、观察者模式等方式实现。他还注意到控制器有太多的逻辑,于是将其移动到另一个称为“Application”的层。我们开始逐渐了解到用例的雏形,但还没有完全形成。

但是领域驱动设计和多层架构区别核心:业务逻辑比数据库更重要!可是领域驱动设计从架构的角度来看,并没有太多改变。

在埃文斯的架构中,定义了以下层次:

  • 表示层(Presentation Layer):负责与用户进行交互。
  • 应用层(Application Layer):协调任务并将工作委托给领域对象。
  • 领域层(Domain Layer):代表业务概念。它规定应用程序正在执行的任务,并使其相对于其他应用程序具有独特性。
  • 基础设施层(Infrastructure Layer):在内存中持久保存数据并维护应用程序的状态。

你可以看到,还是CV+重命名大法好!!!哈哈哈哈~~

  • 用户界面:用户界面的形态并不是一成不变。有时它是用户的图形用户界面(GUI);有时是开发者的命令行界面(CLI);而经常是程序的应用程序编程接口(API)。因此,"表示层"只是一个更通用和合适的名称。
  • 业务逻辑:对于一些开发者来说可能很令人困惑,尤其是对于那些根本不涉及业务的人,所以引入了一个新的名称“领域(Domain)”。
  • 数据库:并不是我们使用的唯一外部工具,因此所有的电子邮件发送器、事件总线、SQL和其他杂七杂八的东西都被移到了"基础设施"中。

基本上就是这些了,重命名+加了新的业务层,这就叫架构设计 ヽ(°▽°)ノ !尽管作者进行了一些层次的调整和重命名,整体架构依然保留了相同的依赖关系结构。如果当初作者能够更深刻理解并应用了依赖反转原则,或许架构设计在灵活性和可维护性上会有所提升。哈哈~

依赖反转原则(Dependency Inversion Principle)是面向对象设计的一项原则,强调高层次模块不应依赖于低层次模块,二者都应依赖于抽象。抽象不应依赖于具体实现,而是具体实现应该依赖于抽象。这个原则通过反转传统的依赖关系,使得高层次的模块不再直接依赖于具体的实现细节,而是依赖于更灵活和可替代的抽象接口。这样的设计提高了系统的灵活性,降低了模块之间的耦合度,使得系统更易扩展、修改和维护。

2005年:六边形架构(Hexagon-Ports and Adapters)

在此之前,上层模块必须引用底层模块。但是,随着依赖反转原则的提出,架构设计发生了颠覆性的变化。这就很让人兴奋,我们可以控制依赖关系的方向,这也就意味着业务逻辑不再引用数据访问。你可能想知道这是怎么实现的,接口又与此有什么关系,那么我们继续往下剖析。

通过使用依赖反转原则,开发者现在能够控制软件系统中模块之间的依赖关系方向。在这种情况下,业务逻辑(business logic)不再直接引用数据访问层。传统上,模块之间的依赖关系是由高层模块指向低层模块的,而依赖反转则允许我们反转这种关系,使得高层模块不再直接依赖于底层实现,而是依赖于更抽象的接口。这种变化提高了系统的灵活性和可维护性,使得各个模块更加独立和可替换。

发现这种架构的码农叫艾利斯泰尔·科克本,

向下依赖:

依赖反转:

多层架构:


科克本实现了埃文斯的梦想。现在,领域(Domain)是系统的核心组件,不仅在重命名上,而是落实在架构具体实现上。它不引用任何其他项目。 为了强调它确实是核心,业务逻辑(Business Logic)被重命名为Core。

基础设施模块被分为两半:抽象(接口)和实现。抽象成为业务逻辑的一部分,并被重命名为端口(ports)。实现留在基础设施层。现在它们被称为适配器(adapters)。实际上,UI被证明与DB是相同的框架层。

在业务逻辑中定义声明了基础设施的接口使得领域成为相对独立的且无依赖的。因此,业务逻辑可以在任何环境中、使用任何工具中运行。

想要更改数据库?只需更改实现,实现所需的适配器,然后“插入”到可用的端口中。 对任何适配器(数据库、邮件发送器、UI)的更改都不会影响业务逻辑。接口保持不变。 每个组件都可以单独部署。如果只更改数据访问,则只需重建数据访问。如果只更改UI,则只需更改UI。

由于模块可以单独部署,这意味着它们可以单独开发。

这个架构设计理念,拥有所有的优势。

终极形态:

调用我们系统的适配器被称为主适配器(主动适配器),而被我们系统调用的被称为次适配器(被动适配器)。

在后端架构模式的演进史中,我们经历了三种关键的架构设计思想:设计模式、多层架构、领域驱动设计和六边形架构。

  • 设计模式: 起源于对软件开发中常见问题的总结和抽象,通过23种设计模式的引入,为解决特定类型问题提供了可重用的解决方案。
  • 多层架构(N-Layered): 马丁·福勒提出了将应用程序划分为表示层、业务逻辑层和数据访问层的多层架构概念。它通过分离关注点、提高可维护性和灵活性,成为了一种经典的软件架构思想。
  • 领域驱动设计(DDD): 由埃里克·埃文斯引入,强调业务逻辑的重要性。尽管带来了业务层的强调和重命名,但从架构角度看,并没有带来根本性变化。
  • 六边形架构(Hexagon-Ports and Adapters): 艾利斯泰尔·科克本通过依赖反转原则,使得业务逻辑不再直接引用数据访问,引入了六边形架构。这一架构设计理念使得每个组件可以独立部署,模块独立开发,提高了系统的灵活性和可维护性。

这一系列演进反映了软件架构领域对于解决复杂业务需求和提升系统质量的不懈探索。在下一篇文章中,我们将深入探讨Onion架构和Clean Architecture,敬请关注。

点赞、收藏、关注,素质3连不迷路~~

点击这里复制本文地址 以上内容由文彬编程网整理呈现,请务必在转载分享时注明本文地址!如对内容有疑问,请联系我们,谢谢!
qrcode

文彬编程网 © All Rights Reserved.  蜀ICP备2024111239号-4