如何结合严格的TDD和DDD?


15

TDD是关于在测试的指导下设计代码的。
因此,通常不预先构建典型的层。它们应该在重构步骤中稍微出现。

域驱动的设计涉及许多技术模式,它们定义了完善的层,如应用程序层,基础结构层,域层,持久性层。

要从头开始DDD项目的编码部分,应如何操作?
我是否应该严格让设计从测试中脱颖而出,这意味着没有关注点分离(没有层次)和重构以适合DDD技术模式?

还是应该创建那些空层(应用程序,实体/域服务,基础结构),并让TDD独立地适合每个层(使用模拟在层之间进行隔离)?


Answers:


12

确保您查看Bob叔叔最近有关TDD设计角色的评论。

域驱动的设计涉及许多技术模式,它们定义了完善的层,如应用程序层,基础结构层,域层,持久性层。

乌迪·达汉(Udi Dahan):“上帝,我讨厌分层。” 他在演讲CQRS中花了一些时间讨论它-但与众不同(分层开始于18m30s)

我的句子拼写会略有不同;“ DDD认识到大多数业务应用程序存在许多共同的关注点,并且这些关注点的解决方案具有不同的生存期”

例如,通常,域关注点需要灵活-特别是在为特定业务定制解决方案时。毕竟,领域关系到公司如何开展业务,也就是说,公司如何赚钱以及能够快速提供业务改进就是免费收入。

另一方面,您可能不需要经常更改持久性组件。在上一发行版中有效的数据库解决方案也可能在此发行版中起作用。

应用程序关注点在中间。它们趋于稳定,因此用户不需要每次发布时都学习新的应用。

同样,可以有多种实现方式来解决任何给定的问题。例如,应用程序可能只需要其当前状态的快照-只需将文件保存到磁盘即可。在最初的几次迭代中,这也可能是所有域需求。但是最终出现了一个需要临时查询支持的故事,并且您认识到配置关系数据库比从头开始实现要容易得多。然后有一个功能可以在图形数据库中更好地工作。

同时,CTO希望在手机上运行该应用程序的版本。CEO刚从一个家伙那里听说,发布API是一件大事。

此外,销售团队使用不同的模型,因此请给我们相同的应用程序,并使用不同的模型。哦,但是我们经常旅行,所以我们的版本需要在离线时工作,以后再同步...

换句话说,您不是通过实现空的占位符并假设它们将在以后填充来应用来自的战术模式,而是通过识别何时穿越流 “来了,这就是我的域模型中的持久性代码,完成了重构。”


11

测试驱动开发(TDD)不是设计。这是影响您设计的要求。就像您需要保持线程安全一样,这不是设计。同样,这是影响您设计的要求。

如果您不顾一切地忽略所有其他设计问题,并且虔诚地遵守TDD规则,则当代码变成废话时,不要怪TTD。这将是可测试的废话,但这将是废话。

关于可测试废话的一件好事是它是可重构废话,因此对于某些人来说已经足够好了。我们只会在需要时才会花哨。其他人对此表示讨厌,并指责TDD。不,这是你的工作。

域驱动设计(DDD)是在TDD的红绿色重构周期之前执行的操作。

DDD是在代码中创建和保留空间的工作,在很大程度上,领域专家完全不了解系统的细节,因此他们可以了解如何控制系统。这是通过以熟悉的方式对问题域进行抽象和建模来完成的。

DDD系统可以具有如下所示的体系结构:

在此处输入图片说明

这DDD架构的推移很多名字: 清洁洋葱六角形

这是我看到许多人在查看此设计时遇到的脱节之处。这不是具体的。我可以遵循这种设计,并且从未写过任何您在此处看到的图表。我看到其他人坚持认为必须有一个用例对象或实体类。这些是一组规则,告诉您可以与谁交谈以及如何交谈。

而已。遵循此设计规则,您可以尽心尽力。TDD不在乎您与谁交谈。它关心的是只要单击一个按钮,就可以证明所有做某事的一切都能正常工作。没有,某处有东西坏了。它准确地告诉您发生了什么。

还是要模糊?看Controler- Use Case Interactor- Presenter图中右下角。这是三个相互交流的具体事物。确定这是DDD,但是如何在此处添加TDD?只是嘲笑具体的东西。演示者必须正在接收信息。一PresenterMock类是检查它让你期望它得到什么好办法。到手Use Case InteractorPresenterMock并驱动Use Case Interactor,如果你是在Controller和你有一个很好的方式,单元测试Use Case Interactor,因为模拟会告诉你,如果它让你期望它得到了什么。

好吧,看看。TDD感到满意,我们不必为DDD设计感到烦恼。那是怎么发生的?我们从良好的解耦设计开始。

如果使用TDD来驱动设计(不仅仅是d才有发展),你反映你把它的努力的设计。如果那是您想要的很好。但这绝不是TDD的目的。什么这最终缺乏肯定不是TDD的错。

TDD与设计无关。如果您必须进行设计更改以使用TDD,则比测试要面临更大的问题。


