对企业级应用开发的思考 -----分层

首先声明,本文并不是介绍什么是N层架构,然后给张分层图,最后来一堆代码结束。本文主要是对分层过程中常常让人感到困惑地方的思考,以及最近园子里面讨论异常激烈的一些问题的再讨论。本文从个人经验角度出发,努力尝试来解决这些困惑,欢迎拍砖,但,如果你进行人生攻击,我也只能在心里画个圈圈诅咒你一下!

开始

我们先从一幅大家眼熟能详的图开始:

这是应用开发人员最熟悉的N层架构图,其中:

  • 数据访问层:应用程序中全权负责与数据存储对话并持久保存和检索业务对象的层。通常,数据访问层包括所有的CRUD 方法与查询机制,使得业务逻辑层能够针对任何给定的条件检索对象。
  • 业务逻辑层:它包含定义和处理复杂业务功能的所有规则、工作流和验证逻辑,设计软件以满足这些复杂的功能;困惑最多的地方就是这一层。
  • 应用层:封装业务模型,并为所有相关的应用程序提供接口。关于应用层,有一个十分让人困惑的地方,后面会详细说明。

这是三层的简单定义,当开发者看到这些定义的时候,基本都会有这么一个感觉:哦!也就这么回事。可是在实际编写代码时,尤其是随着项目代码量越来越多,业务越来越复杂的时候,会明显觉得:

要改这个业务,又要去改数据层的CRUD,太难受了;

这个操作不分层,我一个函数调用就搞定了,为什么一分层,我要嵌套这么多层,太恶心了;

...

当你有这些感觉的时候,请停下手头上的工作,思考一下,有没有因为遇到下面这些情况让你感觉到困惑。

困惑1:层之间的依赖关系

该图引用自jesse liu的博客(如有侵权请告知,我会在第一时间修改,实在是懒得画),我觉得很形象。上面是常见的三层中的依赖关系。下面是在领域驱动设计下的依赖关系。不要小看这个图,可以肯定的是90%以上的开发人员在开发过程中对N层架构的依赖关系是这样的,哪怕是在使用领域驱动进行设计时,无形中也摆脱不了这种依赖关系。初学者一般觉得这种依赖关系很正常啊?本来就应该是这样的。造成这种思想的根本原因是初学者通常觉得DAL层(或DDD中的repository)可以方便给其他系统调用呀?不就实现复用了吗?我的BLL层也可以....

打住,请打住!!你的BLL层能复用?你的BLL层已经在依赖DAL了。

DAL能复用?是能复用。但,对于特定的开发系统来说,DAL层的复用毫无意义。你会把图书管理系统中的DAL复用给博客网站吗?除了能复用最基本的ADO操作之外,你什么都复用不了。

所以,层之间的引用应该设计成这样的:

好吧,图还是jesse liu的。这个图很形象的说明了我们该如何处理层之间的依赖关系。因为系统中真正可以复用的其实是这样的BLL层。它不依赖任何层,对于特定的系统来说,无论你的数据库变了,界面变了,但核心的业务其实是比较稳定的。其实该实现方式的核心思想就是大名鼎鼎的依赖倒置。实现方式可以使用反射或IOC等进行,可以参考园中其他小伙伴的文章或我的另一文:通用数据采集平台,从架构到代码 。

困惑2:业务逻辑层实现方式的选择

业务逻辑层实现方式有三种:事务脚本活动记录领域模型。现在园子里面大兴DDD之风,对领域驱动设计推崇倍至,你要是和他说其实这个用事务脚本封装一下,那个来点活动记录集搞搞就行了。保证他立马喷的你体无完肤。常言道:存在即合理。前两种实现模式自打程序设计出现以来,有着悠久的历史。这里我们简单介绍一下它们及说明一下他们的适用场景。

事务脚本(Transaction Script)

名字叫的很玄乎,其实说直白点它就是使用一系列功能函数来实现系统的业务逻辑。它遵循面向过程的开发方式,而不是面向对象的方法。核心思想是为每个业务创建一个过程,每个过程都包含完成业务事务所需要的所有业务逻辑,包括从工作流、业务规则和验证检查到数据库持久化保存的所有内容。

从各大经典教材上来看,它适用于具有很少逻辑或没有多少逻辑的简单应用程序,在用户界面中实现所有的业务逻辑。在实际操作中,将应用程序分成小的功能模块,分别将它们实现成用户界面,并在其中嵌入业务规则。这时采用自动化程度最高的用户界面创建工具(比如ASP.NET中的服务器控件)和可用的可视化编程工具进行开发。

活动记录(Active Record)

该模式对于数据库中的每个表都存在一个对应的业务对象。业务对象代表数据表中的一行,在业务对象中包含数据和行为,同时包含用于持久化对象的方式及添加新实例和查找数据集合的方法。

适用于业务只是在数据库之上加一个显示处理界面。在有些精典书籍中提出,以EF与linqtosql为代表的数据访问对象模式(DAO)最适合的就是这种场景。它们都通过一个数据上下文(DbContext)作为入口,实现业务对象与数据表的对应。但个人认为EF(linqtosql用的较少)经过多个版本的演化,已经摆脱了一对一映射的限制。完全适用于领域模型。

