本文转载自微信公众号“bugstack虫洞栈”,作者小傅。转载本文请联系bugstack公众号。1.前言领队:为什么要用DDD?我也苦思冥想,怎么跟领导说我们应该从MVC升级到DDD,因为DDD的代码结构更清晰,领域驱动比测试驱动开发更高级,研发兄弟更想用它了新车架等等。不过先不说被喷,不得不说自己设计过度折腾了,这是怎么回事?因为没说到重点,你的MVC升级为DDD;给业务带来了什么,提高了交付效率?是否降低了公司的研发成本?不仅没有,你还说前期需要更多的设计开发时间,用于后期的迭代维护。为什么?你是不是想带着这个Q送我走?我刚来,我们部门的KPI就挂在那里,头发都白了!不要乱来,请注意安全!那不做?哇,领导不换!但在你做之前,你必须想清楚,DDD不是SilverBullet。有激情固然好,但你也需要知道DDD的设计原则是什么,更适合什么场景,和MVC相比如何。云和泥有什么区别。2.开发成本使用DDD模型开发代码的成本是多少?是不是因为使用DDD的四层结构比MVC的三层结构更耗时?其实不是,因为四层结构相对于三层结构,反而更好的区分了代码的职责。熟悉了模块的功能职责后,开发就会更加顺利。那么DDD领域驱动设计开发的成本在哪里呢?这个成本在于,对于一??个复杂的系统,在开发初期没有足够的经验去拆分职责边界、划分功能区域、理清编排逻辑、拓展未知流程。在控制上,带来了风暴模型的设计成本。常用的MVC结构基本不存在这样的问题,因为在实际代码中,DAO、PO、VO等都是共享的。把产品的珠三角功能节点串联起来就行了,不用考虑太多的解耦和内聚。设计一个图案不行吗?就看你站在哪个维度去思考问题了。这里的设计模式是战术问题,DDD和MVC决定战略问题。有点像在说:“方向错了,努力白费了”。下面我们来看一下这个开发成本曲线:架构模式、开发成本曲线等。对比两种层级结构,使用DDD时,前期需要投入更多的时间和成本来设计领域建模,因此初始成本会更高。但随着业务迭代后逻辑的复杂度增加,采用DDD系统架构开发的代码稳定性会更好,这意味着DDD更易于扩展和维护。因此,框架结构的更换并不是最终增加开发成本的地方。如果你不做领域建模,不做更多的设计思考,那么即使是DDD的四层架构,也能让你写出MVC的效果。而那些有业务场景经验的架构师或者研发人员,已经明确了各个业务功能的职责边界,需要完成哪些核心领域服务才能实现一个系统需求。在这样的情况下,使用DDD不会带来太大的发展。成本,但更容易!这就是为什么需要领域专家,因为专家积累了大量的战略设计经验。另外,使用DDD领域驱动设计模型进行开发,除了解决需求的迭代成本,更多的时候是需要在公司战略调整后,系统的交接,人员的更换,人员的增加新加入的东西必须在原有的工程架构下不断迭代开发,否则推翻重做,更换的成本会更大。制定了与人员绑定、不易交接和维护的工程代码。3.架构对比在理解和掌握DDD领域驱动设计的路上,肯定会遇到两个抽象的钉子——“贫血模型”和“拥塞模型”:贫血模型:事务脚本模式,最早起源于EJB2,到春天就进入了“春”的盛世。拥塞模型:领域模型模型在2003年被提出,直到《实现领域驱动设计》的出现,才打开了DDD的大门。然而,直到微服务和低代码在中国兴起,DDD才开始流行起来。1、MVCMVC的层次结构将“状态”(数据、成员对象)和“行为”(逻辑、过程)分离为不同的对象。状态对象(VO->ValueObject)称为贫血模型,只有行为的对象是框架层中常见的Logic/Service/Manager层(对应EJB2中的StatelessSessionBean)。LayerService使用DAO和PO基础设施来封装业务逻辑开发方法。乍一看,好像是应用层在实现领域建模。“领域层”有丰富的对象链接,和真正的领域模型非常相似,但是当我们的代码逐渐实现业务功能逻辑时,会慢慢发现我们写了一堆get/set对象,并且它们被重复使用和交叉使用,不与任何领域聚合,即没有任何行为。只是一堆贫血模型对象。这种反模式设计其实是完全违背面向对象设计的。面向对象设计希望将行为和数据绑定在一起。相比之下,贫血模型更像是面向过程的设计。MVC层次结构下,所有行为都写入Service对象,最终得到一套事务处理脚本,完美规避了领域模型设计带来的好处(职责边界清晰,功能服务聚合,面向对象清晰).2、DDDDDD的层次结构也是面向对象编程的精髓:“对象有行为,有数据”,包括:领域层的对象、聚合对象、仓库和Service实现。DDD分层结构DDD的分层结构更注重Domain领域层的实现。薄应用层定义接口并整理接口,领域层做具体实现。所有的业务逻辑按照各自的职责边界被拆分成功能区域,每个功能区域都是拥塞模型结构的具体实现。那么这样的代码最终实现之后,无论是迭代、维护,还是人员更换,都可以根据领域设计文档找到对应的代码实现进行开发。4.设计原则首先,DDD的设计分为战略和战术;战略设计:从业务角度,建立业务领域模型,划分职责边界,建立通用语言边界上下文。顶层战略设计构建的领域模型结构是整个后期业务编排的重点。它决定了职能职责边界、聚合、对象等,也决定了后期服务策略的制定和交付质量。讲究谋略,才能施行好战术!战术设计:从技术角度出发,重点关注领域模型的技术实现,完成功能开发和交付。领域设计的重点包括:实体、聚合对象、值对象、领域服务、存储,还有一个很重要的设计模式。任何更复杂的领域模型实现都需要考虑使用设计模式,否则即使策略再好,战术也可以回到MVC。在实施DDD领域驱动设计的过程中,需要依靠领域驱动设计的设计思想,通过事件风暴建立领域模型,合理划分领域逻辑和物理边界,建立领域对象、服务矩阵和服务架构图,定义符合DDD的分层架构思想的代码结构模型,保证了业务模型和代码模型的一致性。通过以上设计思路、方法和流程,指导团队按照DDD设计思路完成微服务的设计和开发。拒绝小泥球,拒绝污染功能和服务,拒绝加功能和一个月调度,构建易满足互联网高速迭代的高可用应用服务,服务物化、组装、编排,提升人的效率和领域驱动设计,而不是数据驱动设计,或者界面驱动设计,需要清晰的功能分层,而不是一大筐DDD领域模型设计。边界内的上下文可以拆分为独立的微服务。但是我们不能只从业务的角度看问题,还要考虑非业务的技术因素,包括:高性能、安全性、团队、技术异构性等,这些非业务的技术因素也会决定具体的实现方式域模型。5、比如你说我MVC不好,你说我MVC模型贫血,PO类不断扩容,但是我用DDD都是理论。程序员更喜欢查看已经实现的代码。告诉我如何干燥。为什么实施起来这么难?因为从MVC到DDD的描述比较只是积累MVC失败的教训,而没有成功的DDD经验,所以很多时候,如果要实现DDD,需要前面的案例你除了理论支持。.1.项目架构所以为了让更多的码农看到一条走DDD的路子,特地抛出了一个DDD分布式抽奖系统,告诉大家如何使用DDD开发业务需求;DDD分布式彩票系统,工程分布式整体系统架构设计包括6个项目:彩票:分布式部署的彩票服务系统,提供彩票业务领域功能,分布式提供RPC服务。Lottery-API:网关API服务,提供;H5页面抽奖,公众号开发回复留言抽奖。Lottery-Front:C端用户系统,vueH5lucky-canvas大转盘抽奖界面,讲解vue项目创建、导入模块、开发接口、跨域访问及功能实现Lottery-ERP:B端操作系统,满足运营商对查询、配置、修改、审计等活动的需求。DB-Router:分库分表路由组件,基于HashMap核心设计原理开发一个组件,使用hash散列+扰动函数将数据散列到多个数据库表中,并验证使用。Lottery-Test:测试验证系统,用于测试验证RPC服务和系统函数调用的测试系统。2、流程拆解当我们拿到产品的RPD时,并不是直接开发,而是需要从流程中拆解一个面向对象的设计领域服务,例如;DDD分布式抽奖系统,流程拆解讲解功能流程,细化领域服务,一步一步教你如何将一个业务功能流程拆解成各个职责边界下的领域模块,通过对接开发好的服务提供整个服务链路在应用层串联领域服务。通过这样的设计和落地思路,以及按照面向对象的思想,使用设计模式设计面向过程的功能,使代码的每一步都变得清晰易懂,从而使实现的代码更易于维护和扩展。所以,你在这个过程中学到的不仅仅是代码开发,更多的实践思想和实践都体现在其中。也可以为你以后开发这样的项目或者面试过程中一些实际复杂的场景问题的设计思路打下良好的基础。
