第10&11周
2020年03月16日 - 2020年03月29日

编辑|子鱼

#问答与讨论

1.张老师,有关工厂的那一篇文章里,内部类Builder直接持有Flight对象,而不是持有和Flight对象一样的变量,是不是可以少很多代码,对于有很多成员变量的对象来说。参考mybatis的ParameterMapping 。当对象的成员变量都需要为final时,才用这种方式,参考Environment。

[无]

DDD屠龙刀

➤ 问题解答
张逸 09:15 **可以的。

2.请教大家一个问题:一个聚合中明细项中有 增,有减,也有不变的,这种情况怎么做聚合根覆盖?

[孙君]

DDD少林派

➤ 问题解答**
甘泉 11:44
全体覆盖
孙君 12:04
如果持久层用的是关系型数据库,就先清除,然后插入?

3.看完您的领域驱动的战略篇和战术篇,还是不知道领域驱动应该怎么应用于实际生产环境中。但是,感觉领域驱动确实可以解决一些复杂系统的问题。下一步应该怎么办?有什么好的建议吗@张逸

[小曦阳哟]

DDD少林派

➤ 问题解答
张逸 09:10
@小曦阳哟 可以尝试小范围的实践一下,也找一些案例来学习

4.通常两个上下文之间可以有双向关系吗?例如A上下文用了B的资料,B的上下文用了A的资料,此时把AB资料相关的抽取出C更合适,还是直接在AB中定义新的API包更合理一些

[张智高]

DDD少林派

➤ 问题解答
远远鱼 15:50
和类、模块一样,不要双向依赖
小曦阳哟 15:51
@张智高 抽出一个公共依赖
张智高 15:53
这样会不会最后演变成这个公共依赖都只为基础资料服务,而本应该出现在聚合B中的资料被剥离出去,B只是做业务功能了
张智高 15:54
或者也可能是我在划分的时候上下文过大,导致出现一些不合理性
张智高 15:58
我举个栗子吧,我现在是根据语义来划分的,与人相关的放在了同一个项目里。这里面有两个功能,一个是用户的黑白名单(公共),一个是需要根据一定的规则来做人的匹配(业务)。前面这部分会被其他多个项目依赖使用,因为资料较为基础,这时候有必要把这两个东西剥离开吗
远远鱼 15:59
也可以A B都保留一份C
然后采用领域事件模式,服务之间传递消息,解除依赖。
所谓公有部分C,也许更适合A和B各存一份,这样可以在A和B都对C有专有模型,而不需要考虑C适用于整个领域
远远鱼 15:59
A B各保留一份C,也许更符合微服务的“服务自治”
张智高 16:00
但解决不了最终在数据库层面的数据共享吧,只是各取所需,各自定义持久层的实现
远远鱼 16:07
“张智高: 我举个栗子吧,我现在是根据语义来划分的,与人相关的放在了同一个项目里。这里面有两个功能,一个是用户的黑白名单(公共),一个是需要根据一定的规则来做人的匹配(业务)。前面这部分会被其他多个项目依赖使用,因为资料较为基础,这时候有必要把这两个东西剥离开吗”
- - - - - - - - - - - - - - -
限界上下文最重要的价值,就是承认一个模型(比如用户),不需要解决所有的问题。不同的问题强行由一个模型来解决的话,常常会让模型不清晰不一致。所以拆成多个模型,然后由限界上下文的边界限制模型的使用范围
所以说,剥离符合限界上下文模式
远远鱼 16:08
“张智高: 但解决不了最终在数据库层面的数据共享吧,只是各取所需,各自定义持久层的实现”
- - - - - - - - - - - - - - -
微服务是要数据存储独立。不要奢求一个表用来保存不同限界上下文的多个模型,哪怕这些模型是同一个概念(比如用户)

5.请问你们domainService的入参是啥啊,是entity还是平铺还是啥呢?

[刘杰]

DDD少林派

➤ 问题解答
张智高 18:12
我都是看参数个数的,不多(少于5个)就直接平铺了。
不过也有说通过简单类型的入参,容易误用,因此会通过明确含义的实体进行输入
刘杰 18:13
我看这个ppt里传的是entity,但我个人感觉好像是不太好的。
Pany 18:14
谁也不能保证这个参数个数就不会发生变化 所以传entity我觉得没问题哈。
刘杰 18:17
领域服务暴露的也是领域行为,参数是否应该是更明确的,这样包括外部传入及内部validate会更清楚。
Pany 18:20**
理想是丰满的。项目总在随着需求不断迭代。

