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思想是一项风险收益都较高的事情。
相关推荐
C澒几秒前
多场景多角色前端架构方案:基于页面协议化与模块标准化的通用能力沉淀
前端·架构·系统架构·前端框架
代码游侠6 分钟前
复习——Linux设备驱动开发笔记
linux·arm开发·驱动开发·笔记·嵌入式硬件·架构
Victor3569 分钟前
MongoDB(2)MongoDB与传统关系型数据库的主要区别是什么?
后端
JaguarJack9 分钟前
PHP 应用遭遇 DDoS 攻击时会发生什么 从入门到进阶的防护指南
后端·php·服务端
BingoGo10 分钟前
PHP 应用遭遇 DDoS 攻击时会发生什么 从入门到进阶的防护指南
后端
Victor35611 分钟前
MongoDB(3)什么是文档(Document)?
后端
牛奔2 小时前
Go 如何避免频繁抢占?
开发语言·后端·golang
想用offer打牌7 小时前
MCP (Model Context Protocol) 技术理解 - 第二篇
后端·aigc·mcp
KYGALYX8 小时前
服务异步通信
开发语言·后端·微服务·ruby
掘了9 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结