领域模型(Domain)

该实现模式与活动记录非常相似,它与活动记录集的主要差异就是:领域模型的业务实体不知道如何持久化自身,且数据模型与业务模型之间并不是一定要存在一对一映射的关系。

关于该模型的文章有很多。这里就不详细介绍。它适用于对复杂业务逻辑进行建模,至于这个复杂业务逻辑的标准是什么,我也在探索中。我想有些开发者使用它是为了表现自己的技术能力。其实完全没有必要。个人觉得理解它的思想就行,在一些小项目中能不用尽量不要去用。折腾自己也折腾同事。

这里要特别说明一点的是:因为业务实体并不知道自己如何持久化,所以领域模式依赖于ORM或Repository模式来持久化。我们在这里的依赖并不是在设计时领域要依赖下面的数据操作,而是领域层最终要靠ORM或Repository来实现数据存储的读写。DDD设计中最大的争论也就此展开:Repository模式到底有没有必要,尤其在使用EF的情况下。我们单独为此开一个专题。

困惑3:Repository模式

Repository的争论曾经在园子深挖DDD的几位牛人圈子里面持续了一段时间:

初探领域驱动设计(2)Repository在DDD中的应用

Repository 仓储,你的归宿究竟在哪?(一)-仓储的概念

尤其是当用EF实现Repository时,争论可以达到惨烈的程度:

博客园的大牛们,被你们害惨了,Entity Framework从来都不需要去写Repository设计模式

那段时间我也是看着他们的文章,陪着他们一起困惑,一起纠结。但某个风高月黑的晚上。我突然间有了以下想法:

领域模型的业务实体不知道如何持久化自身,如果我们想把这些实体存储到电脑中,我们必定需要一个可以持久化的方法。方法太多了,ADO.NET、linqtosql、EF等等,于是我们提取一个数据化的接口在业务逻辑层,取个名字叫Ixx..叫什么呢?Martin Fowler大大说叫IRepository吧,于是Repository模式就出来了。记住:这里在业务逻辑层里面添加的是接口,而不是实现,这很重要!

其实我赞同Leo C.W在那篇慷慨激昂的文章里面提到的观点:EntityFramework 本身就是基于Repository设计的,我也赞同他说的那些EF+Repository包裹后的缺点。但,这不足以让我们抛弃Repository,哪怕是和EF做搭档。当他们两个一起工作的时候,Repository可以理解为设计模式中的适配器模式。为了保持整个设计的接口统一,为了协调领域和数据映射层。因为如果在业务逻辑层里面直接使用EF,你的领域就已经不再是纯洁的领域。所以我在上面一段结尾的时候强调了在业务逻辑层里面添加的是IRepository接口。

而且就像我在困惑2中提到的一样,当你选择使用领域模型的时候,就可以假定你所处理的业务逻辑比较复杂,而且需要兼顾扩展性(比如数据库更换),所以Repository有存在的意义。如果你的项目属于短期的项目,或者说你不用考虑更换数据访问层,你大可直接选择活动记录模式,那么如果你不想用Repository,那就不用。不然直白点说:你用领域就是为了装那个啥。

困惑4:应用层

很多人觉得这一层很简单,就是处于界面与业务逻辑之间的一个外观模式。但,就像田园里的蟋蟀说的一样:

    有时候我们在领域驱动设计的时候最容易混淆的就是应用层和领域层,网上关于领域层和应用层的定义概念一搜一大把,你可能也会说几句,比如什么应用层是很薄的一层,主要工作是协调任务的等等,但是实践起来呢?用代码表示就蒙了。

对于某个XXService,你会无比纠结它到底是放在业务逻辑层中还是应用层中,尤其是像我这种对代码整齐有洁癖的人,更是痛不欲生。蟋蟀后来提出:


应用层很薄,所做的工作是:

  1. 发起一个请求
  2. 确认处理结果
  3. 提交工作单元

看到他的这个观点,瞬间让我想到《ASP.NET设计模式》这本书中的一个观点:Document Message消息传送模式。作者在应用层里面唯一做的一件事情就是把所有的界面逻辑封装成一个Request,然后通过业务逻辑层中的功能组合计算出一个Response,返回给界面(详见该书6.3.2章节)。

综合上面的两点经验,也算是给我们指明了一条怎样使应用层“变薄”的出路了。

总结

真正对分层进行研究是因为公司里面一个水务集团的项目,数据量业务逻辑都相对比较复杂,当时硬着头皮要求使用领域驱动设计,结果很悲惨。项目一半的时候大家都被折磨疯了,那时才知道我们离真正的建模差距有多大。我们以前的分层,无非是借着面向对象的外壳,使用类来进行面向过程的分层罢了。中间为了设计模式而设计模式,为了分层而分层。后来项目虽然完工,但远没达到我心目中的期望。于是静下心来,看了园子里面很多这方面的文章,记录下些许心得。还请各位大大不吝指教,感谢!

时间: 2024-10-15 19:42:52

对企业级应用开发的思考 -----分层的相关文章

