如何正确理解并科学实践DDD

这篇具有很好参考价值的文章主要介绍了如何正确理解并科学实践DDD。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

如何正确理解并科学实践DDD

客观的理解DDD

DDD,即领域驱动设计,不仅带给我们一套新的概念,还提供了一套全新的设计思路,应用在构建大型复杂软件系统之上。

 文章来源地址https://www.toymoban.com/news/detail-482320.html

相对于DDD,我们使用的传统的设计思路,常被称为数据驱动设计,常被应用于中小型的项目。互联网的项目,往往是快速迭代,起初一个小项目,慢慢会演化为一个中大型的项目,在演化过程中,很容易出现架构腐化,内部各模块的边界不清晰,耦合严重,所谓牵一发而动全身,而此时,往往会重构的方法来解决。然而重构毕竟是个耗时费力,对业务而言收益不直观的事情,所以人们常常想,在长期的迭代中,如果能有一些方式能够让系统一直保持稳定的架构,清晰的逻辑,那么就能够节省很多成本,甚至可以节省撰写文档的成本(代码即文档)。

 

对于问题的解决方案往往很多,Eric Evans为我们总结了一套DDD理论。其实解决问题的思路,不仅限于DDD,或者说,我们所理解的DDD,可以不同于Eric Evans所总结的那样,只要是为解决问题行之有效的方式,都是值得推崇的。

 

DDD与传统的设计思路,二者其实没必要把各个点拿出来对比,其各有各的优势和劣势,一概的追捧和否定某一个,都是不客观的。我们解决不同类型的问题,会用不同的手段。在解决一个问题时,尽可能用最简单的思路。对于那种不会进行过多迭代的小型系统而言,没必要使用DDD(或者DDD全套),它反而会给你带来更多的问题,保持它的精简是很有必要的。而大型的系统,或持续朝着大型系统方向迭代的系统,一些在小型系统中不容易凸显的问题,就会慢慢被放大,凸显(比如逻辑臃肿,模块边界不清晰)。使用简单的设计思路,往往无法约束这些问题的扩大。这个时候,就需要更多的细节规范来抑制问题产生,发展。因此也可能会产生更多的概念,这也是DDD概念很多的原因。

 

对于DDD的众多概念,学习成本会变高,更是为落地增加了很多困难。一个项目下来,也许会伴随着一个担忧,那就是“一不小心就回到了传统方式上”,最后觉得自己做了个“四不像”。其实我们要做的DDD,并不是说我们要完全按照Eric Evans所总结的那样把所有内容都按照理论概念来实践,它只能起到指导作用,具体的情况,要结合自身公司,项目组成员,业务情况等因素来决定。这就好比是,马克思主义理论,在中国的实践,要结合中国的具体国情才可以。为了DDD而DDD,是没有意义的。始终关注我们的目的,是个十分重要的原则,目的也决定了我们遇到一些细节技术的抉择时如何做出取舍。

 

DDD在转转价格系统的实践过程

 

1、业务理解

 

转转价格系统(估价器),是个十分复杂的系统,它承载着转转回收以及众多卖场的价格计算和等级计算能力,同时提供价格实验能力。由于系统的复杂性高,以下介绍的内容,是系统的一个简版。

 

价格系统估价的大致流程是,估价器拿到验机报告后,首先进行验机报告的解析,然后将验机报告转换为估价项。然后根据请求的参数,找到合适的报价流程,在报价流程中执行其所配置的报价方式进行价格计算。

 

如何正确理解并科学实践DDD

 

因为计算价格是区分多种不同的场景的,比如如转转C2B线上回收,转转门店回收,转转B2C卖场,转转门店零售卖场等。不同的场景需要关联的参数配置和报价方式都有所不同,所以我们这里抽象出一个概念“场景”,用来关联这些参数配置和报价方式。

 

如何正确理解并科学实践DDD

 

对价格的计算,一定是建立在客观的商品各项情况,成色等基础上的。转转作为专业的二手交易平台,是能够产出专业的验机报告的。那么对价格的计算,就依赖验机报告给出的数据。

 

