【问题标题】:Why are CRUD operations so bad in a SOA design?为什么在 SOA 设计中 CRUD 操作如此糟糕?
【发布时间】:2010-10-14 09:06:44
【问题描述】:

我刚刚读完MSDN by John Evdemon 上的一篇文章。他抨击 CRUD 接口并将其称为反模式。

虽然我同意任何有状态的东西都是困难的,并且 Current 和 MoveNext 是坏主意,但我不同意创建读取更新和删除中的 CRUD 是不好的。如果我有汽车服务,并且我想让客户能够做一些基本的事情,比如创建汽车、获取汽车详细信息、更新汽车详细信息或删除汽车,那么他们打算如何做这些事情没有 CRUD 操作。

或者我在这里错过了什么?

【问题讨论】:

  • 我想我必须阅读这篇文章才能得到答案:从什么时候开始将光标操作 (moveNext) 视为 CRUD 操作?

标签: design-patterns soa crud


【解决方案1】:

在分布式系统/SOA 场景中应该避免使用 CRUD 接口,因为它们非常健谈。但应该并不意味着必须。当您有一些需要多次调用您的服务的客户端操作时,您知道您应该放弃 CRUD 方法并创建新的服务操作,将这些调用聚合为单个调用。在设计分布式系统时,您应该始终将调用次数减少到最少,因为网络调用非常耗时。

编辑:

您可以将 CRUD 接口视为服务中公开的数据访问。有时你真的想要这个。但在 SOA 和分布式系统架构中,您通常会公开已经封装数据访问并提供更复杂操作(聚合许多数据访问操作)的业务功能。

示例:

CRUD x 业务逻辑接口。假设您正在使用Invoices。每张发票由一个InvoiceHeader 和一个或多个InvoiceLine 组成。如果您为发票使用 CRUD 接口,您将首先调用 CreateInvoiceHeader 操作来创建 InvoiceHeader,然后调用几个 AddInvoiceLine 操作来添加所有 InvoiceLines - 这是低级别的 CRUD 方法。但是,如果您在服务端实现业务逻辑,您将调用单个 CreateInvoice 并将复杂的对象图(包含所有行的标题)传递给服务以创建和添加所需的内容。 Create 方法还可以进行其他业务操作,例如启动一些工作流等。这是常见的 SOA 和分布式系统方法。

【讨论】:

  • 这让我有点困惑。如果我们不公开 CRUD 操作,我们如何让客户创建新实体或更新他们的详细信息。例如,只是一个接受汽车的简单 Create 方法。如果有问题,我们会将故障发回。如果你什么都没得到,那么它就成功了。在我看来,它不能少说话。就像我说的那样,我可能在这里遗漏了一些重要的东西。
  • @uriDium:我添加了一些示例。
  • 哦,对了。谢谢你的例子。因此,几乎“真实形式”的 CRUD 将所有内容都分解为基本的 Create Read Update 或 Delete 是一个坏主意,因为它会强制使用聊天服务。如果您可以将它们全部包装在一个服务方法中,例如 PlaceOrder(invoiceHeader, List) 会更好,因为它减少了聊天并更具商业意义。但显然仍然存在我们可能只需要创建单个对象的情况。我明白了吗?
  • @uriDium:是的。但这是一个简单的例子。您可以想象更复杂的情况,或者您可以找到另一个示例,例如 Update 将需要整个实体,但客户端将只发布简单的值,而服务的业务逻辑将负责设置其他值。
  • 这是一个十年前的帖子,但似乎仍然相关。在任何 RDBMS 的最基本级别上,您都有需要执行 CRUD 操作的表,并且手动构建 API 肯定会很乏味和麻烦,但是一些现代框架(如 .NET Core)通过逆向工程数据库实现了自动数据优先的脚手架,那么为什么不使用它,然后在数据库端,如果你想封装很多功能,比如添加一个用户帐户,你主要是在存储过程中这样做,然后对存储过程的调用脚手架?这使它更易于重复使用。
