解惑领域驱动设计

2021-11-15 From 张逸说 By 张逸

最近重读Eric Evans的经典《领域驱动设计》,正如Eric提倡我们要去发现隐式概念一般,这次重读也让我发现了许多隐藏的DDD知识。恰好今日有朋友咨询我一些DDD问题,好似激活了触发器,随着问题的解答,我倒是在回答过程中又把这些知识梳理了一遍,才有了这篇杂记。

问题一:Repository的问题

怎么看待DDD中的Repository?我们必须把握一个根本的底线,就是采用DDD方式设计Repository时,一定要忘记所有与数据访问有关的技术实现细节。Repository接口属于领域层,一旦我们将Repository视为DAO对象,就会不期然地重回数据驱动设计的老路。

Eric在书中写道:“Repository将某种类型的所有对象表示为一个概念集合(通常是模拟的)”。这句话一语道破天机,也是DDD得名的由来,必须是通过领域去驱动设计,也就是说在这个设计过程中,应尽量去掉技术的色彩。

借用Martin Fowler对重构的隐喻,在领域驱动设计过程中,也有两顶帽子:领域设计技术实现。在进行领域设计时,考虑的应该是领域逻辑业务规则,以及随之需要设计演进的领域模型;一旦开始关注技术实现,就应该切换到与领域完全无关的技术关注点上。这也就是我认为非常关键的点:分离技术复杂度和业务复杂度。

Repository是一个概念集合,我们在领域设计时,又需要保证领域概念的完整性,并考虑领域逻辑的不变性约束,因此,DDD才会引入Aggregate。同时,DDD明确约定:一个Aggregate只能有一个Repository,即聚合根的Repository。所有对聚合的访问都应该通过Repository来完成。

问题二:针对没有采用DDD的项目,如何演化为DDD

在《领域驱动设计》的第四章“分离领域”,Eric给出了几点DDD的适用范围:

  • 领域驱动设计只有应用在大型项目上才能产生最大的收益,而这也确实需要高超的技巧。不是所有的项目都是大型项目;也不是所有的项目团队都能掌握这些技巧
  • 如果一个架构能够把那些与领域相关的代码隔离出来,得到一个内聚的领域设计,同时又使领域系统其它部分保持松散耦合,那么这种架构也许可以支持领域驱动设计
  • 领域实现独立出来是领域驱动设计的前提

因此,领域驱动设计绝对不是银弹,我们也不要将领域驱动设计视为拯救项目的灵丹妙药。从上述几点描述,我们似乎可以得出DDD的基础要素:

  • 项目的规模与领域复杂度
  • 项目成员的设计能力

当我们开始做一个新项目时,有可能从一开始业务并没有多复杂,系统规模也不够大,没有运用DDD是可以接受的选择。但随着需求的增加与变化,项目规模与领域复杂度都达到了DDD的要求。这时该如何应对?

针对这种已有的系统,若要从Non-DDD形式演化为DDD形式,无非是两种策略:

倘若开启的新项目在领域复杂度上达不到DDD的要求,我仍然建议运用DDD,只不过需要将DDD的设计重点放在战略设计阶段,即对项目划分合理的Bounded Context。一旦确定了这些Context的边界,在边界之内进入战术设计阶段时,就可以不采纳DDD的设计方式,例如选择使用Transaction Script。

问题三:微服务领域驱动设计的关系

领域驱动设计的战略设计可以帮助我们识别微服务边界。针对微服务内部,可以采用DDD的方式,也可以采用其他方式,这个并没有特别约束。

大体可以这样认为:

实践中,我们通常会使用DDD的Bounded Context、Context Map以及六边形架构来指导微服务设计。反过来,由于微服务强调服务的独立部署,因此微服务的引入重新定义了Bounded Context的边界服务之间的通信也突破了Context Map的集成模式。

至于微服务数据存储的设计约束——“每个微服务数据单独存储”,属于基础设施层面,严格来讲,与领域驱动设计是没有任何关系的。

本文来源:张逸说,转载请注明出处!

来源地址:http://zhangyi.xyz/solve-puzzle-of-ddd/

发表感想

© 2016 - 2022 chengxuzhixin.com All Rights Reserved.

浙ICP备2021034854号-1    浙公网安备 33011002016107号