【问题标题】:Django and domain driven designDjango 和领域驱动设计
【发布时间】:2017-02-04 07:11:52
【问题描述】:

我对领域驱动设计方法感到困惑。从网上的消息来源,我了解到这是将Domain ObjectsDatabase Objects 分开的方式,但我不明白两者之间的区别。

我们以 django 教程中 Polls 示例的code 为例,有两个模型PollsChoice

这些是domain level objects 还是database level objects

是否需要带有 ORM 的 DDD?

如果是,您能否提供一个需要使用带有 ORM 的 DDD 方法的好情况

例如,这是模型

class Polls(models.Model):
    question = models.CharField(max_length=200)
    pub_date = models.DateTimeField('date published')

我见过有人写的DDD方法代码

class PollService(object):
    def __init__(self, poll_repository):
        self.poll_respository = poll_respository

    def update(self, poll_id):
        poll = self.poll_respository.fetch_by_id(poll_id)
        poll.question += '?'
        self.poll_respository.update(poll)

#assume that the following code works?
class PollRepository():

    def __init__(self, db):
        self.db = db

    def update(self, poll):
        try:
            self.db.session().add(poll)
            self.db.session.commit()
        except Exception:
            self.db.session.rollback()

这是正确的方法吗?我在这里看到很多冗余代码,但人们说Polls 是域级别的对象,它不应该直接与数据库对话?

DDD 是否总是带有 DDD 存储库?如果我们有 ORM,为什么我们需要一个 DDD 存储库

另一种方法

views.py
def update_poll(poll_id):
    poll = models.Polls.objects.get(poll_id)
    poll.question += '?'
    poll.save()

这种方法有什么问题?

【问题讨论】:

  • “DDD 是否总是带有 DDD 存储库?” - 不。您可以将 CQRS 与事件溯源一起使用
  • 查看github.com/dry-python 项目。它提供了一组工具来轻松地为您的域建模!

标签: python django domain-driven-design ddd-repositories


【解决方案1】:

活动记录模式

Django 专为使用 Active Record Pattern 而量身定制,如此 Django Design Philosophy 页面所述。

您的第二个示例遵循此模式 - 模型本身包含其属性、行为和数据访问。

如果您将更多行为推送到模型上,您仍然可以以更类似于 DDD 的方式使用此模式。例如在您的示例中,更有效地使用该模式是换行

poll.question += '?'

在 poll 对象上的意图揭示方法中,update_poll 方法为:

views.py
def update_poll(poll_id):
    poll = models.Polls.objects.get(poll_id)
    poll.add_question()
    poll.save()

这具有将业务逻辑(推入模型)与应用程序流逻辑(update_poll 方法)分离的优点

虽然我建议使用一个实际说明方法意图或目的的名称,而不仅仅是 add_question。

但即使你这样做了,你仍然在使用 Active Record 模式,而不是纯粹的 DDD。

您问“是否需要带有 ORM 的 DDD?”

DDD 和 ORM 正在尝试解决不同的问题。 ORM 提供了一种方便的方法,以更面向对象的方式抽象出面向集合的面向记录的数据库世界。

DDD 是一种帮助在代码中对复杂的现实世界情况进行建模的方法。

许多 DDD 系统使用 ORM 来解决从数据库中检索和持久化的基础架构问题(有时出于各种原因将 ORM 包装在存储库中),但 DDD 的重点是领域模型以及它们如何适合建模正在考虑的域。

所以 - 在您的示例中,很难看到 DDD 的好处,因为业务逻辑相对简单。

我建议阅读 DDD 上的权威来源 - Domain Driven Design by Eric Evans,以了解与语言无关的方法及其增值情况的概述。

更新

你问:

你能告诉我一个很好的例子,说明在 ORM 中使用 DDD 是有意义的

如果我们使用 ORM,我认为不需要 DDD 存储库

我认为更好的思考方式是 - 当使用 ORM 时,ORM 存储库。你向它索要一个模型,它返回一个模型。这就是存储库的目的。当人们将它包装在一个名为“repository”的类中时,通常是因为他们想做以下几件事之一:

  1. 更容易注入模拟存储库以简化单元测试
  2. 抽象特定 orm 技术,用于灵活地在以后更改 ORM 而无需触及服务或域

