浅析应用分层架构

前言

       刚入职不久的程序员,进入公司看到项目代码的第一感觉就是和学校里面写的代码差别很大,主要体现在这两个方面:    

  1. 项目代码文件繁多、不理解为什么要分那么多文件。

  2. 看每一个代码文件不知所云,甚至不知道项目代码从何看起。

这背后的根本原因就是看待项目代码的思维有限,还是简单的“流水式、功能式”或者“脚本式”的编程思维。

因此了解应用的分层架构思想有助于提高我们思考的维度,提升对技术的理解。这也是所有程序员成为高手的必经之路。简单的只会利用每项技术实现某个功能,过于执著技术细节和实现方式就像建筑业的一线工人(此处没有贬低一线工人的意思),即便技巧再高超,影响范围和对生产力的推动也是线性的。特别是在AI到来的当下,纯粹高超的编程技巧已经不再成为一名程序员的核心竞争力,我们也不能再因为可以手写10种不同的排序算法而沾沾自喜,因为AI生成只需要10秒,还能帮你优化出最好的代码。

而我们的核心竞争力是成为真正的工程师,面对复杂的业务和场景,可以像“庖丁解牛”般,用我们系统的思维和眼光,对复杂任务进行拆分与归纳,将庞大的系统进行合理的设计,充分发挥团队的生产力,让系统在经历复杂的业务变化和项目迭代中,依然具备生命力。

分层架构的演进

3 层架构:表现层 —逻辑层—数据访问层

这应该是很多人最熟悉的分层方式了,这种架构方式在单机应用的时代非常常见,整个项目可能就是一个应用,整个项目在一台服务器上部署运行,项目代码庞大。架构图大致如下:

用户界面层:主要就是前端用户界面,这一部分的开发主要由前端负责,实现界面上的组件渲染逻辑和用户交互效果,一般与业务逻辑和数据无关。有时候后端接收前端请求的Controller接口也被包含在了这一层内。因为Controller主要是对前端的接口进行处理,并调用业务逻辑层的服务后组装参数返回,一般不包含具体的业务逻辑。

业务逻辑层:这一部分包含主要的业务逻辑和对业务数据的处理。因此如果业务复杂(一般公司的项目业务逻辑都不简单),这一部分可以说是非常的“厚重”,臃肿的代码会成为整个项目中最复杂的部分,也最容易成为系统性能和扩展的瓶颈。

数据访问层:主要是对业务逻辑层提供持久化储存的接口,对数据库进行操作。在数据访问层可能会对业务实体进行拆分存储。尽量保持实体间的独立性,也存储实体间的映射关系或者关联关系。

3层架构存在以下问题:

1.无法应对复杂业务:3层架构适合简单的项目,如果项目的业务逻辑复杂,实体间的关系存在多样组合,不同的业务场景设计到的实体关系不同,就会导致业务逻辑层中的代码混乱,每当业务修改或者需求迭代涉及到需求修改,特别是需要重组实体间的关系时,改代码都是一件非常痛苦的事情。

2. 不适应云计算和分布式的时代:在云计算时代,企业部署应用不需要再花费巨额资金购买服务器,服务器资源不再成为限制应用的瓶颈,因此大的业务应用可以拆分成各个独立应用,根据各个应用的职责独立部署、分布式部署,这样便于应用的维护和管理。

3. 不方便团队协作的项目开发方式:业务逻辑层的功能模块之间耦合严重,牵一发而动全身,这为团队间的协作开发造成了非常大的麻烦,有时候动了一处代码,会造成其他地方的Bug,找Bug的时间甚至超出了新功能开发的时间。

4. 不利于系统的横向扩展:当业务发展壮大的时候,往往系统会出现“瓶颈”,这时候系统的架构或者资源就要进行横向扩展,这时混乱的"业务逻辑层"会为系统的横向扩展造成很大的麻烦,要么就是整个系统一起扩展,浪费资源;要么就是代码杂乱、无法扩展。

3层分层架构的思维方式本质上还是“数据库思维”,只注意到了业务上需要对数据库的数据进行读取和处理,流程是“页面请求 —> 处理业务数据 —> 读写数据库 ”,没有关注到业务中更核心应该维护和治理的是业务领域的实体、以及实体间的关系。

基于3层架构出现的各种问题,不能适应现代分布式、云计算的软件系统工程。业界提出了领域驱动设计的分层架构(DDD架构)。

DDD分层架构详解

如其名,“领域驱动设计”分层架构的核心是关注特定业务领域的实体和实体间的关系,并以领域服务的方式开放领域能力。DDD的架构图如下:

用户接口层:包含用户界面的controller接口、对外的服务接口等,一般是项目的入口。

应用层:这是DDD架构和3层架构中差别比较大的一层。应用层应该是比较薄的一层,不应该含有业务逻辑和业务规则,而更多的是调用领域层提供的原子性的领域服务进行服务编排和组合,协调多个领域的实体完成业务流程。

应该特别注意的是:应用层不应该包含业务领域的实体和规则,否则DDD架构会逐渐演变为3层架构,本该在领域层的领域业务逻辑就会失焦。时间一长,业务逻辑将散落在应用层和领域层之间,变得难以维护,违背了领域驱动设计的初衷。

