一文读懂分层架构

精通包括 Java、Scala、Python、C#、JavaScript、Ruby 等多种语言,熟练掌握面向对象思想、测试驱动开发与重构、领域驱动设计、函数式编程、架构、大数据分析、敏捷与过程改进,并致力于大型软件企业的面向服务系统架构设计、大数据平台架构设计以及互联 Web 系统架构设计。

著译作包括《软件设计精要与模式》、《Java 设计模式》、《恰如其分的软件架构》、《WCF 服务编程》、《人件》、《重构——改善既有代码设计》评注版、以及《架构之美(Beatiful Architecture)》评注版。

认识分层架构

分层架构是运用最为广泛的架构模式,几乎每个软件系统都需要通过层(Layer)来隔离不同的关注点(Concern Point),以此应对不同需求的变化,使得这种变化可以独立进行;此外,分层架构模式还是隔离业务复杂度与技术复杂度的利器,《领域驱动设计模式、原理与实践》写道:

为了避免将代码库变成大泥球(BBoM)并因此减弱领域模型的完整性且最终减弱可用性,系统架构要支持技术复杂性与领域复杂性的分离。引起技术实现发生变化的原因与引起领域逻辑发生变化的原因显然不同,这就导致基础设施和领域逻辑问题会以不同速率发生变化。

这里所谓的“以不同速率发生变化”,其实就是引起变化的原因各有不同,这正好是单一职责原则(Single-Responsibility Principle,SRP)的体现。Robert Martin 认为单一职责原则就是“一个类应该只有一个引起它变化的原因”,换言之,如果有两个引起类变化的原因,就需要分离。单一职责原则可以理解为架构原则,这时要考虑的就不是类,而是层次。我们为什么要将业务与基础设施分开是因为引起它们变化的原因不同。

经典分层架构

分层架构由来已久,将一个软件系统进行分层,似乎已经成为了每个开发人员的固有意识,甚至不必思考即可自然得出。这其中最为经典的就是三层架构以及领域驱动设计提出的四层架构。

经典三层架构

在软件架构中,经典三层架构自顶向下由用户界面层(User Interface Layer)、业务逻辑层(Business Logic Layer)与数据访问层(Data Access Layer)组成。该分层架构之所以能够流行,是有其历史原因的。在提出该分层架构的时代,多数企业系统往往较为简单,本质上都是一个单体架构(Monolithic Architecture)的数据库管理系统。这种分层架构已经是Client-Server架构的进化了,它有效地隔离了业务逻辑与数据访问逻辑,使得这两个不同关注点能够相对自由和独立地演化。一个经典的三层架构如下所示:

追溯分层架构的本源

当分层架构变得越来越普及时,我们的设计反而变得越来越僵化。一部分软件设计师并未理解分层架构的本质,只知道依样画葫芦地将分层应用到系统中。要么采用经典的三层架构,要么遵循领域驱动设计改进的四层架构,却未思考和叩问如此分层究竟有何道理是分层架构被滥用的根源。

视分层(Layer)为一个固有的架构模式,其滥觞应为 Frank Buschmann 等人著的《面向模式的软件架构》第一卷《模式系统》。该模式参考了 ISO 对 TCP/IP 协议的分层。《模式系统》对分层的描述为:

分层架构模式有助于构建这样的应用:它能被分解成子任务组,其中每个子任务组处于一个特定的抽象层次上。

显然,这里所谓的“分层”首先是一个逻辑的分层,对子任务组的分解需要考虑抽象层次,一种水平的抽象层次。既然为水平的分层,必然存在层的高与低;而抽象层次的不同,又决定了分层的数量。因此,对于分层架构,我们需要解决如下问题:

  • 分层的依据与原则是什么/li>
  • 层与层之间是怎样协作的/li>

分层的依据与原则

我们之所以要以水平方式对整个系统进行分层,是我们下意识地确定了一个认知规则:机器为本,用户至上。机器是运行系统的基础,而我们打造的系统却是为用户提供服务的。分层架构中的层次越往上,其抽象层次就越面向业务,面向用户;分层架构中的层次越往下,其抽象层次就变得越通用,面向设备。为什么经典分层架构为三层架构是源于这样的认知规则:其上,面向用户的体验与交互;其中,面向应用与业务逻辑;其下,面对各种外部资源与设备。在进行分层架构设计时,我们完全可以基于这个经典的三层架构,沿着水平方向进一步切分属于不同抽象层次的关注点。因此,分层的第一个依据是基于关注点为不同的调用目的划分层次。以领域驱动设计的四层架构为例,之所以引入应用层(Application Layer),就是为了给调用者提供完整的业务用例。

分层的第二个依据是面对变化。分层时应针对不同的变化原因确定层次的边界,严禁层次之间互相干扰,或者至少将变化对各层带来的影响降到最低。例如数据库结构的修改自然会影响到基础设施层的数据模型以及领域层的领域模型,但当我们仅需要修改基础设施层中数据库访问的实现逻辑时,就不应该影响到领域层了。层与层之间的关系应该是正交的。所谓“正交”,并非二者之间没有关系,而是垂直相交的两条直线。唯一相关的依赖点是这两条直线的相交点,即两层之间的协作点。正交的两条直线,无论哪条直线进行延伸,都不会对另一条直线产生任何影响(指直线的投影)。如果非正交,即“斜交”,当一条直线延伸时,它总是会投影到另一条直线,这就意味着另一条直线会受到它变化的影响。

在进行分层时,我们还应该保证同一层的组件处于同一个抽象层次。这是分层架构的设计原则,它借鉴了 Kent Beck 在 Smalltalk Best Practice Patterns 一书提出的“组合方法”模式。该模式要求一个方法中的所有操作处于相同的抽象层,这就是所谓的“单一抽象层次原则(SLAP)”。这一原则可以运用到分层架构中。例如在一个基于元数据的多租户 表系统中,我们特别定义了一个引擎层(engine layer),这是一个隐喻,相当于为 表系统提供 表、实体与数据的驱动引擎。引擎层之下,是基础设施层,提供了多租户、数据库访问与元数据解析与管理等功能。在引擎层之上是一个控制层,通过该控制层的组件可以将引擎层的各个组件组合起来。分层架构的顶端是面向用户的用户展现层。如下图所示:

整个架构模型清晰地表达了领域层别无依赖的特质,但整个架构却容易给人以一种错乱感。单以这个分层模型来看,虽则没有让高层依赖低层,却又反过来让低层依赖了高层,这仍然是不合理的。当然你可以说此时的基础设施层已经变成了高层,然而从之前分析的南向 关与北向 关来说,基础设施层存在被“肢解”的可能。坦白讲,这个架构模型仍然没有解决人们对分层架构的认知错误,例如它并没有很好地表达依赖倒置原则与依赖注入。还需要注意的是,这个架构模型将基础设施层放在了整个分层架构的最顶端,导致它依赖了用户界面层,这似乎并不能自圆其说。我们需要重新梳理领域驱动架构,展示它的演进过程。

本课程限时特价 39 元,共计 34 篇,形式为“图文+音频”;特价截止日期: 7月30日 。

扫码试读或点此试读购买
一文读懂分层架构

声明:本站部分文章及图片源自用户投稿,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!

上一篇 2018年6月21日
下一篇 2018年6月21日

相关推荐