6.大家对于 什么样的业务适合使用DDD 来改造有没有见解呢, 如果只是类似微博这样的业务 (发布,订阅,评论)是否适合使用DDD来设计?

[sunjun]

DDD少林派

➤ 问题解答
Logos 14:06
DDD是用来处理复杂逻辑的吧,微博目前的业务偏向的技术的复杂度而不是业务的复杂度吧
sunjun 14:08
那什么样的业务才算复杂呢
sunjun 14:09
除了单纯的CURD 业务外
sunjun 14:10
是否可以这么理解, 业务涉及到多状态,对流程流转 才算复杂呢
Logos 14:10
这个应该是凭经验来了,或者先用三层架构实现,等觉得业务实现起来越来越麻烦了,新人入场很难理解业务了,再进行DDD重构?
lucoo 14:10
任何场景都可以用DDD来落地,只是你要权衡而已,简单的业务传统的三层模型反而更清晰
Logos 14:14
反正所有业务归根究底就是输入和输出之间的转换,而DDD或者其他的什么,都是为了提高开发效率也就是提高生产力,代码清晰是带来生产力提升的一种方式
Logos 14:15
不过换句不好听的话说,简单的业务使用DDD 然后用以调动大家工作的积极性,也是提升生产力的一种
小浩子 15:11
我倒是在一些小项目上开始尝试DDD。我觉得DDD更重要的在于思维,就跟设计模式一样,无论是什么样的项目,哪怕单体应用,走一遍统一语言、限界上下文、上下文映射、聚合划分、分层架构,对于核心逻辑的保护、技术与业务分离、提高扩展性都是有好处的
小浩子 15:12
张老师的课里也说不需要拘泥于某些做法,比如技术实现比较稳定的地方就不一定非要依赖注入
叶锦铭 15:13
先从小项目开始实践,光学理论还不够
Logos 15:21
关于不拘泥某些做法的观点,我认为需要把刻意练习和实际使用区分开,通过刻意练习成为专家,然后才能不拘泥于某些做法
Logos 15:21
不然你哪知道你不拘泥的东西不是最主要的东西
小浩子 15:23
先理解、实践,才能灵活运用
a~ LiangXuanLin[Sticker] 11:00
领域设计可以认为回归到面向对象编程吧?回到本质上

7.目前苦学, 单元测试 xunit ,动机就是脱离 postman

[方豪]

DDD少林派

➤ 问题解答
方豪 15:58
有没有同感的同学
Logos 16:01
买椟还珠啊
Logos 16:01
TDD它不香么?
深山小书童 16:05
真的有上tdd的吗
someone 16:59
有啊
小曦阳哟 17:02
@方豪 单元测试有没有总结呀?我也在学习
方豪 18:20
https://www.cnblogs.com/edisonchou/p/5467573.html
方豪 18:21
分享一篇今天练习的单元测试文章
方豪 18:21
<单元测试的艺术>的读书笔记
方豪 18:26
我觉得DDD 也是, 我们不清楚 界限上下文如何划分,最好就是有这么一个小小的例子让我们感受到它的4个特性: 最小完备..稳定空间..
Sport 19:10
最小完备,稳定空间,自我履行,独立进化

8.限界上下文可包含多个聚合吗?

[kenny]

DDD少林派

➤ 问题解答
林杰 08:40
可以
kenny 09:42
一个领域就是一个限界上下文吗?
Pany 09:53
不可能是一个领域就是一个上下文。领域的范围太大了。

8.应用服务调用远程服务怎么理解???

[kenny]

DDD倚天剑

➤ 问题解答
a0b6e001ec5ad428ccac2b5fadb68ed9 .jpg

哪位大神帮忙解答一下
菡萏如佳人 10:43
比如应用服务可以直接访问资源库,资源库非本地进程情况下就可以理解为远程服务

9.有两个问题@张逸 大神能指点一下不? 1. 资源(Resource)服务和 控制器(Controller)服务的概念和使用场景是啥? 什么情况下该定义成资源服务, 什么情况下该定义成控制器服务? 2. 供应者(Provider)服务不是很理解, 它的概念和使用场景能详细介绍一下么?

[常昕]

DDD倚天剑