领域层:领域层是整个项目的核心与关键,包含了企业业务的实体、以及业务的核心逻辑,实体和业务逻辑共同组成了领域模型。领域层要确保业务逻辑的正确性和完备性,同时在划分模型时,要注意模型间的独立性(比如财务领域,单据和合同不属于同一个模型,应该划分清楚,各自提供相应领域的领域服务,在应用层进行服务编排与组合,而不要在领域层将二者的逻辑混在一起)。

基础层:也被称为基础设施层或防腐层,这一层主要是对底层的数据库、事件、消息、定时器、缓存、第三方服务等底层基础能力进行封装和适配。这一层的存在主要是为了隔离外部基础组件或外部基础服务对系统代码的侵入,保持项目代码的纯洁性和独立性,换句话说,如果未来有涉及到需要更换外部服务或中间件,应该只需要改动这一层的代码进行适配,不要需要调整其他层代码,这就是“防腐层”的意义。

从架构图中可见,基础设施层可以为其余的3层提供基础设施服务能力,能力一般以RPC服务的方式提供。

3层架构向DDD架构的演变过程大概如下图所示:

这里需要特别提醒:在DDD架构中,核心是领域层的代码,这部分是包含了业务最核心的业务实体与业务逻辑,是整个项目中最重要的一部分,因此维护这部分代码的纯洁性至关重要。

理论上讲,这部分的代码需要可以在任意的环境无缝迁移,迁移时只需要修改其他层的代码,不需要修改领域层代码。

为了解除领域层对基础设施层的依赖,可以通过依赖倒置的方式:在基础设施层建立“仓储服务”,通过仓储服务向领域层提供底层能力,这样使得基础设施层依赖领域层,而领域层代码不依赖任何层次代码,以此保证代码的纯洁性。

DDD分层架构的好处

应用分层的核心是:梳理出每个层次的边界。每个层次的职责独立、边界清楚,才能实现对系统的“分而治之”。DDD分层架构的核心是将业务核心的实体与业务逻辑在领域层内聚,抽象出应用层来调用领域层的领域服务,进行服务编排和组合,是各领域模型互相协作,以此实现业务需要。

DDD架构有如下几点好处:

  1. 代码高内聚低耦合,方便维护:当各层次的代码边界清晰时,我们对系统需要进行修改时就只用对相关的层次代码进行调整,相似的逻辑不会散落在各处。

  2. 便于团队分工合作、每个层次独立部署:合理的系统划分可以最大程度发挥团队的生产力,团队成员之间的负责内容会相对比较独立,大家的精力可以更多聚焦在其他有价值的地方,不用为了彼此兼容而反复拉扯。

  3. 便于系统的细致横向扩展和局部优化:当系统的体量或流量变大时,层次分明、职责清晰的项目结构可以帮助我们识别项目的瓶颈,我们只需要对瓶颈代码进行横向扩展和局部优化,这样更具备针对性。

  4. 便于代码的复用:职责清晰、功能聚焦的代码相比混乱臃肿的代码,更加值得被复用和学习。

其实用心体会就能发现,我们对项目进行分层设计,只不过是遵守了软件设计的原则:

  • 单一职责原则:规定每个类只有单一的功能。在这里可以引申为每一层拥有单一职责,且层与层之间边界清晰;

  • 迪米特法则:原意是一个对象应当对其它对象有尽可能少的了解。在分层架构的体现是数据的交互不能跨层,只能在相邻层之间进行;

  • 开闭原则:要求软件对扩展开放,对修改关闭。它的含义其实就是将抽象层和实现层分离,抽象层是对实现层共有特征的归纳总结,不可以修改,但是具体的实现是可以无限扩展,随意替换的。

掌握这些设计思想会自然而然地明白分层架构设计的妙处,同时也能帮助我们做出更好的设计方案。

分层的缺陷

凡事都是一体两面。分层架构也不是完美的,我们只能说在具体某种场景下,DDD分层架构是比较合适、合理的架构设计。DDD分层架构设计也有他的缺陷:

  1. 增加代码的复杂度:代码被划分成了多个层次,要求我们理解代码时,不但要有“纵向思维”:从一个接口到最后的数据库读写,理解整个完整的业务流程(新手入门一般这么看代码)。更要有“横向思维”:从宏观上了解代码的结构和层次,熟悉每个层次的边界,边界越清楚,对项目的理解越深刻。

  2. 性能打了折扣,多一跳问题:分层之后,各层次代码可能独立部署,相邻层次之间一般通过RPC接口调用其服务,这样导致性能上打了一下折扣,因为要多一次层次之间的调用,会出现“多一跳”问题。

思考

我们思考这样一个问题:为什么现代企业软件的开发被称为“软件工程”。我们一般不叫“软件科学”、“软件学术”。因为在一个软件技术完善成熟的时代,开发软件是一个“工程问题”。工程问题代表了追求标准化、高效率、稳定、不断迭代。因此也许分层架构会有缺陷,但是和它带来的好处相比,缺陷也是可以接受的。合理的分层架构可以满足工程中规范、高效率、标准、稳定的要求。

参考文章

  1. 《一篇文章读懂分层架构》:一篇文章读懂分层架构

  2. 《三层架构如何演进到 DDD 分层架构?》:07 | DDD 分层架构:有效降低层与层之间的依赖 | NOTE-BOOK2

  3. 《什么是三层架构?》:什么是三层架构 | IBM

  4. 《架构分层:我们为什么一定要这么做?》:02丨架构分层:我们为什么一定要这么做? | JAVA 架构师笔记

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值