背景

几年前我总结过DDD战术设计的一些落地经验可落地的DDD(5)-战术设计,和一次关于聚合根的激烈讨论最近两年有些新的落地体验,回过头来发现,当初对这些概念的理解还是没有深入,这篇文章重新阐述下。

之前理解不到位的点有

  1. 战术设计的各个模块是的协作关系
  2. 哪些是问题空间问题,哪些是方案空间问题边界没有划分清楚。
  3. 实体和聚合根的区别理解不不深刻,实体和聚合根建模的方法不对。

以上问题将会在下文解释清楚。

战术设计拆解

DDD的战术设计即设计某个子域的领域模型以及代码落地。领域事件、领域对象、聚合根、实体、值对象、领域服务、工厂、资源库等这些概念都属于这个范畴。

笔者将这些概念重新分层组装了下,如下图所示。



首先将整体分成两部分,问题空间和方案空间。

  1. 问题空间即领域建模。是对业务问题的描述,以及我们如何对这些问题进行抽象。这些是需要在业务、产品、开发都必须达成一致的,与具体的技术方案无关。
  2. 方案空间即如何用技术手段来解决问题,与具体技术的实现有关。

问题空间即领域建模,是通过实体、值对象、领域服务、领域事件来表达。

  1. 实体和值对象是模型对象,实体是重中之重,包括核心模型数据、行为、状态。之所以要区分实体和值对象,是为了降低复杂度,因为值对象是个常数对象,不需要花太多精力。

    注意某个对象在某个领域内是个值对象,在另外的领域可能是个实体,所以脱离领域上下文,说某个对象是值对象,肯定是不对的,比如大家常说的地址是个值对象,这一定是对的吗?

  2. 领域事件即实体产生的事件

  3. 领域服务包括一些逻辑的计算,和业务策略。比如商业决策逻辑、业务流程等。

方案空间即如何解决问题,实现领域模型与代码的映射。实现设计与实现的一致性。主要通过工厂,聚合,资源库来表达。

  1. 聚合是对实体、值对象的封装。领域外部对领域对象所有访问都基于聚合来。如基础设施层操作聚合进行数据保存。其他领域引用聚合对象数据。

    聚合的设计一般是围绕着技术来的,比如聚合对象事务性。

  2. 工厂,复杂对象的创建工厂类

  3. 资源库,对聚合的操作。

从笔者的实践角度来说,落地DDD过程中,问题空间比方案空间更重要,收益更大。因为通常我们吐槽的某些代码写的烂,贫血模型。背后并不是因为没有用DDD,而是问题空间没有定义好,对于业务没有深刻理解,导致模型抽象不足。

如何建模

为什么要建模

通常在某个子域落地DDD,我们会按照业务分析-》用例分析-》领域建模(问题空间) -》技术落地(方案空间)这些步骤来操作。但其实即使我们不在代码里落地DDD,只用前面3步维护一个子域内的领域模型也同样能够带来很多收益,包括但不限于

  1. 统一业务组各个角色的认知,业务、产品、开发大家对同一概念的认知是一致的。
  2. 指导开发工作的拆分。

比如在淘宝有个血的教训,至今这个历史债还无法被修复。早期在淘宝开店。一个卖家只能开一个店。卖家和店铺是两个领域对象,关系是1:1。店铺服务觉得是1:1的关系,对外提供的服务有根据sellerId获取店铺信息,所以其他调用方就无意识的直接引用了卖家id,这样也可以拿到店铺。导致shopId被等同于了sellerID。这个误引用发生在成千上万个地方,最后导致后续需要支持一个卖家开多店铺时无法支持。只能通过其他trick方式实现。

以之前介绍过的CRM领域 来讲解。

省略业务分析,直接拿到用例。

用例分析



按用户角色罗列所有的用例,用来推导模型、以及模型之间的关系。领域模型建立好了,需要根据列出的用例来走查一遍,要确保所有的用例都能走通。完整的用例集才能推导出正确的模型,所以当有变化时,首先调整用例集,再来修改领域模型

建模

领域建模就是定义模型对象,以及模型对象之间的关联关系。分两步建模,第一步通过名词找模型对象。第二步通过动词、形容词分析对象关联关系

名词

通常反复出现的主语和宾语中的名词就是模型对象,比如市场人员创建一个活动,活动就是一个模型对象。当然定语中出现的名词也可能是模型对象。

1.名词的定义一定要清晰。比如说crm领域有通用的名词叫商机。但是你对口的产品经理不熟悉crm领域,新造了一个词,那你要及早纠正他。

2.名词的含义在限界上下文内语义唯一,在不同的上下文中概念就不一定一样了。比如市场人员创建的活动,和做营销时创建的活动就不一定。

动词、活动

1个市场人员可以创建多个活动,所以市场人员和活动关联关系是1对多。两者独立存在,普通关联关系。

这里为了简化描述,只列了市场活动、线索、客户、商机这些域。用户、角色、权限、数据分析这些域先忽略了。

产出物

在推导的过程中,我们是按照自底向上的方式推导的,最后我们呈现出来的结果是按照如下方式

  1. 领域名词

    市场活动: 市场人员为了展示公司形象、推广公司产品,获取线索而举办的活动。一个活动中可以创建多个线索。

线索: 销售人员基于线索发掘潜在客户,多个线索转换为一个客户。线索可以由一个市场活动生成,或者其他渠道。

客户:有意向购买公司产品的用户,销售人员可以通过跟进客户,转化销售机会。

销售机会:更高质量的线索,有机会签单。可以通过客户转换得到,也可以通过其他渠道来获取

  1. 领域模型

    如上图

  2. 主要领域状态转换。

    因为复杂的领域对象生命周期以及一些跨领域对象交互情况在领域模型图中表达不出来,所以需要借助额外的图来表达。