➤ 问题解答
lyning 12:10
我个人的理解:
遵循 REST架构,远程服务端提供的就是resource。
遵循 mvc 设计理念,远程服务端提供的就是 controller
提供者是相对于消费者而言的,例如ddd 中 上游服务就是下游服务的提供者
阿斌哥 13:38
我说下我狭义一点的理解:采用RESTful架构实现的OHS就是Resource,采用SpringMVC实现的OHS就是Controller,采用Dubbo、gRPC、Thrift等RPC框架实现的OHS的就是Provider,采用消息机制如Kafka,RocketMQ等实现的OHS就是Subscriber。

10.有个疑问关于Repository Update ,Repository的Delete和Insert方法是比较容易的实现的,既整体添加Aggregate 包括 Aggregate内的Entity,删除也是类似,对整个Aggregate操作,但是Update方法比较复杂了。因为我的DB用的是Sql Server或者MySql并不是纯粹的Key-Value方式存储Aggregate。

[M丶Long]

DDD倚天剑

➤ 问题解答
举个例子。
我们在Update OrderLine Aggregate 可能包括
修改OrderLine属性,或者删除OrderLine内的OrderItem集合的一个项,或者增加OrderItem集合中的一个项,或者修改OrderItem的属性。

这些操作在执行Repository Update方法的时候需要整体保存到关系型数据库中。
所以这个感觉这个Update的问题很难处理
有什么好的处理方式, Hibernate/JPA?
放到领域服务?
阿斌哥 11:29
可以收集一下DDD常见问题,这个问题可以排TOP5[呲牙]
M丶Long 11:30
那有啥好的解决方案吗
阿斌哥 11:45
说下我的一点拙见,欢迎大佬们指正:具体问题具体分析。为什么觉得整体更新不好?性能问题?这点性能损失真的对系统造成了不可接受的影响吗?如果确实造成了不可接受的影响,那聚合设计真的合理了吗?聚合能再小一点吗?如果不能再小了,那我们能有其他技术手段解决这个性能问题吗?如果确实没有其他技术手段了,那我们能破坏一点点DDD的原则吗?可以

11.在应用层可以通过http client调用其他外部的webapi接口吗?

[kenny]

DDD倚天剑

➤ 问题解答
阿斌哥 14:42
http client是属于具体的技术实现了,最好通过南向网关的抽象层将具体的技术实现隔离开。
kenny 14:44
南向网管抽象层应该放在应用层吗?
阿斌哥 15:10
建议去看下张老师的《领域驱动设计的菱形对称架构》,文章中论述的非常清楚。南向网关的抽象在六边形架构中属于出口端口,强行划分到DDD的分层架构中,会比较尴尬,对应不太上。张老师推出的菱形对称架构,也算是另辟蹊径,避免了这个尴尬。
和光同尘 16:11
这么说来南向网关抽象层是一个独立的项目?
王浩 16:19
那是六边形架构吧
和光同尘 16:38
http通信,controller层和application层可以合并吗
和光同尘 16:38
我把http client接口定义在南向网关抽象层,app层和controller层合并为一层作为实现 可行吗
工地少年与砖 16:56
controller是属于基础设施层的北向网关

12.多对多关系的两个实体是在一个聚合根还是两个聚合根比较好?比如说用户和角色

[小庞 ]

DDD倚天剑

➤ 问题解答

DDZ 15:29
我看到一个实现是这样:user是聚合根,role也是聚合根,userrole跟user
因即果,果求因。 15:30
Userrole是不是定义为值对象了@DDZ
DDZ 15:33
倒也没有,普通的entity
小庞 17:38
userrole不能是值对象
小庞 17:52
那这样的话在role里面需要保存userrole的集合属性吗?@DDZ
DDZ 17:55
不需要
DDZ 17:58
我看那个例子里的userrole是个entity,但是在相关文档上,建议的是value object
DDZ 17:59
userrole不能是值对象 为啥不能是值对象 能讲讲吗
DDZ 18:04
如果userrole上还有比如有效期限的话,是不是就不能是值对象了

13.各位,防腐层,消费者,定时服务你们会放在哪一层

[土族人]

DDD倚天剑

➤ 问题解答
和光同尘 10:43
基础设施
土族人 10:46
全部都放在基础设施么?
土族人 10:47
定时服务如果要调用领域服务呢?
土族人 10:47
消费者也要调用领域服务
和光同尘 10:49
直接调用