事务脚本是Antipattern?

时间:2013-04-22 05:23:31

标签: design-patterns data-access-layer data-access

关于使用NoSQL数据库的事务脚本,有一个类似的主题,但这个主题是关于模式的。从我发现的事务脚本,它根本不是面向对象的。它基本上是程序代码,尽管它可以在其代码的每一行中使用对象。

更好的解决方案是使用域模型,与活动记录或数据映射器相结合,具有工作单元/身份映射/延迟加载/查询对象等。事务脚本可能很容易使用,但它实际上是程序编程,因此应该被视为面向对象世界的反模式。

你怎么看?您是否同意交易脚本是反模式的?或者你真的有办法设计一个面向对象的事务脚本而不是伪装的程序吗?我怀疑这是可能的。

3 个答案:

答案 0 :(得分:43)

交易脚本绝对是 反模式。

  

从我发现的关于事务脚本的内容来看,它根本不是面向对象的。

你是对的,事实并非如此。然而,这一事实并没有使它成为一种反模式。虽然它是一种程序性方法,但事实上,它仍然在一系列业务逻辑体系结构模式中处于正确的位置 - 您只需要知道在哪种情况下使用它是最佳实践 - 在这种情况下它不是。简单地说:如果您的问题域非常简单,那么在您的业务逻辑中使用更复杂的模式就不值得花费。

或 - 正如Fowler所写:

  

何时使用

     

Transaction Script的荣耀在于它的简单性。对于只有少量逻辑的应用程序来说,以这种方式组织逻辑是很自然的,并且它在性能或理解方面的开销很小。

您可能会想到的反模式称为Anemic Domain Model。当您打算认为正在构建域模型时就是这种情况 - 因为您的问题域很复杂,但实际上最终< / em>在一个事务脚本中 - 由于糟糕的代码组织/弱OO技能。

答案 1 :(得分:8)

反模式。事实上,大多数企业应用程序(我所见过的)都使用事务脚本而不是丰富的域模型模式。

您提到的

活动记录模式只有在您将域实体与持久存储聚合(RDBMS表)进行相当简单的一对一映射时才会很方便。

数据映射器类似于ORM(Hibernate和朋友)。如果您的业务逻辑位于域实体中,则这些实体必须自我变异。在我看来,这种耦合逻辑会使状态(当你使用ORM时是固有的)与状态本身发生变化。从外部查看域模型并将业务逻辑放入服务(事务脚本)中更为简单。此外,如果您的业务逻辑量很大,当它分散在域实体中时,更难找到相关代码(就像将事务脚本混合在一起一样)。

但是你不必最终采用完全程序化的方法,因为你可以(而且应该)将你的服务分解为自成一体的高度内聚的“程序容器”。

答案 2 :(得分:0)

TS不是OO或非OO。您可以在域模型方法,服务方法或高级应用程序方法中使用它。这只是意味着您可以阅读该程序的业务意图,而无需处理数百万个回调和“黑魔法”。

这就是Microsoft引入async / await的原因。它将看起来晦涩难懂的发送回调(委托)并退出,以单独的方法处理回调(必需)样式-变成可读的交易脚本

GOTO之所以糟糕,是因为它们破坏了交易脚本的可读流,使其变得很糟糕。

a)事务脚本出错是一种反模式。例如,一个巨大的方法,没有或很少的方法调用等,同一方法中的不同级别的操作(将它们重构为方法)。用一种方法将业务流程的离散步骤组合在一起(将它们分为方法或单独的类。很多业务对象?使用DDD服务模式)。

b)不正确使用TS是反模式。例如大量的应用程序间消息传递,事件触发等,因此您无法通读并查看业务流程(技术应用程序的功能要求)。低级细节(技术)与功能性工作混合在一起。业务活动过度分离,应该在一页上可见。

TS用法应该是分形的,每次放大都将深入探讨TS样式逻辑的更多细节。高级:您会看到方法调用和DDD服务的使用。中级水平可能会有点混乱。最下面的是域对象方法/属性调用,还有最详细的逻辑细节。

将TS丢在公交车上是因为它可能被滥用或阻止其使用,只是将罐子踢倒了-无法分组和分离并且不知道SRP(单一责任)/凝聚力的开发者会陷入困境还有其他样式。答案是对他们进行业务流程培训,并给出分组和分离的示例-应该由业务/功能要求(垂直部分)而非技术(水平部分)完成。

  1. 仅在DO中处理一个域对象或其类型的其他实例的逻辑。不要引用域对象(person.orders)中的其他对象类型或将任何东西注入域对象(其他DO或存储库等)。这样就违反了SRP。 [方法中的低级交易脚本]
  2. 当您需要诸如person.orders之类的东西,或者需要注入某种东西时,请进行DDD服务(未序列化,每次使用后都没有持久性)。注入例如一个人和其他集合(存储库或IQueryable等)。在那里做工作。 [此处是中级交易脚本]
  3. 在DDD服务的“应用程序方法”类别中组合对域对象和DDD svc的操作。
  4. 构造并调用程序最高级别的内容

在每个级别上,它看起来都像一个TX脚本,但要遵守规则。保持方法小。然后您将能够阅读它!

注意:在另一个答案提供的链接中,福勒(Fowler)告诉您如何制作对错脚本:

https://www.informit.com/articles/article.aspx?p=1398617

他也暗示这不是OO。我认为您可以将其与OO混合使用TS专家(可读性和其中的100个专家),以及数百个OO专家。也就是说,您可以将TS元素放在域模型中,并在更高级别的TS中组合使用域模型。

还将事务脚本的定义视为单个数据库事务。由于您的域模型不应注入存储库(将域对象注入存储库),因此您实际上可以像这样组织它,将相关存储库称为最高级别(去持久化)。但是,如果不是这种情况,那么重点是要有一个不会过度分离的可读代码流。

猛烈抨击TS的问题在于,人们认为SRP完全是关于SoC(关注点分离)的,而他们不必担心凝聚力(保持相同的东西,这也意味着SoC,但需要组织)。因此,有主见的工程师会将事物分解成一百万个小块(因为越多越好),并且很难辨别逻辑。