可落地的DDD(7)-战术设计上的一些误区的更多相关文章

  1. 可落地的DDD(5)-战术设计

    摘要 本篇是DDD的战术篇,也就是关于领域事件.领域对象.聚合根.实体.值对象的讨论.也是DDD系列的完结篇. 这一部分在我们团队争论最多的,也有很多月经贴,比如对资源库的操作应该放在领域服务还是领域 ...

  2. 战术设计DDD

    可落地的DDD(5)-战术设计   摘要 本篇是DDD的战术篇,也就是关于领域事件.领域对象.聚合根.实体.值对象的讨论.也是DDD系列的完结篇.这一部分在我们团队争论最多的,也有很多月经贴,比如对资 ...

  3. DDD领域驱动设计落地实践(十分钟看完,半小时落地)

    一.引子 不知今年吹了什么风,忽然DDD领域驱动设计进入大家视野.该思想源于2003年 Eric Evans编写的"Domain-Driven Design领域驱动设计"简称DDD ...

  4. DDD(领域驱动设计)--战术设计

    前言 战术设计 战略设计为我们提供一种高层视野来审视我们的软件系统,主要包括领域/子域.通用语言.限界上下文和架构风格等概念, 而战术设计则将战略设计进行具体化和细节化,它主要关注的是技术层面的实施, ...

  5. C#进阶系列——DDD领域驱动设计初探(二):仓储Repository(上)

    前言:上篇介绍了DDD设计Demo里面的聚合划分以及实体和聚合根的设计,这章继续来说说DDD里面最具争议的话题之一的仓储Repository,为什么Repository会有这么大的争议,博主认为主要原 ...

  6. DDD领域驱动设计初探(二):仓储Repository(上)

    前言:上篇介绍了DDD设计Demo里面的聚合划分以及实体和聚合根的设计,这章继续来说说DDD里面最具争议的话题之一的仓储Repository,为什么Repository会有这么大的争议,博主认为主要原 ...

  7. 可落地的DDD(4)-如何利用DDD进行微服务的划分(2)

    摘要 在前面一篇介绍了如何通过DDD的思想,来调整单体服务内的工程结构,为微服务的拆分做准备.同时介绍了我们在进行微服务拆分的时候踩过的一些坑. 这篇介绍下我们最终的方案,不一定对,欢迎留言讨论. 微 ...

  8. 浅谈我对DDD领域驱动设计的理解

    从遇到问题开始 当人们要做一个软件系统时,一般总是因为遇到了什么问题,然后希望通过一个软件系统来解决. 比如,我是一家企业,然后我觉得我现在线下销售自己的产品还不够,我希望能够在线上也能销售自己的产品 ...

  9. DDD 领域驱动设计-商品建模之路

    最近在做电商业务中,有关商品业务改版的一些东西,后端的架构设计采用现在很流行的微服务,有关微服务的简单概念: 微服务是一种架构风格,一个大型复杂软件应用由一个或多个微服务组成.系统中的各个微服务可被独 ...

随机推荐

  1. ImageView的scaleType属性 与 adjustViewBounds属性

    ImageView的scaleType的属性有好几种,分别是matrix(默认).center.centerCrop.centerInside.fitCenter.fitEnd.fitStart.fi ...

  2. 服务器安全加固 - Linux

    一.账号和口令 1.1 禁用或删除无用账号 查看 /etc/passwd 文件查看是否有无用的账号,如果存在则删除,降低安全风险. 操作步骤: 使用命令 userdel <用户名> 删除不 ...

  3. VUE3 之 自定义指令的实现 - 这个系列的教程通俗易懂,适合新手

    1. 概述 老话说的好:能屈能伸的人生,才是完满而丰富的人生. 言归正传,今天我们来聊聊 VUE 中自定义指令的实现. 2. 自定义指令 2.1 文本框聚焦的实现  <body> < ...

  4. 五四青年节,今天要学习。汇总5道难度不高但可能遇到的JS手写编程题

    壹 ❀ 引 时间一晃,今天已是五一假期最后一天了,没有出门,没有太多惊喜与意外.今天五四青年节,脑子里突然想起鲁迅先生以及悲欢并不相通的话,我的五一经历了什么呢,忍不住想说那大概是,父母教育孩子大声嚷 ...

  5. Jmeter接口测试流程详解(中科软测认证中心)

    1.jmeter简介 Jmeter是由Apache公司开发的java开源项目,所以想要使用它必须基于java环境才可以: Jmeter采用多线程,允许通过多个线程并发取样或通过独立的线程对不同的功能同 ...

  6. 斯坦福NLP课程 | 第12讲 - NLP子词模型

    作者:韩信子@ShowMeAI,路遥@ShowMeAI,奇异果@ShowMeAI 教程地址:http://www.showmeai.tech/tutorials/36 本文地址:http://www. ...

  7. BUUCTF刷题记录(更新中...)

    极客大挑战 2019]EasySQL-1 直接通过输入万能密码:' or 1=1#实现注入: 思考:服务端sql语句应该为:select * from users where username='xx ...

  8. Python实现将excel文件转化为html文件

    需要转化的excel文件(nsrxx.xlsx): 源代码: import pandas as pdimport codecspd.set_option('display.width', 1000)p ...

  9. 爬取豆瓣喜剧类热门TOP60的电影

    学习任务:爬取豆瓣喜剧类热门TOP60的电影并保存在douban.txt文件中. 代码示例: import requests url="https://movie.douban.com/j/ ...

  10. js颜色调试器

    1 /* ColorTestViewer 颜色调试器 2 3 attribute: 4 onchange: Function; //颜色改变回调; 默认null 5 6 //以下属性不建议直接修改 7 ...