在五彩石项目启动伊始,就决定采用领域驱动模型来设计业务框架,可是因为当时好多人对该模型的不熟悉,以及对一些设定的难以理解,致使第一版的代码仍是存在很多mvc的影子的。随着你们对该模型的逐渐了解,一致认为须要对业务代码作一些优化,因而组内在8月份启动了二次DDD改造的内部迭代,通过不断的灰度放量,近期已经全量放开了新版业务逻辑。数据库
关于对DDD的理解,每一个人均可以是不一样的,而且依据不一样的理解所写的业务框架也是不一样的,只要在必定的范围内可以逻辑自洽,那是没问题的。在启动DDD改造前,组内也作过一些分享,制定了一些规范,本文就是对组内这些规范的一个总结。编程
流量请求入口。
用户接口层负责向用户显示信息和解释用户指令。这里的用户多是:用户(H5/APP)、程序(API)、消息队列(MQ)、超时中心回调,自动化测试和批处理脚本等等。缓存
在最初的设计中,只有用户的调用是放在这一层的,其余调用是放在了application,这样致使了两个结果,分层不明确和入口分散。架构
因此本次将全部的流量入口所有放在了interfaces作收口。mvc
应用层链接用户接口层和领域服务层,它是很薄的一层,主要职能是协调领域层多个聚合完成服务的组合和编排。
应用服务层是很薄的一层,理论上不该该有业务规则或逻辑,主要面向用例和流程相关的操做。但应用层又位于领域层之上,由于领域层包含多个聚合,因此它能够协调多个聚合的服务和领域对象完成服务编排和组合,协做完成业务操做。app
应用层也是微服务之间交互的通道,它能够调用其它微服务的应用服务,完成微服务之间的服务组合和编排。框架
在设计和开发时,不要将本该放在领域层的业务逻辑放到应用层中实现。由于庞大的应用层会使领域模型失焦,时间一长你的微服务就会演化为传统的三层架构,业务逻辑会变得混乱。dom
举个精简的例子,假设出价分四步,
一、调用商品接口校验商品是否上架,
二、出价规则校验,
三、数据落地,
四、调用库存接口生成库存;微服务
那么应用层的主要功能就是编排这四步,不作业务处理。其中第1步和第4步放到基础层处理(基础层封装外部RPC),第2步在规则域执行,第3步在出价域执行。性能
在第一版的设计讨论中,有过一个定义是查询业务能够穿领域层,直达基础层,理由是纯查询的业务没有复杂的逻辑,仅仅是拿数据而已。但这也只是一个想法而已,通过实际的业务实践可知查询仍是有不少的业务逻辑组装,而基础层是不处理业务逻辑的,拿到数据后只能在应用层作封装,致使了应用层过于厚重。同时也考虑到一个合理的规范性,约定一样的流程之后,会更好的推动DDD。
领域服务层是由多个业务职责单一的聚合构成,实现核心的领域逻辑。
领域层的做用是实现领域核心业务逻辑,经过各类校验手段保证业务的正确性。领域层主要体现领域模型的业务能力,它用来表达业务概念、业务状态和业务规则。
领域层包含聚合根、实体、值对象、领域服务等领域模型中的领域对象。领域模型的业务逻辑主要是由实体和领域服务来实现的,其中实体会采用充血模型来实现全部与之相关的业务功能。
什么是充血模型与之对应的是贫血模型,咱们常用的MVC模型中,实体类只定义属性,并无定义实体行为。这种将数据与业务逻辑分离,实际上是违反了 OOP 的封装特性,其实是一种面向过程的编程风格。任意代码均可以修改实体的属性,那么实体的属性值就不受限制了。这实际上是自下而上的设计思想,是SQL 驱动(SQL-Driven)的开发模式。
而充血模型则是将该实体全部行为也进行了定义(好比save,modify,remove等操做)。任何想要修改实体属性的操做,必需要经过实体自己来实现。这是一种自上而下的设计思想,由具体的业务驱动开发,不须要关心底层的SQL实现。
实体和领域服务在实现业务逻辑上不是同级的,当领域中的某些功能,单一实体(或者值对象)不能实现时,领域服务就会出马,它能够组合聚合内的多个实体(或者值对象),实现复杂的业务逻辑。
聚合根是一种更大范围的封装,把一组在业务上不可分隔的实体和值对象聚合在一块儿,经过根实体的惟一标识对外提供能力。
实体是领域中须要惟一标识的领域概念。相同的两个实体,若是惟一标识不同, 那么即使实体的其余全部属性都同样,咱们也认为它们两个是不一样的实体,好比同一个用户对同一个sku同价格的两个库存实体,除了主键ID外,其他均相同,但这仍然是两个实体。
同时,不该该给实体定义太多的属性或行为,而应该寻找关联,将一些属性或行为转移到其余关联的实体或值对象上。 好比Inventory实体,会存储一些商品信息(sku、spu等),因为商品信息是一个完整的有业务含义的概念,因此,咱们能够定义一个Commodity对象,而后把Inventory实体中商品相关的信息转移到Commodity对象上。若是没有Commodity对象,而把这些商品信息直接放在Inventory对象上,而且若是对于一些其余的好比费用信息、仓库惟一码等信息也放到进去,会致使Inventory对象很混乱,结构不清晰,最终致使它难以维护和理解。
值对象就是上面所说的Commodity对象,并非每个值对象都必须有一个惟一标识,也就是说咱们不关心对象是哪一个,而只关心对象是什么。以Commodity对象为例,若是有两个Commodity的spuId是同样的,咱们就会认为这两个Commodity是同一个。也就是说只要spuId同样,咱们就认为是同一个商品。
基础设施层是数据封装层,在这里获取各种数据,好比数据库,缓存,外部领域,外部接口等。
基础层是贯穿除领域层外全部层的,比较常见的功能仍是提供数据库持久化和外部领域服务调用的。
基础层包含基础服务,它采用依赖倒置设计,封装基础资源服务,实现应用层、领域层与基础层的解耦,下降外部资源变化对应用的影响。
好比说,在传统架构设计中,因为上层应用对数据库的强耦合,不少的架构演进中最担心的可能就是换数据库了,由于一旦更换数据库,就可能须要重写大部分的代码,这对应用来讲是致命的。那采用依赖倒置的设计之后,应用层就能够经过解耦来保持独立的核心业务逻辑。当数据库变动时,咱们只须要更换数据库基础服务就能够了,这样就将资源变动对应用的影响降到了最低。
Domain 层再也不直接依赖 Infrastructure 层,而是引入了一个适配器模式(Port/Adapter),使用DIP(Dependency Inversion Principle,依赖倒置)反转了 Domain 层和 Infrastructure 层的依赖关系,其关系如上图所示Domain 层以接口的方式开放端口,让Infrastructure层去实现,这样设计的有点是 Domain 层的演变和进化彻底是独立的,向上不受 Application 层影响,向下不受 Infrastructure 层影响。
举个例子,领域层是经过仓储接口(repository)获取基础资源的数据对象,仓储接口会调用仓储实现,具体的基础资源的数据处理过程是在仓储实现中完成的。这样作的好处是,避免将仓储实现的代码混入上层业务逻辑中。若是之后替换数据库,因为作了基础资源的个性的代码隔离,因此实现了应用逻辑与基础资源的解耦。在更换数据库时只须要更换仓储相关的代码就能够了,应用的逻辑不会受太大的影响。
分层是为了各层独立演进的,上层使用下层定义的服务,而下层对上层一无所知,另外每一层对上层隐藏细节实现,依赖契约交互,独立层在技术方案调整时只要遵照契约则能够作到上层无感知迁移,这样也方便各层的维护和标准化工做。DDD 有两种架构,严格分层架构和松散分层架构。优化后的 DDD 分层架构模型就属于严格分层架构,任何层只能对位于其直接下方的层产生依赖。而传统的 DDD 分层架构则属于松散分层架构,它容许某层与其任意下方的层发生依赖,建议使用严格分层架构。
interfaces 层: request、response
application 层:DTO(data transfer object)
domain 层:entity、VO(value object)
infrastructure 层:PO(persist object)
首先用户接口层经过 request/response 对象来进行跨进程间的交互数据;应用服务层使用(DTO)来进行数据交互;在领域内部,咱们经过领域对象(entity/VO)做为领域内部的数据和行为载体;在基础设施层,咱们使用持久化对象(PO)进行数据库资源的交互。
也被称适配层或者转换层
在一个上下文中,有时须要对外部上下文进行访问, 一般会引入防腐层的概念来对外部上下文的访问进行一次转义。
有如下几种状况会考虑引入防腐层:
领域事件是领域模型中很是重要的一环,领域事件将会致使进一步的业务操做,有助于实现业务的解耦,并完成业务闭环。
举例来讲,领域事件是业务流程的一个中间步骤,好比出价领域出价成功后将通知库存域添加库存动做;也多是批处理过程发生的事件,好比求购域批处理程序扫描求购业务表判断是否要的群体触发基础服务域的push服务告知求购用户最新的求购进展。
领域事件能够切断领域模型之间的强依赖关系,事件发布完成后,发布方没必要关心后续订阅方事件处理是否成功,这样能够实现领域模型的解耦,维护领域模型的独立性和数据的一致性。经过领域事件+补偿机制来达到最终一致性,提升系统的稳定性和性能;
在一致性要求不高时,能够经过领域事件订阅器直接向消息队列发送事件。
对一致性要求高时,须要先将事件存储,而后经过后台线程加载并分发到消息队列。
以上就是出价组在二次DDD改造中的一些总结,下面以一个例子作结尾吧。
应用服务层主要是作流程编排等轻量逻辑,领域服务层完成领域内实际逻辑并持久化数据。
文|CJ BOYSCJ 是出价的拼音首字母缩写,因为组内都是Boy,因而团队起名CJ BOYS。关注得物技术,携手走向技术的云端