我从来没有说过TDD是设计,但它是关于设计的。
Mik378 '16

1
鲍伯叔叔告诉你设计。他不是在告诉您“嘿,如果您正在测试工作,谁会关心其余的事情”。
candied_orange

1
正如我已经说过的,请遵循允许您与谁交谈的规则。干净的架构并不是BDUF争论的话题。只需确定您所处的位置,然后考虑应该与谁和如何进行沟通即可。它比您想象的要敏捷。之后,询问是否可以通过TDD进行测试。如果不是,那您做错了什么。如果可以的话,我希望您能引起注意,因为好的设计不仅仅是可测试的。
candied_orange

6
......我真的受不了“测试驱动设计”的误称。无论您是否编写测试,都必须先进行一些设计,然后才能开始愉快地敲击键盘。
RubberDuck

1
在这点上引用Bob叔叔的话:“您必须设计时期”。单击此处,如果您太急躁而无法阅读全文,请搜索这些单词。您会发现Martin先生非常坚信TDD并不是万灵药,如果您不想生活在非常脆弱的代码库中,则不仅必须设计代码,还必须设计测试。
candied_orange

4

TDD确保您的代码具有与开发并行编写的所有必要测试用例。这不应影响高级设计。在战in工作中考虑更多。

DDD涉及高级设计,领域专家与工程师之间的语言,上下文映射等。这应该是应用程序高级设计的驱动力。

这些都是对两种功能强大的编程方法的简要说明。但是最终,他们确实完成了两项截然不同的事情。

从DDD语言和上下文映射开始,然后最终在您去编写代码时,开始TDD的实践。但是,TDD的实践不应影响高级设计,但应确保可以进行测试。这里有一些警告。

我认为可能要注意一点:如果应用程序足够复杂,则仅应练习DDD。


1
我不同意,TDD不是关于测试,而是关于设计。
Mik378 '16

我将一切都基于Bob叔叔描述的TDD的3条规则。
马特·瓦哈卡

GOOS书的作者Steve Freeman说:开始TDD周期之前,您不应该指定任何层或基础结构。
Mik378 '16

我不熟悉那本书,但我不得不不同意。我不想让TDD塑造我的DI和类图。
马特·瓦哈卡

3
@ Mik378:TDD与测试无关,但也不主要与设计有关-TDD引发的唯一设计是单元可测试性设计。设计的所有其他部分都必须来自其他地方。我将TDD视为一种实现技术。
布朗

3

DDD与软件设计有关。
TDD与代码设计有关。

在DDD中,“模型”代表领域的抽象,这是领域专家的所有知识。

我们可以将TDD用于代码初始软件设计模型。域具有业务规则和域模型,编写的测试(第一次)应为绿色。

实际上,在设计域驱动模型之后,我们可以对测试进行编码。
本书“通过测试引导增长的面向对象软件” 以购买链接的
方式购买,采用了行走骨架六角形体系结构和TDD。

来源:DDD快速-InfoQ


1
对我来说,软件和代码是同一回事
Konrad,

1
也可能是相同的。我试图说:软件是“解决方案”,“系统”,“高级”,而代码则是“实现”,“低级”,“细节”。
JonyLoscal

我认为重要的是“首先我们要测试,但是我们需要一个最小的框架来开始测试”。你呢?
JonyLoscal

1

我应该严格让设计从测试中产生吗

否。(域驱动)按定义设计应该来自领域要求。让其他任何东西来驱动您的设计都是一个坏主意,无论是测试套件,数据库架构还是...(待续)

还是我应该创建那些空层(应用程序,实体/域服务,基础架构),并让TDD独立地适合于它们中的每一个

(续)...或您最喜欢的OO语言选择的类/类层次结构的某些规范层,即使它是一种非常成熟和流行的语言(毕竟“成千上万的苍蝇也不会错”,对吗?) 。

当涉及DDD时,OOP缺乏以人类可读的形式表达要求的条件,即,对于非程序员来说,或多或少是清楚的。严格键入的FP语言可以做得更好。我建议读一本关于使用功能编程的DDD的书,作者是Scott Wlaschin的“ Domain Modeling Made Functional”

https://pragprog.com/book/swdddf/domain-modeling-made-functional

您不必使用FP语言从那里借用一些想法(不幸的是,并非所有想法都可以),但是如果您实际阅读它,那么您可能会想要使用功能性语言。

它还会回答您有关TDD如何适合DDD图片的问题。简而言之,当需求以功能样式编码时,它消除了对大量单元测试的需求,因为它使大多数无效状态和场景无法表示/无法编译。当然,FP项目中仍有自动测试的地方,但是测试绝不会驱动任何重大的设计决策。

要绕一个完整的圈子,让我们回到标题问题,即“如何结合严格的TDD和DDD?”。答案很简单:没有什么可以结合的/没有利益冲突。根据需求进行设计,根据设计进行开发(如果您确实想进行TDD,请首先编写测试)


FP DDD书籍和整体说明为+1。
罗曼·苏西
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.