Answers:
域驱动的设计涉及许多技术模式,它们定义了完善的层,如应用程序层,基础结构层,域层,持久性层。
乌迪·达汉(Udi Dahan):“上帝,我讨厌分层。” 他在演讲CQRS中花了一些时间讨论它-但与众不同(分层开始于18m30s)
我的句子拼写会略有不同;“ DDD认识到大多数业务应用程序存在许多共同的关注点,并且这些关注点的解决方案具有不同的生存期”。
例如,通常,域关注点需要灵活-特别是在为特定业务定制解决方案时。毕竟,领域关系到公司如何开展业务,也就是说,公司如何赚钱以及能够快速提供业务改进就是免费收入。
另一方面,您可能不需要经常更改持久性组件。在上一发行版中有效的数据库解决方案也可能在此发行版中起作用。
应用程序关注点在中间。它们趋于稳定,因此用户不需要每次发布时都学习新的应用。
同样,可以有多种实现方式来解决任何给定的问题。例如,应用程序可能只需要其当前状态的快照-只需将文件保存到磁盘即可。在最初的几次迭代中,这也可能是所有域需求。但是最终出现了一个需要临时查询支持的故事,并且您认识到配置关系数据库比从头开始实现要容易得多。然后有一个功能可以在图形数据库中更好地工作。
同时,CTO希望在手机上运行该应用程序的版本。CEO刚从一个家伙那里听说,发布API是一件大事。
此外,销售团队使用不同的模型,因此请给我们相同的应用程序,并使用不同的模型。哦,但是我们经常旅行,所以我们的版本需要在离线时工作,以后再同步...
换句话说,您不是通过实现空的占位符并假设它们将在以后填充来应用来自ddd的战术模式,而是通过识别何时穿越流 “来了,这就是我的域模型中的持久性代码,完成了重构。”
测试驱动开发(TDD)不是设计。这是影响您设计的要求。就像您需要保持线程安全一样,这不是设计。同样,这是影响您设计的要求。
如果您不顾一切地忽略所有其他设计问题,并且虔诚地遵守TDD规则,则当代码变成废话时,不要怪TTD。这将是可测试的废话,但这将是废话。
关于可测试废话的一件好事是它是可重构废话,因此对于某些人来说已经足够好了。我们只会在需要时才会花哨。其他人对此表示讨厌,并指责TDD。不,这是你的工作。
域驱动设计(DDD)是在TDD的红绿色重构周期之前执行的操作。
DDD是在代码中创建和保留空间的工作,在很大程度上,领域专家完全不了解系统的细节,因此他们可以了解如何控制系统。这是通过以熟悉的方式对问题域进行抽象和建模来完成的。
DDD系统可以具有如下所示的体系结构:
这是我看到许多人在查看此设计时遇到的脱节之处。这不是具体的。我可以遵循这种设计,并且从未写过任何您在此处看到的图表。我看到其他人坚持认为必须有一个用例对象或实体类。这些是一组规则,告诉您可以与谁交谈以及如何交谈。
而已。遵循此设计规则,您可以尽心尽力。TDD不在乎您与谁交谈。它关心的是只要单击一个按钮,就可以证明所有做某事的一切都能正常工作。没有,某处有东西坏了。它准确地告诉您发生了什么。
还是要模糊?看Controler
- Use Case Interactor
- Presenter
图中右下角。这是三个相互交流的具体事物。确定这是DDD,但是如何在此处添加TDD?只是嘲笑具体的东西。演示者必须正在接收信息。一PresenterMock
类是检查它让你期望它得到什么好办法。到手Use Case Interactor
的PresenterMock
并驱动Use Case Interactor
,如果你是在Controller
和你有一个很好的方式,单元测试Use Case Interactor
,因为模拟会告诉你,如果它让你期望它得到了什么。
好吧,看看。TDD感到满意,我们不必为DDD设计感到烦恼。那是怎么发生的?我们从良好的解耦设计开始。
如果使用TDD来驱动设计(不仅仅是d才有发展),你反映你把它的努力的设计。如果那是您想要的很好。但这绝不是TDD的目的。什么这最终缺乏肯定不是TDD的错。
TDD与设计无关。如果您必须进行设计更改以使用TDD,则比测试要面临更大的问题。
TDD确保您的代码具有与开发并行编写的所有必要测试用例。这不应影响高级设计。在战in工作中考虑更多。
DDD涉及高级设计,领域专家与工程师之间的语言,上下文映射等。这应该是应用程序高级设计的驱动力。
这些都是对两种功能强大的编程方法的简要说明。但是最终,他们确实完成了两项截然不同的事情。
从DDD语言和上下文映射开始,然后最终在您去编写代码时,开始TDD的实践。但是,TDD的实践不应影响高级设计,但应确保可以进行测试。这里有一些警告。
我认为可能要注意一点:如果应用程序足够复杂,则仅应练习DDD。
DDD与软件设计有关。
TDD与代码设计有关。
在DDD中,“模型”代表领域的抽象,这是领域专家的所有知识。
我们可以将TDD用于代码初始软件设计模型。域具有业务规则和域模型,编写的测试(第一次)应为绿色。
实际上,在设计域驱动模型之后,我们可以对测试进行编码。
本书“通过测试引导增长的面向对象软件” 以购买链接的
方式购买,采用了行走骨架,六角形体系结构和TDD。
来源:DDD快速-InfoQ
我应该严格让设计从测试中产生吗
否。(域驱动)按定义设计应该来自领域要求。让其他任何东西来驱动您的设计都是一个坏主意,无论是测试套件,数据库架构还是...(待续)
还是我应该创建那些空层(应用程序,实体/域服务,基础架构),并让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,请首先编写测试)