首页 > 其他分享 >DDD领域驱动设计

DDD领域驱动设计

时间:2023-05-22 16:11:53浏览次数:32  
标签:模型 业务 领域 事件 设计 驱动 代码 DDD

本文源于最近学习实践DDD相关知识的自我总结。相关内容源于网络

本文部分引用

  1、钟敬老师极客时间的DDD课程——手把手教你落地 DDD

  2、欧创新老师极客时间的DDD课程——DDD 实战课

一、DDD基本开发过程

  1、捕获行为需求

    识别需求流程、功能、参与者、功能结果

    (1)常用手段:用例建模

    (2)常用方法:事件风暴

  2、领域建模

  3、架构设计

    进程间架构:例如微服务设计、中台设计

    进程内设计:DDD分层架构

  4、数据库设计

  5、代码实现

 

二、事件风暴

  1、参与者:  

      业务人员:领域专家、一般由业务部门的专家、产品经理、PO(Product Owner)、BA(Business Analyst)等角色来担任

      技术人员:架构师、技术经理、开发人员、测试人员

  2、准备:

    会议室、一面比较长的墙/白板、彩色便利贴

  3、事件风暴的过程

    (1)识别领域事件

     a) 领域事件:业务流程中每个步骤引发的结果,事件风暴的作者认为,从结果入手来梳理需求,比从操作入手,更容易把业务想清楚。

       b) 领域事件的命名,如果套用英语的语法来说,一般是完成时 + 被动语态。比如说,订单已提交。在 DDD 中的各种命名,一般都优先使用约定俗成的业务术语。这样的目的是统一业务语言,基于统一的业务语言来沟通可以为团队节省沟通交流的成本。方便业务交流理解。这里的统一业务语言是指在一个项目或者一个模块内是统一的,业务名词在该范围内是唯一的含义,如果是跨模块或项目,那么就不存在统一的业务语言,业务上下文之间的相同业务名词的含义会有改变。

     c) 领域事件的识别

      可以在墙面/白板上使用橙色(或其他颜色)的便利贴来书写和粘贴,每个参与者按照自己的理解书写自己识别到的领域事件,然后统一粘贴到墙/白板上,由所有参与者一同梳理出来重复的,缺失的,理解不一致的,最后梳理出一套全体参与者认同的领域事件。

      ps:

      1. 粘贴领域事件的便利贴时,可以按照大致流程顺序来粘贴,但不必强求顺序准确完美,大致的顺序只是为了方便参与者查看。

      2.不要把技术事件当成领域事件,领域事件一定要是领域专家关注的,是业务描述

      3.查询功能不算领域事件

     d) 业务规则

      某个领域事件存在相关的限制,这种可以称之为业务规则,可以用灰色便利贴标识于相应的领域事件的橙色便利贴下方

    

    (2)识别命令

     命令(command),就是引发领域事件的操作,我们可以通过分析领域事件得到。除了识别出命令本身以外,我们通常还要识别出谁执行的命令,以及为了执行命令我们要查询出什么数据。

                        事件风暴示例图:来源自钟敬老师极客时间课程

    (3)识别领域名词

      领域名词,是从命令、领域事件、执行者、查询数据里找到的名词性概念。例如,对于签订合同这个命令而言,受到影响的名词性概念是“合同”;类似地,对于合同已签订这个领域事件,是由于“合同”这个名词性概念的状态变化所导致的。

   4、关于事件风暴部分的收获

    (1)事件风暴过程中不必强求分析出所有的事件和命令,这是不现实的,也比较浪费时间。我们只需要列出改业务领域主要的,能完整表达和交流领域知识的时间和命令即可,同时粒度不要过细,因为领域建模本身就不是一个力度很细的模型,事件风暴更是如此,领域模型都还要在事件风暴的基础上不断完善而不是以事件风暴分析的信息就此停止。

    (2)之前看到的有些网络文章说事件风暴需要有领域专家的参与,就误以为真正的实践必须要有十分精通业务专家。后来在实战的过程中发现即使团队内部对业务没有那么精通(知晓了解业务基本情况)的情况下,事件风暴的开展也取得了不错的结果,在这个过程中解决了业务需求不清晰,理解不统一的问题,统一的业务语言和领域模型对新项目的开展效果很好。老项目如果系统知识团队内缺失的比较严重,也可以开展事件风暴。

    (3)其实在实践过程中由于没有足够宽广的墙面和颜色合适的便利贴,我在开展完领域事件之后就把统一后的领域事件搬到了绘图软件上开始后续的分析,对于小团队我自身感觉这样更方便,同时兼顾了保存和后期维护事件风暴结果。

    (4)建立领域规则表,作为领域知识的重要组成部分。

 

