DDD与N层(3层)架构的比较

12
我已经练习DDD有一段时间了,使用四个不同的层:领域、表示、应用和基础设施。最近,我向我的一个朋友介绍了DDD概念,他认为它引入了不必要的复杂性(特别是针对接口和IoC)。通常在这种情况下,我会解释DDD的好处,尤其是它的模块化。所有繁重的工作和底层操作都在基础设施中处理,如果我想完全更改底层数据访问方法,只需要触及基础设施层存储库。

我朋友的论点是,他可以以相同的方式构建三层应用:

  • 业务
  • 数据
  • 表示
他将创建业务模型(如领域模型),并使数据层中的存储库返回这些业务模型。然后,他将调用业务层,再由业务层调用数据层。我告诉他,这种方法的问题在于它不能进行可测试性的单元测试,虽然可以编写集成测试,但不能编写真正的单元测试。您是否能看出他提出的三层方法有其他问题(我知道有,否则为什么DDD存在呢)。

编辑:他没有使用IoC。他的示例中每一层都依赖于另一层。


6
领域驱动设计和分层架构似乎与你的争议无关(而且据我理解,它们彼此独立)。如果你去掉缩写词,你们真正的分歧是什么?是编写接口和依赖注入吗? - Jeff Sternal
编辑:他没有使用IoC。他的示例中每个层都依赖于另一个层。仍然可以使用Mockito进行测试。因此,这不是二选一的问题。更多关于一个人或一组人认为哪种代码更清晰、设计更好、更易于维护(作为比较水平,而不是其他可能完全无法维护的代码)。 - tgkprog
4个回答

16

我认为你在做不可比较的事情。N-Tier并不妨碍它利用接口和依赖注入进行轻松的单元测试。同样,静态类和硬依赖关系也可以实现DDD。

此外,如果他正在实现业务对象并使用存储库,则听起来像他正在执行DDD,而你只是在争论语义问题。

你确定问题不仅仅是关于是否使用DI/IoC吗?


不使用IoC,如何轻松地进行单元测试?他可以进行集成测试,但是如果没有接口/IoC/DI,你将如何进行单元测试呢? - Josh Barker
3
我想说的是DDD或N-Tier并不意味着有或没有IoC。你似乎试图将问题集中在DDD与N-Tier之间的比较上,但实际上你的问题似乎是在问IoC/DI和无IoC/DI的区别。我支持使用IoC/DI,尽管我认为DDD或N-Tier并不重要,因为它们都可以使用或不使用DI/IoC进行开发。 - quentin-starin

11
我觉得您把几种方法论混淆了。DDD是面向领域驱动开发,旨在使业务领域成为代码的一部分。您所描述的更像洋葱架构(链接),而不是“普通”的三层方法。使用三层架构和DDD并没有什么问题。DDD依赖于TDD(测试驱动开发)。接口有助于TDD,因为可以更容易地独立测试每个类。如果使用依赖注入(DI)和控制反转(IoC),则进一步减轻了这种依赖关系。
洋葱架构的思想是使域层(也称为业务规则)与其他所有内容独立 - 即它是应用程序的核心,所有内容都依赖于业务对象和规则,而与基础设施、UI等相关的内容则在外层。这样做的意义在于,模块离“洋葱壳”越近,替换新实现就越容易。
希望这能稍微澄清一下 - 现在进行了一些小修改!

嗯...我非常熟悉Jeff Palermo的洋葱架构,因为我的项目中有这些不同的层,并且我是基于他的博客文章构建的。然而,在DDD项目中,所有这些层也存在(例如:领域、应用、展示和基础设施)。 - Josh Barker
我的观点是,虽然许多人使用联合结构体也使用DDD,但它不是DDD的前提条件。 - Goblin
进一步阐述一下,为了练习DDD(领域驱动设计),您并不需要特定的层集合,也不需要以特定的方式结构化。但是,您编写的所有内容都应该模拟您所针对的领域,包括商业对象具有与其真实同名的名称。 - Goblin
本身它不是反模式,但我同意使用洋葱结构可以使耦合更松散,因为业务层不依赖于基础设施层。我更喜欢洋葱而不是传统的三层模型。但我仍然相信如果您不相信交换ORM,完全可以使用三层架构:请参阅此链接以了解原因:http://ayende.com/Blog/archive/2010/07/30/the-false-myth-of-encapsulating-data-access-in-the-dal.aspx - Goblin
我开始理解你的想法了...如果你编辑你的答案,我可以改变我的投票。 - Josh Barker
显示剩余2条评论

1
阅读《软件架构基础:工程方法》第8章100页到107页。
顶层划分对架构师特别重要,因为它定义了基本的架构风格和代码划分方式。这是架构师必须做出的首个决策之一。这两种风格(DDD和分层)代表了不同的顶层架构划分方式。因此,你并非在比较不可比较的东西。
使用技术划分的架构师通过技术能力来组织系统的组件:展示、业务规则、持久性等等。
域划分受Eric Evan的《领域驱动设计》一书的启发,这是一种用于分解复杂软件系统的建模技术。在DDD中,架构师识别出相互独立且解耦的域或工作流程。
领域划分(DDD)可能使用持久库,并具有单独的业务规则层,但顶层划分围绕着域展开。域划分中的每个组件可能具有子组件,包括层,但顶层划分侧重于域,这更好地反映了项目中最常发生的变化类型。
因此,你可以在DDD的每个组件上实现层(你的朋友正在做相反的事情,这很有趣,我们也可以尝试一下)。
但是,请注意(《软件架构基础:工程方法》,第135页):
分层架构是一个技术划分的架构(而不是域划分的架构)。组件群组不是按域(如客户)分组,而是按其在架构中的技术角色(如展示或业务)进行分组。因此,任何特定的业务域都分布在架构的所有层中。例如,“客户”领域包含在展示层、业务层、规则层、服务层和数据库层中,使得对该域应用变更变得困难。因此,面向领域驱动设计的方法与分层架构样式结合效果不佳。
架构中的所有内容都是权衡取舍,这就是为什么宇宙中每个架构问题的著名答案都是“取决于”。话虽如此,你的朋友的方法的缺点是,在数据级别上具有更高的耦合性。此外,如果架构师之后想将该架构迁移到分布式系统(例如微服务),那么它将会导致解开数据关系方面的困难。

0

N层或3层架构在单元测试方面表现出色。 您需要做的就是使用依赖注入和存储库模式进行IoC(控制反转)。

业务层可以验证并为展示/ Web API层准备返回数据,通过返回所需的确切数据。 然后,您可以在整个层中使用虚拟对象来进行单元测试。 所有业务逻辑和需求都可以在bl层上处理,而Dal层将包含从更高级别注入的存储库。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接