领域驱动设计可以用例驱动吗?

Can domain-driven design be use-case driven?

也许这个问题是矛盾的,但是在 DDD 中从用例开始开发,然后开发将支持这些服务的域模型是否正确?

如果设计是由领域驱动的(如DDD所说),则假设您首先开发领域模型(通过了解问题领域并使用通用语言),然后再开发应用层(用例)将使用域。

然而,在 DDD 中,您似乎首先从用例(或用户故事)开始,然后开发领域模型。

正如名称 domain-driven design 所暗示的那样, 位于中心。所以你先对域建模。

因此,您需要与领域专家交谈,并且您需要为您 interdisciplinary team 中的每个人建立对该领域的良好理解。其中一部分是找到/创建无处不在的语言,确保每个人都用相同的词表达相同的意思,因此您的目标是消除基于不明确术语的冗余和误解.

我写了一个关于 DDD and co., which may be of interest to you. Also, I have written this blog post at the Auth0 blog, which describes how to model and build a software from scratch using DDD, event-sourcing and CQRS, and wolkenkit 的博客 post 系列,open-source CQRS 和 event-sourcing 框架用于 JavaScript 和 Node.js。

一旦你有了领域模型和你的通用语言,你就可以开始定义用户故事了。实际上,一旦您对域进行建模,这是一项非常简单的任务。

If the design is driven by the domain (as DDD says), it is supposed that you develop the domain model first (by understanding the problem domain and using the Ubiquitous Language), and then you develop the application layer (use cases) that will use the domain.

However it seems that in DDD you start from the use cases (or user stories) first and then you develop the domain model.

这些说法都不准确。 DDD 的 -driven 部分并不意味着系统实现中的特定顺序。它只是说整个设计和编码工作应该主要围绕域及其语言。

您同样可以选择先实现应用层作为先实现领域层。无论如何,在开始实施之前,需要有一个域的逻辑模型。用例与领域模型使用相同的语言——如果没有至少一种 well-defined 普遍存在的语言和领域的草图模型,开发应用层是没有意义的。

根据我的经验,我建议从用例(应用层)开始实施。这里有一些原因:

  • 用户故事以用例的形式出现:"register an user"、"place an order",等等。所以对我来说,从那里开始编码更自然。
  • 由于用例的输出是 returning/publishing 来自域的一些事件的状态转换,我使用它们首先创建测试如下:

given(new User("an id", "inactive_email@example.com"))
.when(new ActivateUserEmailCommand(input))
.then(new EmailUserWasActivated())
  • 一旦我为我的用例可以通过的每个不同场景实施了测试,我什至可以将测试 class 传递给另一个人(也许是经验较少的人)并让他实施它,因为大部分 UL 已经在测试本身中定义。

  • 我看到的一个好处是您只需实施最少量的代码即可使您的用例正常工作。通过这种方式,您可以避免提前确定聚合根需要哪些属性,而只需关注特定用例所需的属性。

  • 通过只实现用例(以及测试和域),你的 PR 将更容易被审查,因为审查者只看到使用了什么,他们不应该找到 attributes/parameters 尚未使用,因为他们将更难理解添加它们的原因。

DDD 并不意味着任何 "order" 在实现中。
但是,它在理解领域方面付出了很多努力,并尽可能地使其成为最明确
根据项目的不同,可能需要几个月的时间才能很好地理解该领域,我认为软件应该随着团队对该领域的了解而发展。

所以,我认为你应该从用例开始(以非常敏捷的心情),编写测试,implement/evolve领域,完成用例,制作测试通过,确保一切正常,然后继续下一个用例。

因此,您的应用程序中的领域层会不断发展,并且随着您获得更多关于领域的知识,将随着新概念和对领域的理解而得到完善。

更新
这种方法的困难部分是保持用例的快速开发,以便轻松重构模型。要做到这一点,所有干净的代码、设计模式和发现的所有技巧都会对 "good" 代码有所帮助。
很难重构的可能是持久化数据。对持久数据进行数据结构重构可能会非常痛苦,为此,事件溯源技术与 DDD 密切相关。
(以一种简单的方式)它以存储不可变数据结构为中心,而你的"domain model"只是这些数据的内存投影,这样你就可以重构你的模型而不必重构持久化数据。