【解决方案2】:

最近越来越受欢迎的RESTfull web services 被证明是错误的 John Evdemon 先生的帖子。

【讨论】:

  • 我不这么认为,他说“开发人员在开发自己的架构之前应该参考现有的行业标准。”好吧,带有 CRUD 操作的 HTTP 是您与 RESTfull Web 服务一起使用的标准。恕我直言,这里的故事是,为 CRUD 操作定义自己的 CRUD 操作是没有意义的,因为已经发明了足够的解决方案。
【解决方案3】:

我认为他在这里故意设计了最糟糕的界面,它并不是真正的 CRUD 界面。

<WebMethod()> _
Public Function MoveNext() As Boolean
End Function

<WebMethod()> _
Public Function Current() As Object
End Function

这两种方法显然不是无状态的,但它们也不是真正的 CRUD 接口所必需的。我认为这只是一个写得很糟糕的例子,它与 CRUD 操作并没有真正的关系。

更新:

发现了一个类似的问题,很好answer :)

【讨论】:

    【解决方案4】:

    接受的答案不正确。尽管 John 使用 CRUD 作为反模式示例,但使用 CRUD 对 SOA 来说还不错。正如 John 所描述的,这就是 SOA 的问题:它鼓励增加服务级别的复杂性,最终导致对多个用例的支持减少。我们构建 API 的主要原因之一是提供对多个应用程序的访问,这是构建 API 的主要投资回报率。

    例如,假设我们有一个博客 API。假设我们让用户能够在我们的外部应用程序的一个屏幕上写帖子、添加图像和放置 cmets。在 John 的 SOA 愿景中,他可能会建议我们构建我们的 API 以使用一个调用来完成所有这些事情,这样就不会那么啰嗦了……所以:

    {
      "post_title": "New Post",
      "post_content": "Some Stuff....",
      "comments": [{
        "comment": "This is right on!",
        "userId": 101
      }, {
        "comment": "I agree.",
        "userId": 105
      }],
      "images": [{
        "imgURL": "http://some.img.com/1"
      }, {
        "imgURL": "http://some.img.com/2"
      }]
    }
    

    现在显然需要在这里分别存储三种不同的数据对象:post、cmets 和 images。从数据存储的角度来看,帖子进入 POSTS 表,cmets 进入 COMMENTS 表,图像进入 IMAGES 表。因此,如果我们按照 John 描述的 SOA 的租户构建我们的服务,我们将使用我们的对象进行一次调用,然后它会尝试创建帖子的服务,例如,它工作得很好,然后它会尝试创建cmets 可以正常工作,但是当我们获取图像时,服务会意识到其中一个图像 URL 有错误是失败的。所以我们的服务返回失败?即使其他 3 个部分现在已成功存储在我们的数据存储中?我们是否返回并撤消所有成功执行的部分?如果数据存储已经提交了更改,而我们无法回滚呢?

    再加上这样一个事实,如果我们让它“更健谈”并单独提交它们,我们现在可以在其他应用程序中重复使用这些服务,而无需重新编写服务的任何部分。

    整合服务的坏处在于,您被出售的想法是服务永远不会失败……这很荒谬。总会有一个边缘情况,有些事情会失败,通过将所有东西整合到一个服务中,你增加了复杂性,实际上增加了失败的能力。

    我会将这个版本的 SOA 与我们在面向对象编程中构建上帝对象时已经意识到的缺点进行比较。 https://en.wikipedia.org/wiki/God_object

    我们比这更清楚,所以我们为什么要重新散列它?就像上帝对象一样,合并或上帝服务是一个坏主意。我说构建你的服务是为了做一件事,并为尽可能多的用例做好它,你的服务会很好。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-11-27
      • 2020-05-10
      • 1970-01-01
      • 2010-11-19
      • 2010-09-06
      • 1970-01-01
      相关资源
      最近更新 更多