软件架构编年史:分层架构

简介: 软件架构编年史:分层架构

分层是一种常见的根据系统中的角色/职责拆分和组织代码单元的常规实践。

在一个面向对象的程序里,UI、数据库和其它支撑代码会被写到业务对象里。额外的业务逻辑也会被嵌到 UI 控件和数据库脚本里。这是由于在短期内完成够用的代码是更简单的选择。

当领域相关的代码扩散到这样大规模的其它代码中,要发现和理解这些代码会相当困难。表面上对 UI 的修改实际上也会改变业务逻辑。要修改业务规则就得小心翼翼地追踪 UI 代码、数据库代码,或者其它的编程元素。实现内聚的、模型驱动的对象变得不切实际。自动化测试也变得尴尬。如果每个活动都要卷入所有的技术和逻辑,程序必须非常简单,要不然就完全无法理解。

——Eric Evans 2014, Domain-Driven Design Reference

◐ 分层意味着什么


在一个分层系统中,每一层:

  • 依赖它之下的层;
  • 和它之上的层无关,对使用(依赖)它的层次无感知。

在分层架构中,分层的使用可以严格地限制:分层只知道直接的下层,或者可以宽松一些:分层可以访问它之下的任何分层。Martin Fowler 和我自己的经验都是第二种方式实际中会更好,因为它避免了在中间分层创建代码方法(或者完整的代理类),也避免了退化成千层面的反模式(下文会详细探讨)。

有时分层会这样安排,领域层将数据源完全隐藏不让展现层看到。但是,更多的时候展现层会直接访问数据存储。这不那么纯粹,但实际却工作得更好。——Fowler 2002, Patterns of Enterprise Application Architecture

它的优势有:

  • 我们只需要了解我们工作的那层之下的层次;
  • 每个层次都可以用等价的实现替换,而不会影响到其它层次;
  • 层次是标准化的最佳候选;
  • 层次可以被多个不同的上级层次使用。

它的劣势在于:

  • 分层并不能封装一切(UI 中添加的字段,很可能也要添加到数据库) ;
  • 额外的分层会影响性能,尤其是位于不同物理层的时候。

◐ 20 世纪 60 年代和 70 年代


尽管上世纪 50 年代软件开发就开始了,它真正发展成我们今天所见的这样是在 60 年代和 70 年代,随着构建可以被发行、部署并可以被除了开发者自己之外其它人使用的应用的活动发展起来的。

然而,当时的应用程序和今天的应用程序截然不同。那时还没有 GUI(大概 80 年代末 90 年代初才出现),所有的应用程序要通过命令行使用,显示在一个哑终端里,它只是将用户的输入传输给应用程序,应用程序很可能就在同一台电脑中被使用。

image.png

应用程序此时还十分简单,还不需要分层,它们被部署到一台电脑之中被使用。它们实际上是单层的应用程序,尽管有时哑客户端还是远程的。尽管这些应用程序非常简单,但它们却无法伸缩,例如,如果我们需要升级软件的新版本,我们要在每台安装了该软件的电脑上升级。

◐ 20 世纪 80 年代和 90 年代的分层


在 20 世纪 80 年代,企业应用出现了,在公司里有多个用户开始使用桌面电脑通过网络访问应用。

这时它们多半分成三层:

用户界面(展现):用户界面就是网页、命令行或者原生桌面应用;

例如:作为(富)客户端的 Windows 应用,普通用户在桌面电脑上使用,和服务器器通信才能完成工作。客户端负责应用的流程和用户输入的校验;

业务逻辑(领域):应用之所以存在的逻辑;

例如:应用服务器,包含业务逻辑并从原生客户端接收请求,采取行动并将数据保存到数据存储;

数据源:数据的持久化机制(数据库),或者是和其它应用之间的通信。

例如:数据库服务器,应用服务器用它来完成数据持久化。

image.png

随着使用上下文的变迁,分层实践开始得到应用,尽管它真正得到大范围的实践是在 C/S 系统崛起的 20 世纪 90 年代。这实际上是一种 两层 应用,客户端是一个用为应用界面的富客户端应用程序,而业务逻辑和数据源放在服务器。

这种架构模式解决了伸缩性问题,因为很多用户可以独立地使用应用,只需要另外一台安装了客户端应用程序的桌面电脑就行。然而,如果我们有数百或者数十个客户端而我们想用更新应用程序的话,操作会特别复杂,因为我们要一个一个地更新客户端。

◐ 20 世纪 90 年代中期之后的分层


大约在 1995 年和 2005 年之间,随着普遍迁移到云的趋势,应用用户的增长,应用复杂性和基础设施复杂性的增加,我们终于看到了分层方案的变化。新的分层的典型实现如下:

  • 原生浏览器应用程序,渲染和运行用户界面,向服务器应用发送请求;
  • 应用服务器,包括了展现层、应用层、领域层和持久化层;
  • 数据库服务器,应用服务器用它来完成数据的持久化。

image.png

这就是三层架构模式,也叫 N 层架构。它是可伸缩的解决方案,尽管用户界面是在客户端浏览器中渲染和运行,但由于用户界面存放于服务器上并在服务器上编译,它“解决了客户端的更新问题”。

◐ 新世纪之后的分层


2003 年, Eric Evans 出版了他的标志性著作 Domain-Driven Design: Tackling Complexity in the Heart of Software。在书中提出的许多关键概念之中,也有对软件系统分层的展望:

image.png

用户界面