三、领域建模

  1、模型的表达

    使用UML来画,受限识别实体之间的关系,包含一对一,多对多,多对一,所有的多对多都可以拆成两个多对一。此外在绘制过程中要合理的使用抽象,识别实体的自关联,增加关系约束,所有的约束必须在程序中得到实现。

    领域模型可以分为宏观层次(包图,模块)、微观层次(模块内部的实体),这样方便理解领域模型,可以在一定程度上减少复杂性。

  2、DDD 领域模型与传统方法的不同之处

  DDD 强调领域模型要兼顾业务和技术两个视角。围绕领域模型进行开发的方法,在 DDD 中称为模型驱动设计(Model-Driven Design),是 DDD 的核心模式之一。这个模式可以概括为两点:领域模型要和业务需求一致;系统实现要和领域模型一致。

  领域模型不仅要对业务进行直观模拟,更要经过提炼,形成浓缩的知识。第一点,是通过抽象思维得到更“深刻”的模型。第二点,是通过深入思考得到更“丰富”的模型。

  领域模型和业务相一致,必须通过业务人员和技术人员的协作才能完成。业务人员的参与,能为领域模型带来专业的领域知识,而技术人员可以为领域模型带来更高的抽象性和严谨性。

  除了模型驱动设计以外,DDD 中的另一个核心模式是统一语言(Ubiquitous Language)。统一语言包含了两个层面的含义:一是业务和技术人员之间的语言是统一的,二是开发团队内部各角色之间的语言是统一的。最终结果就是每一行代码都能对应到统一语言,从而与业务保持一致。你可能已经发现了,统一语言和领域模型的目的是一致的。领域模型、和词汇表(glossary)和业务规则表等文档性的制品,就是统一语言的“物质基础”。

 

四、代码实践——目录结构

  网上的DDD程序目录由很多种,大部分都是基于DDD的各种架构思想得来的。实践过程中没有完整的采用某种结构,个人感觉DDD主要还是指导思想,实际的代码结构,代码的实现都要看团队实际情况来做出取舍,如果团队对DDD了解的比较少,感觉可以舍弃一些严格的分层写法的限制,节约理解成本。

整体目录结构如下:

适配器层目录结构如下:

 应用层结构如下

 领域层结构如下:

   之前在网上看到的资料有推荐将与数据库的交互放到基础层的,但是我感觉还是按照钟敬老师的方式都放到适配器好一些,这是基于六边形架构的思想做出的代码结构。此外由于项目代码比较简单没有采用单独建PO转DO的工厂或者装配器,而是直接在仓储实现的代码中处理了,其实最好还是单抽出来。项目中DTO转DO还是使用了装配器(Assembler),没有使用工厂的原因是觉得工厂实现起来还是比较复杂代码量较大,此外感觉如果使用工厂由于代码层次是在domain层,没法使用应用层的DTO什么作为入参,这样的话调用工厂相关的代码也不少。项目业务比较简单于是舍弃了工厂写法。

下面放一份网络上其他方案的结构说明:

-interfaces(用户接口层)     -assembler:DTO转换成领域对象     -dto     -facade:controller   -application(应用层)     -event:事件         -publish:事件发布         -subscribe:事件订阅     -service:应用服务 应用服务会对多个领域服务或外部应用服务进行封装、编排和组合,对外提供粗粒度的服务   -domain(领域层)     -aggregate:聚合         -entity:实体 放聚合根、实体、值对象以及工厂模式(Factory)相关代码         -event:事件 存放事件实体以及与事件活动相关的业务逻辑代码         -service:存放领域服务代码。一个领域服务是多个实体组合出来的一段业务逻辑。         -repository:仓储          -infrastructure(基础层)     -config:配置相关代码     -Util:存放平台、开发框架、消息、数据库、缓存、文件、总线、网关、第三方类库、通用算法等基础代码   ps:关于语法命名的一个小tips

  repository接口名称不应该使用底层实现的语法:我们常见的insert、select、update、delete都属于SQL语法,使用这几个词相当于和DB底层实现做了绑定。相反,我们应该把 Repository 当成一个中性的类 似Collection 的接口,使用语法如 find、save、remove。在这里特别需要指出的是区分 insert/add 和 update 本身也是一种和底层强绑定的逻辑,一些储存如缓存实际上不存在insert和update的差异,在这个 case 里,使用中性的 save 接口,然后在具体实现上根据情况调用 DAO 的 insert 或 update 接口。

 