转转的验机报告中的数据,都是验机工程师填写的比较专业的,详细的,丰富的验机项,如果直接拿给运营人员对其进行价格的维护,会有较大的维护成本。所以,需要将验机报告的项,通过一种关系,转换为人工易维护的估价项,后续运营人员对价格进行维护时,就比较方便高效。这一步就是估价项转换。

 

估价项转换好后,就要执行估价流程了。估价流程封装了某一个或某几个估价的方式或估价的算法,我们暂且叫它估价方式,如人工价格表,等级价格,算法模型等。除此之外,估价流程还封装了不同估价方式的执行过程,如B2C零售卖场优先使用算法模型,如果无法给出价格,则使用人工价格表。最后根据这些逻辑,输出一个价格。

 

在开始实践之前,对于业务的理解十分重要,对于各个概念要做到统一语言,也就是消除团队成员之间的理解的偏差。我们的目标,就是构建一个架构良好,可测试性强,学习成本低,易于扩展和维护的系统。

 

2、战略设计

 

如何正确理解并科学实践DDD

 

通过对业务逻辑的理解,我们可以得到以下的子域划分:

 

  • 场景子域,通用域,为其他域提供配置参数。

     

  • 验机报告解析子域,支撑域,为估价提供前置的数据支撑。

     

  • 估价项转换子域,支撑域,也是为估价提供前置的数据支撑。

     

  • 报价流程子域,支撑域,为报价提供流程的封装。

     

  • 报价方式子域,核心域,提供报价的计算方式,这是业务的核心,需要花费主要的精力。

 

3、战术设计

 

这一步我们对限界上下文做设计。这里每一个限界上下文对应一个子域,得到的领域模型详细设计。例如下图为验机报告解析上下文,绿色代表实体,黄色代表值对象。此上下文依赖外部的验机报告服务,使用防腐层来做适配。该上下文输出解析后的验机报告。对于验机报告,每一个商品有唯一一份,存在唯一标识,所以属于一个实体。验机报告中,应该包含商品的品类,品牌,型号,以及它的验机项,这三者都属于值对象,被聚合为验机报告实体。

 

 

4、上下文集成

 

上下文集成可以简单理解为,每一个上下文都是什么样的关系。从概念上讲,上下文集成关系有很多种:

 

  • 分离方式 separate way

  • 客户-供应 customer/supplier

  • 发布-订阅 publisher/subscriber

  • 开放主机服务和发布语言 open host service, publicshed language

  • 防腐层 anti corruption layer

  • 尊奉者 conformist

  • 共享内核 shared kernel

  • 合作者 partnership

 

这其中很多概念应用较少,引入过多的概念对于我们解决问题可能没有太大意义,这里只采用“合作者”,“开放主机服务和发布语言”和“防腐层”。“合作者”能够表示出本系统中两个限界上线文的依赖关系,后两者能够表示出,与外部系统的限界上线文的依赖关系。其中“PS”代表合作关系,“U”代表上游,“D”代表下游,这里的上下游和依赖方向正好相反。“ACL”代表防腐层,与“OHS/PL”开发主机服务和发布语言搭配使用。

 

如何正确理解并科学实践DDD

 

5、架构设计

 

架构理论发展至今,各种新型的架构不断出现。除了我们常用的分层架构外,还有整洁架构,六边形架构,洋葱架构,CQRS架构等。各有特色,各有利弊。出于学习成本,团队成员经验的角度考虑,这里采用松散型(可跨层调用)的分层架构。

 

api层作接口定义层,被其他服务所依赖。application层作应用服务层,实现api层的接口。domain作领域层,实现核心的业务逻辑。infrastructure作基础数据层,为上层提供数据接口和外部调用的防腐。

 

如何正确理解并科学实践DDD

 

除了核心的估价业务逻辑外,系统还包含后台维护的功能,这一部分多为数据的增删查改操作,逻辑简单,可以不进入domain层,由application层直接从infrastructure获取。

 

工程结构和架构一致,在此基础上,每一层可能都会依赖相同的一些常量,工具,和基本算法,这些内容可以单独封装为一个common的包。于是得到如下工程结构:

