【问题标题】:Service Oriented Architecture & Domain-Driven Design面向服务的架构和领域驱动设计
【发布时间】:2011-01-28 21:00:33
【问题描述】:

我一直以 SOA 类型的方式开发代码。今年我一直在尝试做更多的 DDD,但我一直觉得我没有得到它。在工作中,我们的系统是负载平衡的,并且设计为没有状态。架构是:

网站

===物理层==

主要服务

==物理层==

服务器 1/服务 2/服务 3/服务 4

只有服务器 1、服务 2、服务 3 和服务 4 可以与数据库通信,主服务根据订购的产品调用正确的服务。每个物理层也是负载均衡的。

现在,当我开发一项新服务时,我会尝试在该服务中考虑 DDD,即使它并不真正适合它。

我使用良好的 DDD 原则,例如实体、值类型、存储库、聚合、工厂等。

我什至尝试过使用 ORM,但它们似乎不适合无状态架构。我知道有一些方法可以解决它,例如使用 IStatelessSession 而不是 ISession 和 NHibernate。然而,ORM 只是觉得它们不适合无状态架构。

我注意到我实际上只使用了 DDD 教给我的一些概念和模式,但整体架构仍然是 SOA。

我开始认为 DDD 不适合大型系统,但我确实认为某些模式和概念确实适合大型系统。

就像我说的,也许我只是没有掌握 DDD,或者我过度分析了我的设计?也许通过使用 DDD 教给我的模式和概念,我正在使用 DDD?不确定这篇文章是否真的存在问题,但我在试图弄清楚 DDD 在整个系统中的位置以及它的真正可扩展性时产生了更多想法。事实是,我认为我什至不知道 DDD 是什么?

【问题讨论】:

    标签: domain-driven-design design-patterns soa


    【解决方案1】:

    我真的很晚了,但我想在其他人的非常好的答案中添加以下内容。

    • DDD 与 SOA 没有任何冲突。相反,DDD 可以帮助您维护更好的面向服务的架构。 SOA 促进了服务的概念,以便您可以在系统之间定义更好的边界(哦,上下文边界也是 DDD 概念!)并提高对它们的理解。
    • DDD 不是应用一组模式(例如存储库、实体等)。 DDD 主要是尝试为您的软件建模,以便所有概念(即面向对象编程中的类)直接与业务概念保持一致。

    您还应该查看this video(尤其是最后 5 分钟),Eric Evans 正是在此讨论了这个话题。


    我什至尝试过使用 ORM,但它们似乎不适合 无状态架构。

    我没有任何方便的参考资料来支持这一点。但是,您是对的,ORM 也不适合 DDD。这是因为,他们试图以错误的方式桥接object-relational impedance mismatch。他们强制软件使用anemic domain model,类最终成为“普通数据持有者”。

    我开始认为 DDD 不适合大型系统,但我确实认为 一些模式和概念确实适合大型系统。

    在我上面链接的视频中,您还可以看到 Eric 解释说 DDD 概念可以在超大规模系统中“破坏”。例如,想象一个零售系统,其中每个订单都是可能包含数千个订单项目的聚合。如果您想严格按照 DDD 计算订单的总金额,则必须将所有订单项加载到内存中,这与利用存储系统(例如使用巧妙的 SQL 语句)相比效率极低。因此,应始终牢记这种权衡,DDD 不是灵丹妙药。

    就像我说的,也许我只是没有掌握 DDD,或者我已经结束了 分析我的设计?

    对不起,我得再引用 Eric Evans 的话。正如他所说,DDD 不适合完美主义者,这意味着可能存在不存在理想设计的情况,您可能必须采用解决方案,这在建模方面更糟糕。要了解更多信息,您可以查看this article

    【讨论】:

      【解决方案2】:

      关于领域驱动设计最重要的事情是大局观:

      • 无处不在的语言,
      • 通过在核心领域工作(并将自己与其他讨厌的系统隔离开)来增加价值的战略决策,以及
      • 通过将基础架构与业务逻辑分离来进行可测试的灵活设计的方法。

      这些应用广泛,是最有价值的部分。

      有很多关于工厂、服务、存储库、聚合等设计模式的东西,我认为这是一位经验丰富的开发人员对另一位开发人员的建议,而不是信条,因为其中很多内容可能会因您正在使用的语言和框架。恕我直言,他们往往被过分强调,因为像我们这样的程序员是注重细节的,我们痴迷于那种东西。那里也有有价值的东西,但需要保持透视。因此,其中一些可能与您无关,或者在您使用它时可能会在您身上成长。

      所以我想说,这并不是说您可以通过检查清单来确保您使用了所有模式,而是要牢记大局,看看这会如何改变您开发软件的方法。如果您从模式中获得一些好的技巧,那也很棒。

      特别是关于 SOA 的事情,我开发了将所有状态都交给数据库的应用程序,这些应用程序使用了对持久性无知的域对象。为必须模拟 daos 和反馈内容的服务编写测试是件苦差事,我可以在域对象中放入的逻辑越多,我就越少在服务中弄乱模拟,所以我更喜欢这种方法。

      【讨论】:

        【解决方案3】:

        在构建 SOA 时,DDD 引入了一些概念,实际上可能会让您感到困惑。

        我必须完全同意another answer,即 SOA 服务公开充当原子命令的操作。我相信一个非常干净的 SOA 使用消息而不是实体。然后服务实现将利用领域模型来实际执行操作。

        但是,DDD 中有一个概念,称为“域服务”。这与应用程序服务略有不同。通常,“域服务”与域模型的其余部分使用相同的通用语言设计,并表示不完全适合实体或值的业务逻辑。

        不应将域服务与应用程序服务混淆。事实上,应用服务可以很好地实现为使用域服务。毕竟,应用服务可以将领域模型完全封装在 SOA 中。

        【讨论】:

          【解决方案4】:

          我认为一个常见的误解是 SOA 和 DDD 是两种相互冲突的风格。

          IMO,它们是两个完美结合的概念; 您创建一个领域模型来封装您的领域概念,并通过服务公开该模型的入口点。

          我也看不出 ORM 和服务有什么问题,您可以轻松地在每个服务调用中使用会话/uow。 只需将您的服务操作建模为原子域命令。

          一个天真的例子:

          [WebMethod]
          void RenameCustomer(int customerId,string newName)
          {
              using(var uow = UoW.Begin())
              {
                  var customerRepo = new CustomerRepo(uow);
                  var customer = customerRepo.FindById(customerId);
                  customer.Rename(newName);
                  uow.Commit();
              }
          }
          

          也许您面临的问题是您创建了像“UpdateOrder”这样的服务,它接受一个订单实体并尝试在新会话中更新它?

          我尽量避免使用这种服务,而是将它们分解为更小的原子命令。

          每个命令都可以作为一个操作公开,或者您可以有一个单独的服务操作来接收命令组,然后将这些命令委托给命令处理程序。

          IMO,这样你可以更好地暴露你的意图。

          【讨论】:

          • 我终于发了一些关于这个的帖子:服务 + 命令模式 + DDD rogeralsing.com/2013/12/02/…
          • 还有一些信息为什么旧的 DTO 方法不好rogeralsing.com/2013/12/01/…
          • 当您在示例Service.RenameCustomer(ID, Name)Customer.Rename(Name) 中有两种相同的方法来应用相同的业务逻辑时,它们如何协同工作?在更复杂的情况下,即使这 2 个复制方法也将具有 2 个不同类的参数,例如 NameDTOName
          最近更新 更多