• potato00fa
    2019-11-29
    我对DDD的看法就是,它可以把原来最重的service逻辑拆分并且转移一部分逻辑,可以使得代码可读性略微提高,另一个比较重要的点是使得模型充血以后,基于模型的业务抽象在不断的迭代之后会越来越明确,业务的细节会越来越精准,通过阅读模型的充血行为代码,能够极快的了解系统的业务,对于开发来说能说明显的提升开发效率。
    在维护性上来说,如果项目新进了开发人员,如果是贫血模型的service代码,无论代码如何清晰,注释如何完备,代码结构设计得如何优雅,都没有办法第一时间理解系统的核心业务逻辑,但是如果是充血模型,直接阅读充血模型的行为方法,起码能够很快理解70%左右的业务逻辑,因为充血模型可以说是业务的精准抽象,我想,这就是领域模型驱动能够达到"驱动"效果的由来吧
     6
     106
  • miracle
    2019-11-29
    建议将完整一些的代码放到 github 上 然后感兴趣的话可以自行去github 上研究或者提 pr

    作者回复: 好的,我把完整代码抽空整理好放到github上
    https://github.com/wangzheng0822

     5
     36
  • 辣么大
    2019-11-29
    理解OOP,我们就不难理解DDD:
    DDD第一原则:将数据和操作结合。(贫血模型将数据和操作分离,违反OOP的原则。)
    DDD第二原则:界限上下文。这是将“单一指责”应用于我们的领域模型。

    DDD is nothing more than OOP applied to business models. DDD其实就是把OOP应用于业务模型。

    实现:
    1、使用通用语言(Ubiquitous Language):类、方法、字段的命名,要符合业务。使用业务语言命名,以后在和客户或者其他团队交流时能够更顺畅。

    2、理解系统业务:例如做一个理财系统,要亲自去和银行卖理财产品的人聊聊或者买个理财产品之后,那些数据库中对你来说毫无意义的字段才变得有血有肉。

    介绍一篇博客吧:DDD101 https://medium.com/the-coding-matrix/ddd-101-the-5-minute-tour-7a3037cf53b8

    最后,是时候祭出大杀器了:《领域驱动设计》Eric Evans (反正我也没看)
    展开
     9
     32
  • 风之射手座
    2019-11-30
    第2步支付处理流程感觉有点问题:
    从用户的虚拟钱包转90到商家虚拟钱包应该就完了,不应该再从应用公共银行卡再划钱到商家银行卡。如果要即时划转到商家银行卡,就要记得把商家的虚拟钱包减少90。
    好像是这样吧?
     9
     20
  • 丿淡忘
    2019-11-29
    这两天一直在思考ddd,就等课程更新,这样一说就理解了,domain模型使用充血模型设计,使之具备独立性,而业务无关的vo,po就可以使用贫血模型进行设计,因为不涉及具体复杂业务,如果control层需要调用多个领域模型,则把相关的领域服务组合在一起,这里有个小问题,就是do转为dto这个过程,应该是在应用层完成还是领域层完成,如果在应用层完成,好像属于把领域模型暴露出去了,希望老师可以在指点一下
     9
     19
  • 邹佳敏
    2019-12-02
    看了一圈评论,好像没有人和我有同样的疑惑?
    争哥说了很多交易流水表的设计,明明已经详细介绍了字段冗余的表1要明显优于表2,但为何在虚拟钱包的交易流水表的设计里,使用的又是字段紧凑的表2呢?
    那么,在底层虚拟钱包的交易流水表里,同样会存在数据不一致的情况呀?A转出被记录下来了,B转入失败。

    作者回复: 是有这个问题 我改下

     4
     14
  • Cy23
    2019-11-29
    听完一遍,看来我需要在听一遍,php视乎要理解JAVA的有点差异啊
     14
     10
  • join
    2019-11-30
    看到这里,感觉才真正理解充血模型的作用:

        真正的业务逻辑都放在充血的领域对象中,与具体使用什么框架(比如Spring,MyBatis),具体使用什么数据库无关。这样有利于保护领域对象中的数据,比如钱包中的余额,当有入账和出账操作时,余额在领域对象中自动执行加减操作,而不是将余额暴露在Service中直接操作(这样很容易出错可能导致帐不平衡,余额应该封装保护起来),当然“余额自动增减”这只是一个简单的业务逻辑例子,业务逻辑越复杂就越应该封装到领域对象中。

    1. Service层只是一个中间层,起到连接和组合作用。
    用于支持领域模型层和Repository层的交互(连接作用),利用各种领域对象执行业务逻辑(组合作用)。
    比如通过Repository查出数据,将数据转换为领域模型对象,利用领域模型对象执行业务逻辑(核心),然后调用Repository更新领域模型中的数据。

    2. Service类还负责一些非功能性及与三方系统交互的工作。
    比如幂等、事务、发邮件、发消息、记录日志、调用其他系统的 RPC 接口等。

        不允许Service中的逻辑过于复杂,如果Service中的组合的业务逻辑过于复杂,我们就要将这业务逻辑抽取出一个新的领域对象进行封装,通过调用这个领域对象来进行这些复杂的操作。

        由于controller和Repository层中本身没有什么业务逻辑,controller中的Vo对象实际上只是传输数据使用(数据从系统传输数据到外部调用方),Repository中的Entity本质上也只是传输数据(数据从数据库中传输数据到系统),所以用贫血模型不会带来副作用,是没有问题的。
    展开
    
     8
  • 落叶飞逝的恋
    2019-11-29
    还有一点,期待老师实现一个完整的案例的代码以供我们参考琢磨。

    作者回复: 完整案例代码可能就太多了

     5
     8
  • 随机的
    2019-12-06
    请教一下老师,以及各位同学,销售单、进货单、调拨单、入库单、出库单之类的单据类型是否适合使用ddd,单据的操作一般是新增编辑删除,还有状态的变化,以最复杂的调拨单为例,调拨单有新增、编辑、删除、查找操作,还有状态操作,比如从草稿到待审核,待审核到已审核,待审核到拒绝,审核通过之后还要在出库仓库生成待发货的出库单,入库仓库生成待收货的入库单,出库单入库单又有各自的状态操作,出库单确认发货,出库单变成已发货状态,同步修改调拨单和入库单的状态为已发货,入库仓库收到货,确认收货后,入库单变成已收货,同步修改调拨单和出库单的状态为已收货,这已经是简化的流程,我当前的实现中还涉及到仓库与总部的结算,仓库部分发货,部分收货等操作,结算还支持部分结算,就更复杂了,这种情况下,适合使用ddd吗?若适合,该怎么使用,仿照老师虚拟钱包的例子,实在不知从何下手,ddd不是更适合复杂操作吗,这里该如何应用ddd呢?求指教,感激不尽。
    
     7
  • 南山
    2019-11-30
    DDD真正的价值在于战略设计,对业务模型到领域模型的建模时需要重点关注的有哪些,比如确定核心服务(核心域、通用域、支撑域)、微服务边界(领域、子域)、领域边界(限界上下文),功能归类(聚合)等等。而战略设计最终的目的仍然是说过来说过去的那些,高内聚、低耦合、面向对象设计、职责单一、易扩展、易维护、易拆分、易演进。
    DDD战术设计是一种实施的方法论,但是因为他是看的见、摸得着(有真正所谓的代码结构可以参考)的,吸引了更多的关注点,如果没有背后的战略设计的思想,生搬硬套,甚至可能会适得其反。
    DDD最重要的还是设计思想,也就是战略设计,而不是他的模式或者分层方式,也就是战术设计!
    
     7
  • 墨雨
    2019-11-29
    看了老师的这篇文章让我对 entity,bo,vo有了一个更清晰的认识。我是这样理解的,entity是对数据库的映射,vo 是前端展示的映射,bo 在 DDD 充血模型中我看到了他的用处,看起来他是将 entity 的一些逻辑业务分离了出来做了一个解耦(在我看来貌似没有 bo 或者说 Domain 类似 加余额减余额的逻辑也可以写在 entity 中,只是这样做对于专注于数据库的 entity 来说逻辑更复杂了,维护起来会很困难 ),同时也解决了 entity 暴露过多 getter setter 方法的问题。不知道我这样理解有没有问题,欢迎老师指正。

    同时我有如下几个疑问:
    1.具体上 domain 和 entity 属性和结构上有哪些不同呢?(在我看来好像能写成一样的)
    2.在贫血模型下 bo 的作用好像没有那么明显了,多写一层 bo 能给我们带来什么好处呢?
    3. entity bo vo 类属性上好像有很多重合,貌似在实际编写的过程会出现很多重复代码,并且要为每一层编写转换代码,代码量好像又增加了,对于这种情况应该怎么优化和权衡呢?
    展开
     4
     5
  • 睡觉💤
    2019-11-29
    在我看来,Repository与Domian都是service的底层。Repository复杂数据的存储,Domian负责业务逻辑,service将两者融合。
    
     4
  • 落叶飞逝的恋
    2019-11-29
    DDD 中VirtualWalletService convert哪里定义了。
     4
     3
  • Angus
    2019-11-29
    我理解的ddd分为四层,用户接口层,应用层,领域层,基础设施层。领域服务还是跟基础设施层打交道,领域服务主要是提供这个领域的业务行为,通过应用层聚合领域服务,而应用层正是和领域专家建立统一语言的一层,
    
     3
  • 旺旺
    2019-11-30
    对于支付类型的交易,钱包的交易流水记录中的虚拟钱包交易流水ID会有2个吧,一个加钱流水,一个减钱流水。
    
     2
  • 阿卡牛
    2019-11-29
    十个项目九个挂,做为一个瘦子,先从贫血开干,等项目有奔头了,吃成胖子后再充血:)
    
     2
  • sprinty
    2019-11-29
    感谢老师的分享,收获很多,也产生了两个问题:

    问题1:Entity 转换成 Domain 的代码应该在哪一层实现?感觉在 Service 层不大合适,因为可能多个 Service 会使用到。
    问题2:如果涉及到表单的保存,入参是一个保存全量数据的对象(比如,创建一个新用户的所有用户数据,但部分属性还是要计算得到的,比如年龄等)。这个对象是属于 VO 吗?这时的 Domain 怎么设计呢?数据模型间的转换怎么处理呢?VO->BO->Entity 感觉就是在写各种赋值语句啊, 所以我以前在传统开发模式是合并 VO、BO、Entity的,一个大而全的东西也是很尴尬。

    期待老师解答。
    展开
     3
     2
  • 老姜
    2019-11-29
    更新流水出现异常会导钱包操作成功了,但是就是状态是错误的?是不是应该把生成流水放到一个事务里面,更新钱包和更新流水状态放到另外一个事务里面会避免这个问题?
    
     2
  • adasumm
    2020-01-06
    感觉是懂非懂,目前只知道充血模式是将service分开成“纯业务”+“与Repository 层交互,或拆分不开”,但还是不知道业务逻辑怎么拆分。写的案例看不懂
    
     1
我们在线,来聊聊吧