负责绘制用户和应用交互的界面,并将用户输入转换成应用的命令。值得注意的是,“用户”可以是人类也可以是其它应用。它和 Ivar Jacobson 的 EBI 架构(后面其它文章会介绍更多细节)中的边界对象不谋而合;

应用层

指挥领域对象完成用户要求的任务。它不包括业务逻辑。它和 Ivar Jacobson 的 EBI 架构中的交互器对象对应,唯一不同的是 Jacobson 的交互器可以是任意和界面或实体无关的对象;

领域层

这一层包含了所有的业务逻辑、实体、事件或者其它任何包含业务逻辑的对象类型。显然它和 EBI 中的实体对象类型相对应。这是系统的心脏;

基础设施

支撑上面所有层次的技术能力,如持久化机制和消息机制。

◐ 反模式:千层面架构


image.png

千层面架构常常说的就是分层架构的反模式。以下这些情况发会出现:

  • 我们决定使用严格的分层方法,也就是分层只感知得到它的直接下层。这种情况下,我们最终会创建代理方法甚至代理类,必须通过中间层次访问而不是直接访问需要的层次;
  • 热衷于创建完美的系统导致项目过度抽象;
  • 小更新也会波及应用的方方面面,例如,整理一个层次也会是风险巨大和收效甚微的大动作。
  • 层次太多,增加了整个系统的复杂性;
  • 物理层次太多,不但增加了整个系统的复杂性,还降低了系统的性能;
  • 我们明确地按照层次(UI、领域、数据库)来组织我们的单体,而不是根据子域/组件(例如,产品、支付、付款)来组织它,并因此破坏了领域概念的模块化和封装。

◐ 总结


分层架构是另一种根据代码在应用中的功能角色对代码单元进行划分的方式,它带来了关注点的分离、封装性和解耦。

然而,和生活中的很多事情一样,过犹不及!所以,最重要的一条经验是:只使用必要的层次和物理层次,够用就行!我们千万不要得意忘形地追逐架构的圣杯,它根本就不存在。存在的只是需求,和最可能恰好符合它的架构。顺便说一句,这也是精益所提倡的。

此外,还有一点值得注意,上/下这种纵向的分层方式已经过时了。现代的软件开发中我们不应该使用这种方式了,应用的层次有更好的新思路。我会在接下来的文章中进行探讨。

◐ 引用来源


  • 2002 – Martin Fowler – Patterns of Enterprise Application Architecture
  • 2003 – Eric Evans – Domain-Driven Design: Tackling Complexity in the Heart of Software
  • 2011 – Chris Ostrowski – Understanding Oracle SOA – Part 1 – Architecture
相关文章
|
2月前
|
人工智能 前端开发 JavaScript
前端架构思考 :专注于多框架的并存可能并不是唯一的方向 — 探讨大模型时代前端的分层式微前端架构
随着前端技术的发展,微前端架构成为应对复杂大型应用的流行方案,允许多个团队使用不同技术栈并将其模块化集成。然而,这种设计在高交互性需求的应用中存在局限,如音视频处理、AI集成等。本文探讨了传统微前端架构的不足,并提出了一种新的分层式微前端架构,通过展示层与业务层的分离及基于功能的横向拆分,以更好地适应现代前端需求。
|
19天前
|
数据库
分层架构
表现层(Presentation Layer):处理用户界面和用户交互逻辑。 业务逻辑层(Business Logic Layer):处理业务相关的逻辑和规则。 数据访问层(Data Access Layer):负责与数据库或其他数据源进行 [Something went wrong, please try again later.]。
|
2月前
|
JSON 前端开发 Java
Spring Boot框架中的响应与分层解耦架构
在Spring Boot框架中,响应与分层解耦架构是两个核心概念,它们共同促进了应用程序的高效性、可维护性和可扩展性。
65 3
|
2月前
|
存储 前端开发 API
DDD领域驱动设计实战-分层架构
DDD分层架构通过明确各层职责及交互规则,有效降低了层间依赖。其基本原则是每层仅与下方层耦合,分为严格和松散两种形式。架构演进包括传统四层架构与改良版四层架构,后者采用依赖反转设计原则优化基础设施层位置。各层职责分明:用户接口层处理显示与请求;应用层负责服务编排与组合;领域层实现业务逻辑;基础层提供技术基础服务。通过合理设计聚合与依赖关系,DDD支持微服务架构灵活演进,提升系统适应性和可维护性。
|
4月前
|
存储 消息中间件 JSON
|
5月前
|
人工智能 供应链 架构师
软件架构一致性问题之Serverless架构处理架构一致性问题如何解决
软件架构一致性问题之Serverless架构处理架构一致性问题如何解决
59 2
|
5月前
|
运维 Java Docker
业务系统架构实践问题之在某些情况下,将能力代码和业务逻辑严格分层可能是一个挑战问题如何解决
业务系统架构实践问题之在某些情况下,将能力代码和业务逻辑严格分层可能是一个挑战问题如何解决
|
5月前
|
存储 搜索推荐 API
业务系统架构实践问题之分层架构中的四层定位是什么
业务系统架构实践问题之分层架构中的四层定位是什么
157 0
|
5月前
|
缓存 项目管理
项目管理定义问题之DDD架构的分层架构中基础层作用是什么
项目管理定义问题之DDD架构的分层架构中基础层作用是什么
|
5月前
|
存储 消息中间件 Kafka
细说数据仓库分层架构
【7月更文挑战第20天】数据仓库分层架构包括缓冲层、操作数据层、明细数据层、汇总数据层和数据集市层。
下一篇
DataWorks