标签:模型,业务,领域,事件,设计,驱动,代码,DDD
From: https://www.cnblogs.com/qingfengsuixin/p/17420471.html

相关文章

  • 程序与设计
    2-27在命令行窗口中启动的Python解释器中实现在Python自带的IDLE中实现print("Helloworld")编码规范每个import语句只导入一个模块,尽量避免一次导入多个模块不要在行尾添加分号“:”,也不要用分号将两条命令放在同一行建议每行不超过80个字符使用必要的空行可以增加代码的可读性运......
  • java通用xls导出设计
    背景在后端日常开发中总会有各种各样的导出需求,实现这个需求必须要解决的两个问题:1、表头不能直接使用字段名,需要显示为中文,甚至还需要考虑国际化2、值需要翻译,比如性别、状态之类的字段现状现在主流写的比较好的方法是定义一个对象,对象上用自定义的注解+easytrans我的解决......
  • 【实践篇】领域驱动设计:DDD工程参考架构
    背景为什么要制定参考工程架构不同团队落地DDD所采取的应用架构风格可能不同,并没有统一的、标准的DDD工程架构。有些团队可能遵循经典的DDD四层架构,或改进的DDD四层架构,有些团队可能综合考虑分层架构、整洁架构、六边形架构等多种架构风格,有些在实践中可能引入CQRS解决读模型与......
  • BOSHIDA电源模块 开关电源磁性元件设计 了解磁学
    BOSHIDA电源模块开关电源磁性元件设计了解磁学对于许多电气工程师来说,磁学相关的理论通常晦涩难懂,大家发现。在导体中描述电流流动是相对比较容易的,但是难以直观地想象电流发出的磁场。结果就是,许多磁性元件设计被“外包”给其他部门的“专家”,他们可能是来自于公司内部的另一个......
  • 基于C++实现房贷计算器的设计
    访问【WRITE-BUG数字空间】_[内附完整源码和文档]本次项目的要求是完成一个房贷计算器的设计,实现商业贷款、公积金贷款和组合贷款的利息计算三种功能。并且使用Qt或其他的界面库设计人机交互界面,要求界面友好方便使用。并且必须使用面向对象的思想进行设计,使用C++编程。1.题目要求......
  • c语言程序设计知识点总结03
    c语言程序设计知识点总结03地址(Address):计算机的内存由若干个字节内存单元构成,每个字节内存单元都有一个唯一的地址用于区分和存取单元中的数据。形式上,地址是一个无符号整数,从0开始,依次递增,在表达和交流时,通常把地址写成十六进制数。指针(Pointer):一个变量,它存有另外一......
  • 计算机组成原理:阵列乘法器设计实验
    实验名称:1.2阵列乘法器设计实验实验目的了解运算器的组成结构。基于数据通路图,观测并分析运算器的工作原理。基于信号时序图,观测并分析运算器的工作原理。实验设备PC机一台,TDX-CMX实验系统一套。实验预习画出4*4阵列乘法器原理图,分析延迟与哪些因素有关。答:(上传图片......
  • 数模混合设计的LVS流程
    数模混合设计的LVS流程1.前言最近项目到了验证环节,在做LVS碰到了一些问题。网络上也没有文章给出完整的解决方案,自己试了一下,踩了一些坑之后基本上搞定了这个问题,现记录流程供学习交流。整体流程包括:数字模块单独LVS,模拟模块单独过LVS,数字网表反提原理图,顶层数字symbol处理,原......
  • 程序设计进阶模拟试题
    题目描述程序定义了NxN的二维数组,并在主函数中自动赋值。请编写函数fun,函数的功能是:使数组右上三角元素中的值乘以m。#include<stdio.h>#include<conio.h>#include<stdlib.h>#defineN5intfun(inta[][N],intm)/不得改动此注释文字及位置,begein/{}/不得改动此注释文字......
  • 设计模式总结
    2023年05月21日18:17:36设计模式分类创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式、简单工厂模式。结构型模式,共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。行为型模式,共十一种:策略模式、模板方法模式......