一、软件中的架构分层
在我们日常所开发的应用中,一般的流程是用户界面到服务,服务再到数据库。这里可能会有个问题,就是业务逻辑可能会分散在用户界面和数据库的逻辑里,不太存在高内聚和低耦合。当然,对于不太重要又着急的项目,这确实是比较简单的做法。
不过,要注意的是,如果把与领域相关的代码分散在大量其他代码中,那么查看和分析领域代码就会变得异常困难。对用户界面的修改实际上可能会改变业务逻辑,而要想调整业务规则也很可能需要对用户界面代码、数据库操作代码等仔细摸查,稍不留神就会掉入陷进。如此一来,不要说实现一致的模型了,这样的实现大多数人可能都会“敬”而远之。
所以,对于具有复杂业务逻辑的应用程序,尽量不要采用DIRTY AND QUICK的做法。
那么,如果想要创建应对复杂的业务逻辑,需要怎么做?答案是分离关注点。在分离的同时,也要维持系统内部复杂的交互关系。于是,就诞生了分层架构(Layered Architecture)。
所以,你看,分层架构并非DDD首创,在DDD之前,分层架构就已经广泛存在,并且种类繁多。不过,大多数成功的架构使用的都是下面这4个概念层的某种变体:
| 分层 | 职责 |
|---|---|
| 用户界面层 | 负责向用户显示信息和解释用户指令,这里指的用户可以是另一个计算机系统,不一定是使用用户界面的人。 |
| 应用层 | 定义软件要完成的任务,并且只会表达领域概念的对象来解决问题,这一层所负责的工作对业务来说意义重大,也是与其他系统应用层进行交互的必要渠道。应用层要尽量简单不含业务规则或者知识,而只为下一层的领域对象中协调任务分配工作,使他们相互协作,它没有反映业务情况的状态,但是却可以具有另外一种状态,为用户或程序显示某个任务的进度。 |
| 领域层(或模型层) | 负责表达业务概念,业务状态信息以及业务规则,尽管保存业务状态的技术细节是由基础设施层来实现的,但是反映业务情况的状态是由本层控制并且使用的。领域层是业务软件的核心。 |
| 基础设施层 | 为上面各层提供通用的技术能力,为应用层传递消息,为领域层提供持久化机制,为用户层提供绘制屏幕组件等等,基础设施层还可以通过软件架构来支持4个层次间的交互模式。 |
在日常的一些项目中,有些项目没有明显划分出用户界面层和应用层,而有些项目则可能拥有多个基础设施层。但是,将领域层分离处理出来才是MODEL-DRIVEN DESIGN的关键。
对复杂软件进行架构分层的重要性,Eric给了下面这段描述:
给复杂的应用程序划分层次。在每一层内分别进行设计,使其具有内聚性,并且只依赖于它的下层。采用标准的架构模式,只与上层进行松散的耦合,将所有与领域模型相关的代码放在一个层中,并把它与用户界面层应用层以及基础设施层的代码分开,领域对象应该将重点放在如何表达领域模型上,而不需要考虑自己的显示和存储问题,也无需管理应用任务等内容。这使得模型的含义足够丰富,结构足够清晰,可以捕捉到基本的业务知识,并且有效的使用这些知识。
分层架构是DDD重要的一部分,现在很多人在提到DDD时,可能首先会想到的就是它的分层架构,这与技术人员的思维有一定关系。不过,虽然分层架构并不是DDD的全部,但你仍然有必要了解它。
上面的描述多少会有些抽象,下面对各层再做一些简单地分析。
二、用户界面层(PRESENTATION)
用户界面层是应用程序的最上层,负责向用户显示信息和解释用户指令。不过,Eric在提出DDD时的情形与现在的软件开发相比,已经不可同日而语。那会,还没有前后端分离,用户界面层和其他层的代码在一个工程里,现在前端界面代码已经被分离出去。
那么,既然前端代码被分离了出去,那服务端是不是就不用管这一层了呢?并不是,如果那样理解就太过狭隘了。
对于用户界面层,要注意下面几点:
- 用户界面的任务驱动:虽然界面被隔离出去独立了,但是逻辑依然存在,这一层可以用于响应前端的各种请求;
- 设备友好:对于Web、移动端等各种设备要友好;
- 用户友好:这一层本质上也是设备友好,针对用户使用的设备提供不同的响应和处理逻辑,以提高用户体验;
- 不涉及业务逻辑处理;
如果这么看用户界面层,你会发现,它所承担的其实是类似于BFF的职责。在我们现有的一般性代码结构里,它是API的最外层。
三、应用层
应用层是分层架构重要但又似乎不太好理解的一层。我们再回顾下前面对于应用层的描述:
定义软件要完成的任务,并且只会表达领域概念的对象来解决问题,这一层所负责的工作对业务来说意义重大,也是与其他系统应用层进行交互的必要渠道。应用层要尽量简单不含业务规则或者知识,而只为下一层的领域对象中协调任务分配工作,使他们相互协作,它没有反映业务情况的状态,但是却可以具有另外一种状态,为用户或程序显示某个任务的进度。
理解应用层的重要是:
- 它所做的一切都是为了用户(不要狭义地理解成UI,还可能是二方调用);
- 应用层体现的是用户故事,用户需要什么,它就需要准备什么;
- 应用层可以组织并协调不同的领域层来实现用户目的;
- 应用层也是领域层的保护层,不要直接对外暴露领域层。
四、业务逻辑层
业务逻辑层表示的是应用层+领域层,这种表示在一般的DDD分层架构图上不多见,但它也只不过没有被显示地展示出来(本文上图有展示),实际是存在的。
这是因为,在软件系统的设计中,抽象地说,软件系统的业务逻辑有两个主要部分构成:应用程序逻辑和领域逻辑。应用程序逻辑是代码的重要组成部分,严格取决于用户故事(用例)。但是领域逻辑就不同了,它是不变的,不会随着用例的变化而变化。用例可以张口就来,但是领域逻辑必须稳如泰山。举个例子,试驾中的预约可以有多种预约方式和途径,但是预约的内在领域逻辑则必须一致且稳定。
所以,我们不能撇开应用层只谈领域层,那样的话,你会发现很多业务规则和逻辑无法安放,压根不知道代码往哪里写,其根本原因是没有搞清楚应用程序逻辑领域的存在及区别。
五、领域层
领域层是DDD分层架构中的精髓,它是业务系统中不变的部分,是领域模型以及所有与其直接相关的设计元素的表现,由业务逻辑的设计和实现组成。在MODEL-DRIVEN DESIGN中,领域层的软件构造反映了模型概念。
如果领域逻辑与程序中的其他关注点混在一起,就不可能实现这种一致性。所以,将领域实现独立出来是领域驱动设计的前提。
关于领域层的细节,这里暂不做赘述,后面会有独立文章解析,目前理解它的定位和重要性即可。
六、基础设施层
如上文所述,基础设施层为上面各层提供通用的技术能力,为应用层传递消息,为领域层提供持久化机制等等,基础设施层还可以通过软件架构来支持各层次间的交互模式。
基础设施层中需要注意的有两点:
- 代码中非领域逻辑和应用程序逻辑的支撑性、工具性代码应当分离到基础设施层;
- 同一个工程中,不要有多个基础设施层。同一个组织中,尽量考虑基础设施层可以跨工程复用。
小结
本文主要讲述的是DDD中的分层架构的由来和它的重要性。在实践过程中,具体的框架并不是实现分层架构的必需品,只能说框架应用得当,可以降低分层架构的复杂度,让其更易用落地,不必拘泥于外界的框架。要记住,如果一个架构能够把那些与领域相关的代码隔离出来,得到一个内聚的领域设计,同时又使领域与系统其它部分保持松散耦合,那么这种架构也许就可以支持领域驱动设计。
如果非要使用框架的话,请务必考虑到框架对复杂度、灵活性的支持和限制,更要考虑到组织接受的能力和意愿。
关注公众号【MetaThoughts】,及时获取专栏文章更新通知。
如果本文对你有帮助,欢迎点赞、关注。