evaluation_sys
 - api
 - application
 - domain
 - infrastructure
 - common

 

6、业务逻辑实现

 

在使用传统的mvc模式下,我们往往使用三层架构,即controller,service,dao或者其类似的方式。这种架构会把所有的业务逻辑堆积在service之下,领域实体只做数据传输,没有行为。随着项目的迭代,可能出现service臃肿的情况,大量业务逻辑,把service搞成一个胖子,业务逻辑就会变得混乱不堪,理解和维护成本极大。

 

如何正确理解并科学实践DDD

 

然而我们希望代码不仅仅是用来执行的,更是用来阅读的,表达的业务逻辑给人一目了然,一看就懂,是我们追求的。好的代码结构,就是要把各个业务逻辑按一定原则拆分开,再用一种机制将它们很好的组织在一起。按照DDD的思想,应用服务编排领域服务,用以描述业务主干逻辑,每个领域的细节逻辑由领域服务封装实现,这就把逻辑做了鲜明的分离。

 

如何正确理解并科学实践DDD

 

如价格系统中,估价的应用服务中是这样实现的:


public EvaluateResult eval(Scenario scenario, EvaluateContext context) {
    // 获得验机报告
    QcReport report = qcReportService.parseReport(context.getQcCode());
    // 估价项转换
    EvaluateItems evaluateItems = evaluateItemsService.transfer(report, scenario);
    // 执行估价流程
    EvaluateResult result = evaluateProcessService.evaluate(scenario, context, evaluateItems);
    // 返回结果
    return presult;
}

 

其次DDD提倡领域对象拥有行为,这不仅仅是更加符合面向对象所讲的,让对象贴近客观世界,而且又一次的划分了逻辑,让领域服务中的主干逻辑和细节的逻辑实现做了鲜明的分离。如估价流程的领域服务是这样实现的:


public class EvaluateProcessService {
    public EvaluateResult evaluate(Scenario scenario, EvaluateContext context, EvaluateItems evaluateItems) {
        // 获取估价方式(或估价算法)
        List<EvaluateAlgorithm> algorithms = EvaluateAlgorithmFactory.create(scenario);
        // 获得估价流程
        EvaluateProcess process = EvaluateProcessFactory.create(scenario, context, algorithms, evaluateItems);
        // 执行估价流程
        reutrn process.evaluate();
    }
    // ...
}

 

其中一种估价流程的实现是这样的:


/**
 * 取最高价的估价流程实现
 */
public class MaxPriceEvaluateProcess implements EvaluateProcess {
    // 对象属性
    private Scenario scenario;
    private EvaluateProcess context;
    private List<EvaluateAlgorithm> algorithms;
    private EvaluateItems evaluateItems;
    
    
    /**
     * 对象行为,计算价格
     */
    public EvaluateResult evaluate() {
        long maxPrice = 0;
        // 遍历算法,分别计算价格
        for (EvaluateAlgorithm algorithm : algorithms) {
            long price = algorithm.calculate(context, evaluateItems);
            if (maxPrice < price) {
                maxPrice = price;
            }
        }
        return new EvaluateResult(maxPrice);
    }
    // ...
}

 

经过一级一级的逻辑拆分和组织,最终让代码有极强的可读性,更加符合人的思考问题的方式,让维护,学习更加容易。

 

写在最后

 

DDD实践,需要花费大量的精力去学习理论,概念和前人实践的案例,过程中还会出现很多的问题,很多的抉择,能够得到一个满意的结果,绝不是一件轻松的事情。所以,再次强调,一定要明确自己的目的,我们不应该怀着赶时髦的心态去实践它,应理性的思考是否真正的需要它。当然对于DDD的实践,书中所讲述的思想,案例,往往不是全部适用于你的项目,哪些适合自己,哪些可以解决自己的问题,才是我们应该思考的。

 

作者丨高宏杰

