成为工程师 - 系统分层的设计原则

简介: 成为工程师 - 系统分层的设计原则

今日内容



上一篇文章的末尾我们留了一个问题:


“在传统分层中,处于越下方的层次,就应该越稳定,而传统分层中最下层是数据层。数据层随着业务的发展,是非常有可能升级、换框架乃至换底层存储的。如果哪天数据层要更新,难道要整个系统重构吗?”


这其实只是系统分层中的一个问题。我们今天以这个问题为引子,来聊聊系统分层的原则。



原则1:低层次修改对高层次透明空说没有体感,我们从一个反例开始


反例时间


假设我们有一个用户查询服务,通过用户id查询用户信息


我们的设计如下所示(按照我们上一篇文章说的典型分层方式):



下图是具体在代码中的目录结构:



接下来,我们看下具体的代码:接口层:UserController



服务层:UserService



数据层:UserDAO



从例子中大家可以看到,数据库的访问使用的是直接撸jdbc的方式来做的,显然这种方式已经过时了。

某一天架构师大喊一声:“我们要使用mybatis来替换掉这种jdbc的数据库访问方式”。


于是,我们可能会这样修改代码:


首先先添加一个mybatis的数据层:


mybatis数据层的实现:


UserService的修改:



到这里你有没有发现一个问题。那就是数据层DAO的替换居然影响了业务Service层!


所以,这里也就引出了我们的第一个原则:【低层次修改应该对高层次透明】


那要怎么达到这个效果呢?就是遵循一个非常重要的设计原则:【依赖抽象而非具体】


我们可以把最初的设计进行如下修改:



UserDAO代码修改如下:



UserService代码修改如下:


需要替换Mybatis框架时,只需要


【1】使用mybatis实现数据层逻辑。

【2】将JdbcUserDAO的@Repository注解去掉。


spring就会自动为UserService装载MybatisUserDAO了


事实上,真实的情况会比例子更加复杂。例如在切换DAO层时,往往会涉及灰度切流或者双读的情况。这个时候中间可以再加一层代理,来控制新旧DAO的使用方式,如下图:


到这里,相信你已经明白【依赖抽象不要依赖具体】的含义和具体用法。


事实上,这个原则可以说是软件系统设计中最重要的原则。


我们常提“高内聚低耦合”,这个原则可以帮助我们尽量地降低耦合。


另外,不仅仅是在数据层,任何层次之间的依赖都应该遵循这个原则,大部分模块的设计其实也应该遵循这个原则。


这个原则以及解题思路也回答了上一篇文章留下来的“依赖不合理”问题。


原则2:不要跨层依赖


系统分层要求调用只能是上层调用下层。在这个大准则下,其实又有两种分层依赖模式,我们称之为【严格分层架构】和【松散分层架构】。


【严格分层架构】:每一层只能调用其下面一层提供的能力。

【松散分层架构】:每一层可以调用处于其下方所有层次的能力。

我们可以结合下面的图示来理解:


这两种分层架构方式各有利弊:

其实从图示你也可以看出,我更推荐【严格分层架构】。虽然在一些情况下,遵循严格的规范会带来一些麻烦,但是其带来的好处还是更多的。图中列了几项【严分层构】的好处,其中我觉得最重要的还是第2点,那就是对业务逻辑和数据的保护。


举个例子,如果用户信息表中有保存身份证号,那么领域层可以对身份证号做脱敏再向上返回。如果我们允许接口层直接访问数据层拿用户信息,那身份证号就很容易泄露。


在整个分层架构中,每一层除了提供向上的能力,也提供向下的保护。这一点往往很多同学没有意识到。



原则3:确定每一层的边界


无论你是否根据传统分层方式对系统进行分层,在分层之后,要确定每一层的边界。所谓的边界是指:不能做什么


例如在传统分层方式中:


【接口层】:对出入参仅做格式上的校验,不能涉及“例如用户是否在黑名单中”这样的校验。

【服务层】:负责编排流程、处理rpc请求、控制同异步。不能涉及领域概念。

【领域层】:针对领域规则来实现具体的能力,不能跨领域。

【数据层】:仅对数据做CRUD,不能涉及对数据的额外加工。

那,为什么要强调边界呢?

【防止冗余】:例如计算支付手续费的逻辑没有内聚在领域层,就等于存在冗余逻辑,如果以后修改就有冗余的工作。更危险的是,容易漏

【便于拆分】:微服务盛行的当下,拆分服务司空见惯。

【便于替换】:例如数据层要换框架,如果数据层还涉及业务逻辑,就变得复杂多了。


今日总结


讲到这里,我们就把系统分层的设计原则讲完了。

相关文章
|
5月前
|
Java 持续交付 数据库
避免服务分层污水池反模式
【6月更文挑战第30天】本文介绍污水池反模式,分层架构在敏捷性、部署性和性能方面得分较低,但具有高测试性和易开发性。关键在于合理分层以降低耦合和提高解耦效果。
257 1
避免服务分层污水池反模式
|
3月前
|
设计模式 架构师 数据建模
架构师必备底层逻辑:设计与建模的技术深度探索
【8月更文挑战第13天】在软件开发的浩瀚星海中,架构师如同星辰指引,他们不仅规划着系统的蓝图,更在底层逻辑上精雕细琢,确保系统的稳健与高效。其中,“设计与建模”作为架构师的核心能力之一,是连接业务需求与技术实现的桥梁。本文将深入探讨架构师在设计与建模过程中的关键思维与实践方法,为工作学习中的技术同仁提供一份宝贵的干货分享。
47 3
|
4月前
|
存储 设计模式 前端开发
软件架构设计的原则与模式:构建高质量系统的基石
【7月更文挑战第26天】软件架构设计是构建高质量软件系统的关键。遵循高内聚、低耦合、单一职责等设计原则,并灵活运用分层架构、微服务架构、客户端-服务器架构等设计模式,可以帮助我们设计出更加灵活、可扩展、可维护的软件系统。作为开发者,我们应该不断学习和实践这些原则与模式,以提升自己的架构设计能力,为团队和用户提供更加优秀的软件产品。
|
6月前
|
存储 设计模式 编译器
软件体系结构 - 复杂指令集架构 (CISC)
【4月更文挑战第18天】软件体系结构 - 复杂指令集架构 (CISC)
236 6
|
6月前
|
前端开发 Oracle 安全
软件架构设计 C/S与B/S架构的区别
C/S是Client/Server的缩写。服务器通常采用高性能的PC、工作站或小型机,并采用大型数据库系统,如Oracle或SQLServer。
74 0
|
消息中间件 缓存 架构师
【老猿说架构】系统架构设计原则和步骤
【老猿说架构】系统架构设计原则和步骤
355 0
【老猿说架构】系统架构设计原则和步骤
|
设计模式 缓存 监控
【软件架构】支持大规模系统的设计模式和原则
【软件架构】支持大规模系统的设计模式和原则
架构:第九章:架构设计(为什么要这么设计,解决了什么问题)
架构:第九章:架构设计(为什么要这么设计,解决了什么问题)
129 0
|
XML 设计模式 JSON
领域驱动设计总结——如何设计大型系统
本文为领域驱动设计系列总结的第五篇,主要对领域驱动设计概念做个介绍,本系列领域驱动设计总结主要是在Eric Evans 所编写的《领域驱动设计》 一书的基础上进行归纳和总结。本文主要介绍在领域驱动设计中如何设计大型系统。
189 0
|
存储 Oracle 关系型数据库
软件架构编年史:分层架构
软件架构编年史:分层架构
软件架构编年史:分层架构