DDD是什么?怎么使用?

前言

随着业务的不断拓展,一个项目再也不是只需要运行一段时间就可以了,也不是一个很小的项目,随着业务的增长,最终开发的代码会变成一个很大的项目,此时如果不能做好很好的重构,会造成越来越难的拓展,最后导致无法拓展。所以DDD(Domain Driven Design,领域驱动设计)就是从领域业务这个方面对代码做重构与设计的方法论之一。

另外不可能将DDD用于任何一处代码,原因如下:

  1. 成本不允许,一般只有项目的核心领域才会考虑使用DDD重构,培养DDD团队会消耗比较长的时间,且整个时间成本是需要持续投入的。
  2. 因为DDD无法使用于任何一个环境,只使用DDD无法做到满足全部的业务场景,比如G端企业做数据化,很多时候是只需要从数仓查询数据;但是DDD只是一个业务思想,单纯的数据也无法做到成为业务领域
  3. DDD要求可以将业务分的很清晰,需要一个"聚合根"将一组业务模型组起来,这要求需要一组业务专家作为开发主力,这通常意味着需要将团队中比较聪明的几位来将项目解构成DDD的模型,很多时候这群人的工作重点不在这里。
  4. 就算使用DDD也不可能将其全部的教条应用在代码中,因为工作主要是为了盈利,如果使用DDD会帮助提升代码价值,全使用DDD会降低代码价值。在这种情况下,必然是只会使用一部分的DDD思想。

Model-Driven Design

好的模型可以反应真实的业务情况

  1. 好的模型需要统一的语言,在一个开发团队中,需要让每个开发者对同一个术语的概念是了解一致的,且需要业务专家将对应信息传达下去。

    如"数据资产",数据专家和一个应届生想到的肯定是不一样的。

  2. 模型类与其他非DDD层的POJO需要分离开来,尤其需要和数据库的POJO分离开来,DDD是软件设计思想,与数据库、技术组件、远程调用是完全不相关的。

  3. 除了核心组件外,其他组件,如MVC的DAO层,因为其确实是需要做到和固定数据库做好对接,所以面向结果编程是完全值得提倡的。

  4. DDD中一组很重要的思想是Entity和Value Object,Entity可以被认为是数据库中一张表的自增主键,具有连续性和唯一性,Value Object相当于是一个更关注其数据属性的一个组件,因此只能依附于一个Entity

  5. Entity和Value Object只是提供了一组事物信息,如广告转化率、广告使用地区等。但是另外还需要非"事物"的部分引入到模型中,如行为,如一组模型相关的业务,如广告投放业务中,如果需要对广告相关的信息做校验,其中就包括业务校验和技术校验,如果将这两个模块混淆了,则会导致业务层被"腐化",无法实现很好的解耦与以后的拓展,因此需要将业务操作和技术操作分离出来,我们可以将基于Entity和Value Object的操作称之为"Service"。

    模型中的Service有应用层面的Service、领域层面的Service(因为需要将真实业务层和技术实现层解耦,在Java的开发中可以使用依赖反转实现)、技术层的Service,应用层面的Service、领域层面的Service无法很好的区分,有时候可能不需要做区分,但是一旦涉及到业务领域核心,且不已不同应用场景为变更,则可能需要区分。

    以下有一个例子:

    在C端进行广告投放业务,会需要做到以下代码

    java 复制代码
    public class AdvertisementService {
    ​
        @Resource
        OnlineRetailersFeign onlineRetailersFeign;
    ​
        @Resource
        AdvertisementDAO advertisementDAO;
        
        @Resource
        AdvertisementDomainService advertisementDomainService;
    ​
        public Result<AdvertisementDTO> showAdvertisementInfo(AdvertisementRequestAO advertisementRequestAO) {
    ​
            String reginId = advertisementRequestAO.getReginId();
            //查看广告校验是否有效
            if (checkAdvertisementDisable(reginId)) {
                return new Result<AdvertisementDTO>();
            }
            //进行本业务相关操作
            /**
             * 1.查看投放地域、用户信息,查看用户所处环境(APP、Web等)
             * 2.从数据库中取出用户个人画像、当地广告服务商提供的服务
             * 3.通过算法取得合适的投放信息,并且按照需要从电商微服务等服务获取信息包装
             */
            advertisementDomainService.domainOperate();
            //最后进行写入数据库操作
            advertisementDAO.insert();
    ​
            //给其他微服务发送对应消息
            onlineRetailersFeign.notify();
            //最后返回信息
            return new Result<AdvertisementDTO>();
        }
    ​
        /**
         * 校验广告地址信息
         *
         * @param reginId
         * @return
         */
        private boolean checkAdvertisementDisable(String reginId) {
            return true;
        }
    ​
    }
    ​

    其中最重要的是advertisementDomainService.domainOperate(),这个可以认为是领域相关Service,不能算作是应用Service,应用Serivce可以是advertisementDomainService.domainOperate()中的实现,通过状态模式/策略模式,实现具体逻辑。因为取得服务可能因为地区、用户不同、具体的实现逻辑是不一样的,调用的组件是不一样的,所以细节上的实现需要应用层去协调和跟技术层Service实现,但是总的来说,投放一个广告就是需要这几步,因此这一组需要作为领域层的Service。

    Service是当需要Entity和Value Object做一组操作时候出现的,且Service最好是无状态的。

  6. 最后的Entity和Value Object应当以一组模块的形式出现。