到了这里,关于如何正确理解并科学实践DDD的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 关于聚合根,领域事件的那点事---深入浅出理解DDD

    作者:京东物流 赵勇萍 最近有空会跟同事讨论DDD架构的实践落地的情况,但真实情况是,实际中对于领域驱动设计中的实体,值对象,聚合根,领域事件这些战术类的实践落地,每个人理解依然因人而异,大概率是因为这些概念还是有一些抽象,同时有有别于传统的MVC架构

    2023年04月27日
    浏览(49)
  • 快速理解DDD领域驱动设计架构思想-基础篇 | 京东物流技术团队

    本文与大家一起学习并介绍领域驱动设计(Domain Drive Design) 简称DDD,以及为什么我们需要领域驱动设计,它有哪些优缺点,尽量用一些通俗易懂文字来描述讲解领域驱动设计,本篇并不会从深层大论述讲解落地实现,这些大家可以在了解入门后再去深层次学习探讨或在后续进阶

    2024年02月09日
    浏览(42)
  • 【实践篇】最全的【DDD领域建模】小白学习手册(文末附资料)

    DDD领域建模被各个大小厂商提起并应用,而每个人都有自己的理解,本文就是针对小白,系统地讲解DDD到底是什么,解决了什么问题,及一些建议和实践。本文主要是思想的一种碰撞和分享,希望能对朋友们有所启发或帮助。 在当时的环境下,单体应用仍然是市场的主体,但

    2024年02月15日
    浏览(47)
  • DDD进阶_领域事件是什么?如何开展领域事件驱动开发工作?

    DDD从入门到精通,系列文章传送地址,请点击本链接。   目录 一、什么是领域事件 二、如何识别领域事件 三、领域事件的数据一致性 四、领域事件分类 1、微服务内的领域事件 2、微服务之间的领域事件 五、领域事件案例 六、领域事件总体架构图 1. 事件构建和发布 2、事

    2024年02月15日
    浏览(39)
  • Python中如何正确地使用科学计数法显示数字?

    Python中如何正确地使用科学计数法显示数字? 在数据分析和科学计算时,我们经常会遇到非常大或非常小的数字。默认情况下,Python会使用科学计数法来显示这些数字,例如1e+08和1e-06。虽然这种表示方法是精确的,但有时候在阅读和理解数据时可能不太直观。那么如何在P

    2024年02月14日
    浏览(81)
  • 领域驱动设计——DDD领域驱动设计进阶

    进阶篇主要讲解领域事件、DDD 分层架构、几种常见的微服务架构模型以及中台设计思想等内容。如何通过领域事件实现微服务解耦?、怎样进行微服务分层设计?、如何实现层与层之间的服务协作?、通过几种微服务架构模型的对比分析,让你了解领域模型和微服务分层的作

    2024年01月15日
    浏览(49)
  • 【深入理解SSD 实践】对NVMe SSD热插拔时,正确做法是怎样的?

    声明 主页 :元存储的博客_CSDN博客 依公开知识及经验整理,如有误请留言。 个人辛苦整理,付费内容,禁止转载。 内容摘要 前言 概念 SAS/SATA 和NVMe 区别 热插拔分类 热插拔基本原理

    2024年02月06日
    浏览(113)
  • DDD领域驱动设计(六)

    领域对象需要资源存储。存储手段多样化,常见就是数据库,分布式缓存,localCache.资源库的作用,就是对领域的存储和访问进行统一管理对象。在抽奖平台中。通过下面这种方式组织资源库。

    2024年01月24日
    浏览(69)
  • DDD[领域驱动模型]

    这是一种思想,不是一个工具。更多内容前往 IT-BLOG Eric Evans 于 2004 年提出的一种软件设计方法和理论。在应用架构的设计中, 领域驱动设计 DDD 占据着非常重要的位置,可以说 DDD 是应用架构设计的核心。 DDD 是一套综合软件系统分析和设计的面向对象建模方法。 过去 系统

    2024年02月04日
    浏览(39)
  • DDD领域驱动

    我们经常讲技术为业务服务,架构设计需要对业务充分理解,在面向复杂的业务场景时,会面临诸多问题: 复杂系统设计 :业务系统多、业务类型多、业务相互耦合,有没有合适的方法来指导模块的边界开发? 多团队协同 :业务系统边界划分不清,系统间依赖复杂,往往一

    2024年02月09日
    浏览(35)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包