在单体应用的一些DDD实践经验

自从我在团队中推行DDD以来,我们团队经历了一系列的磨难——先是把核心项目重构,接着又在一些衍生项目中尝试全面落地DDD, 最终探索了一些经验出来,特此记录一下。

本文采用语言无关的角度陈述,无论你是Java或者c#的开发同学相信都可以无障碍阅读。

请注意本文并不是介绍如何实现DDD,因为这个话题实在太大了。

这次的主题是分享一些我们团队在实践DDD过程中碰到问题和如何克服它们,以及介绍一下我们所使用的架构体系。

 

先说说为什么标题限定在“单体应用”这个范围内,

我们团队这次实践的应用全是单体应用

如果是分布式的应用,那么拆分限界上下文(BoundedContext)的最佳实践是什么?当然是微服务!

我相信现在讨论微服务的文章肯定不在少数,微软也专门出过容器化微服务架构的电子书。传送门点我

资源如此丰富,当然就不需要我画蛇添足了。

 

领域模型

 

领域模型的分析可以说是DDD当中最为核心的部分,因为你整个系统的业务逻辑代码都是基于领域模型而构成的。

而要将业务逻辑转换成领域模型除了对业务的熟悉外还需要极高的抽象能力,所以一般需要业务专家和建模专家共同完成。

怎样提炼一个好的领域模型是一个非常大的话题,推荐你阅读以下书籍:

《领域驱动设计:软件核心复杂性应对之道Eric Evans

《实现领域驱动设计》Vaughn Vernon

领域驱动设计与模式实战》Jimmy Nilsson

另外微软架构电子书上还有推荐其他几本DDD的书籍,遗憾的是,JD和TB都没搜到。

 

在团队刚开始分析领域模型时,对所有相关者都是一个极大的挑战,我这里分享几点经验帮助团队更好地度过这段时期:

不要想着能够一次提炼出完美的领域模型(除非团队中有着经验丰富的DDD实践者),通常来说,我们会在会议上决定一个粗略的模型,然后在开发过程中你会发现有一些不自然的地方,比如某些上下文频繁地与其他上文通信,或者某个实体的行为不是很恰当,这个时候再去修正领域模型,这样演进式的过程可以大大降低你们在初期的压力。

如果你的团队整体能力不足以支撑领域模型的推行,或者他们在初期的配合度不高时,你可以选择把你的项目中业务逻辑最为复杂的部分使用弱化的领域模型拆解,比如仅使用充血模型和领域服务,这样至少你可以对最为复杂的部分引入一些DDD战术模式或设计模式。

就算你的团队能力够了,但大部分人都没有DDD的经验的话,我也建议先只引入部分模式(比如只引入实体,值对象和仓储这类比较容易理解的模式)来提高团队的敏感度之后再采用完整的领域模型。

领域模型会对查询带来一定的复杂性,这种时候你可以采用CQRS来分离Query和Command,只有在Cammand的时候你才需要发挥领域模型的威力,至于Query,SQL语句显然是更好选择。

 

基础架构

了解DDD的同学都应该知道,DDD当中最为重要的部分就是限界上下文(BoundedContext),在领域模型中我们区分好了上下文之后,下一步就是选择一种技术手段来确保每个上下都是低耦合高内聚且自治的。

在分布式应用中,多数设计者和包括微软架构的电子书都会推荐使用一个上下文对应一个微服务的方式来实现(确实微服务和上下文的设计需求不谋而合)。

但单体应用该怎么办呢?

有同学说,我们可以通过命名空间来隔离它们啊。

不错,我们可以这样做,但是有以下几个缺点

在使用IDE的智能引用时,你得确认你引用的实体究竟是位于当前上下文之内还是之外。

会导致你的项目结构层次过深,不便于查看。(至于过深的标准是多少,看个人了,对于我来说,5层是可以接受的上限,理想是控制在4层以内)

不便于向微服务架构迁移

所以我们选择了使用程序集(java是使用jar包)的方式来隔离每个上下文,这样做克服了以上的缺点,但却带来了新的问题:动态加载这些上下文。

不过这种程度的问题比起带来的收益几乎可以忽视。

我们团队使用一个基础平台来动态加载这些上下文,

我们采用了 Abp 框架提供的插件功能来实现,如果你也是.net 的使用者,也可以采用 Abp 来构建这个应用。

当然自己写一个动态加载功能也并不困难。

基础架构如下图所示:

在单体应用的一些DDD实践经验

 

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wspxwy.html