对企业级应用开发的思考(2)--会话状态

在我们使用HTTP协议进行应用开发的的时候,通常服务器端是不关心请求是从哪个客户到来的,客户端也不并不关心服务器端是通过生成哪个对象处理的这次请求.这就是我们通常说的HTTP无状态请求,从技术的角度上讲是因为: 客户端和服务器用TCP Socket通信,服务器将请求结果返回给浏览器后,通常会关闭Socket连接: 服务器会在处理页面完毕后销毁页面对象: HTTP协议本身就是一个无状态协议: 举个例子,如返回一个Web页面告诉你关于一个商品的信息.可以通过访问一个URL请求服务器.在URL中带有该

Swift项目开发实战-基于分层架构的多版本iPhone计算器-直播公开课

本课程采用Q Q群直播方式进行直播,价值99元视频课程免费直播.完整的基于Swift项目实战,手把手教你做一个Swift版iPhone计算器.(直播过程也有惊喜!)直播Q Q群:362298485(直播时点击群视频即可进入直播课堂)直播时间:8月26日(周二),9月2日(周四),每天20:00-22:00欢迎咨询客服Q Q:1575716557直播后希望继续深入学习了解本课程可在51CTO学院购买本课程,定价99元.购买课程更有惊喜:买课程送书,送优惠券了! 购买本课程赠送关东升老师价值69元国

NET中小型企业级项目开发架构系列(一)

前端时间我们开发了基于Net的一套搭建sprint.NET+NHibernate+MVC+WCF+EasyUI等中小型企业级系统开发平台,现在把整个开发过程中的步步进展整理出来和大家分享,这个系列可能有点长,多多指导学习.        我们的底层开发平台是sprint.NET+NHibernate+MVC+WCF+EasyUI方式开发,顺便加点Spring.net注入的部分,当然我们最主要的关于权限设计.业务设计,而架构,咱们没有学过太复杂的架构,我们还是以最常用的MVC架构开始拓展 参考材料

企业级快速开发平台

需要商业合作或者项目外请联系我:QQ 909994561  手机 18768868380 个人邮箱 [email protected] 谢谢合作! 企业级快速开发平台,布布扣,bubuko.com

基于Appium的自动化case开发及case分层结构设计

基于Appium的自动化case开发及case分层结构设计 首先为每条case创建一个公共的基类AppiumTestBase,内含setup和teardown两个方法,以后每条case继承该基类即可.代码如下: public class AppiumTestBase { public WebDriverWait webwait; private AndroidDriver driver; @Before public void setUp() throws Exception { File cl

Spring Boot 企业级应用开发实战

Spring Boot 企业级应用开发实战[下载地址:https://pan.baidu.com/s/1SbB-auGkUN6r2i6dtv7t_w ] Spring Boot是目前Spring技术体系中炙手可热的框架之一,既可用于构建业务复杂的企业应用系统,也可以开发高性能和高吞吐量的互联网应用.Spring Boot框架降低了Spring技术体系的使用门槛,简化了Spring应用的搭建和开发过程,提供了流行的第三方开源技术的自动集成. Spring Boot是由Pivotal团队提供的全新框

三月惊喜降临,带你彻底理解PHP企业级应用开发!

三月初始,全国各地有条不紊进入复工状态,面试竞岗日渐被提上行程.你有没有经历过大型企业级系统开发,成为鉴定技术人才的最佳方式,很多PHP程序员在此望洋兴叹. 如果你经历过大型企业级系统开发,那一定对大流量.高并发.大数据下开发有所接触.对于这些问题和挑战,要及时妥善解决,否则要么无法满足最终用户的需求,要么业务受损惨重.所以负责企业级系统开发和维护时,需要持续投入更多的时间.精力和创造力. 而这次课程,主要讲述企业级系统的开发,不仅包括网站系统的开发,还包括微服务.接口系统.定时任务系统的开发.

企业级开发的思考

以前自己一直认为企业级开发是神圣的,是不容质疑的.尽管有时候自己也认可"多大屁股穿多大裤衩"的道理,但是那种重量级的开发模式在自己心目中占据的位置一直是不容侵犯的.直到最近公司打算要做个东西的时候才发现企业级真的很重,重到90%以上的情况用不到. 之前考虑过EJB和Spring,自己一直认为只有EJB才是亲生的,至于Spring只不过算是一个长得很壮的野草而已.但是最近工作中遇到的问题改变了我以往的观点. 在一个纯EJB的系统中毋庸置疑得使用JPA来持久化,但是由于系统升级的需要我们不

分层开发——软件系统的分层开发

分层模式可以这样定义:将解决方案中功能不同的模块分到不同的项目中实现.每一层中的组件应保持内聚性,每一层都应与它下面的各层宝石耦合.分层模式是最常见的一种架构模式,甚至可以说分层模式是很多架构模式的基础. 数据访问层:这一层处于最底层,负责与数据库的交互,也称为:DAL(Data Access  Layer) 表示层:这一层直接和用户打交道,负责显示或者获取数据,也称为UI层(User Interface Layer)无论用控制台还是用windows窗体显示数据,都是表示层的一种应用. 表示层依