overview of the repository pattern 提供了另一个关于 ddd 存储库模式的好文章。

【讨论】:

  • 谢谢克里斯。你能告诉我一个很好的例子,说明使用 DDD 和 ORM 是有意义的吗?
  • 请注意,DDD 中的“模型”是“域模型”,它由实体、值对象、服务、存储库、聚合、聚合根以及表示相关域所需的任何其他内容组成。 django模型中的模型,是实体。也就是说,在 DDD 中,model 是领域的模型。
  • 来自 Fowler 的 PoEAA 书中:“Active Record 是不太复杂的域逻辑的不错选择 [CRUD]。[...] 如果您的业务逻辑很复杂,您很快就会想要使用对象的直接关系、集合、继承等。这些不容易映射到 Active Record 上,并且零碎地添加它们会变得非常混乱。[...] 反对 Active Record 的另一个论点是它结合了从对象设计到数据库设计。随着项目的推进,这使得重构任一设计变得更加困难。”
  • 如果你认真对待 DDD,那么 Django 模型不是实体,ORM 也不是存储库。存储库只是一个普通的 python 类,它提供了一个接口来查询域数据。 ORM 是一个不属于领域模型的实现细节。存储库可以使用它与数据库进行通信,但它不能是同一件事。遵循活动记录模式的模型也是如此。它们不能被视为一个实体。
  • @trixn 我同意,但是存储库必须与底层存储层通信,在这种情况下是 Django ORM,必须妥协才能利用两者。 Django 的实体定义是不鼓励发生的紧密耦合,如果在 xml/yaml 之类的配置文件中发生相同的字段映射,则应该解决这种情况,但那有可能吗?建议同时拥有什么?
【解决方案2】:

Paul Hallett 在他美丽而完整的文章中将这一切放在一起:https://phalt.github.io/post/django-api-domains

这里的例子:https://github.com/phalt/django-api-domains

简而言之:

Django 的风格指南很旧

文档,从教程到完整文档,都谈到了一个 模型-视图-控制器世界,Django 在其中呈现 HTML 并交付 它到网络浏览器。

这件事让我觉得很奇怪——我曾与 Django 合作过 自 2012 年以来,我只记得使用它渲染 HTML 一次。几乎 我和 Django 在一起的所有时间,而且我一直看到 Django 在会议上谈到的一直是提供一个 API(通常与 Django REST Framework)到前端项目。我认为这 实际上是当今 Django 的事实标准。文档 对于当前流行的用例来说已经过时了。这一般是一个 我在 Django 中看到的趋势 - 该项目正在尝试现代化 它正在运行,甚至如何正确处理异步。也许是时候了 Django 重新考虑了它为开发人员建议的设计模式 也是?

回到我眼前的问题:为了帮助团队组织他们的 软件更好,我开始从 社区。我读到了域驱动辞职,有界的好处 上下文,我发现了一个很好的 Hacksoft 风格指南,我们试图 采用。这太棒了!这里的文档非常完善,并且 非常适合小型项目或小型公司。

但在我们对它进行实验的过程中,我们发现它不适合 目的有几个原因。即,鼓励的事实 存在于模型中的业务逻辑。 Django 也推荐这个和 它基本上是活动记录模式。根据我们的经验,非常 大型团队,鼓励将业务逻辑与模型联系起来 开发人员用大量代码填充 models.py。这使它 开发人员很难同时处理一个文件。不 提到一个事实,当一个文件拥有多个问题时 一个域(演示文稿、数据、控制器等)它往往会吸引所有 文件中还有其他问题。

【讨论】:

  • 您知道您可以将文件夹用于包含多个文件的模型,对吧?您甚至可以为每个文件创建一个模型,就像 java 一样。
【解决方案3】:

如果您需要一些有关 DDD 和 Django 的示例,那么使用干 Python 工具的 https://dry-python.org/static/slides/ddd-toolkit-2.html 幻灯片可能会很有用。

另外,查看示例项目https://github.com/dry-python/tutorials/tree/master/django/example

【讨论】:

    猜你喜欢
    • 2016-09-29
    • 2011-10-06
    • 2011-06-21
    • 2016-07-18
    • 2013-09-16
    • 1970-01-01
    • 1970-01-01
    • 2015-03-30
    相关资源
    最近更新 更多