业务域

  1. 设计好模型后就需要将模型组合成为领域,那么就需要一个model作为聚合根实现聚合。其中占主导作用的,和外部做主要交互的model作为聚合根,是这个领域存在的前提条件。
  2. 开发一个领域就是为了让隐性概念显性化,让隐形上下文显性化,配置多对象行为。
  3. 需要根据业务需要将领域划分为核心子域、支撑子域、通用子域。这些领域之间需要做到可以使用限界上下文、通用语言、上下文映射图做好划分。
  4. 限界上下文是当一个领域形成时候,需要将业务与其他业务进行物理隔离,只能通过几个固定方式进行交互,这个边界就是限界上下文

总结

  1. 只学习DDD并不能帮你更好的架构与设计,更好的方式应当是学习软件常见的架构设计模式、自己使用的编程语言的基本特性、然后再积极的使用
  2. (另外就是Eric Evans的软件驱动设计:软件核心复杂性应对之道不推荐看,因为翻译比较捉襟见肘,很多时候不知道在讲什么)
  3. DDD思想知易行难,期间需要花大量精力打通多个团队,是个人硬实力与软实力的体现,另外就是需要正确的构建出模型,需要可以满足实际的需要。实践DDD思想是一项风险收益都较高的事情。
相关推荐
Ellie陈1 小时前
Java已死,大模型才是未来?
java·开发语言·前端·后端·python
三日看尽长安花1 小时前
【Redis:原理、架构与应用】
数据库·redis·架构
wclass-zhengge2 小时前
SpringBoot篇(运维实用篇 - 临时属性)
运维·spring boot·后端
2401_857600952 小时前
商场应急管理:SpringBoot技术解决方案
java·spring boot·后端
半夏之沫3 小时前
✨最新金九银十✨大厂后端面经✨
java·后端·面试
小宇3 小时前
The valid characters are defined in RFC 7230 and RFC 3986
java·开发语言·后端·tomcat
Moment3 小时前
💯💯💯 历经四个月,我们开源了一个协同的在线代码编辑器,还支持执行 Node 项目哦!
前端·后端·github
景天科技苑4 小时前
【Golang】Go语言中如何进行包管理
开发语言·后端·golang·go mod·go语言包管理·go包管理·go sum
秦朝胖子得加钱4 小时前
Flask
后端·python·flask