ActiveRecord模式是否遵循/鼓励SOLID设计原则?


43

我对从Ruby on Rails中出名的ActiveRecord模式是否鼓励或不鼓励使用SOLID设计原则感到感兴趣。

例如,在我看来ActiveRecord对象都包含域逻辑和持久性逻辑,这违反了“单一职责”。


6
Jim Weirich在2009年Ruby大会上的SOLID Ruby演讲结束时向观众提问:“ ActiveRecord对象实现了域概念和持久性概念。这是否违反了SRP(单一责任原则)?” 听众同意它确实违反了SRP。吉姆问这是否打扰了他们。许多听众说是。为什么?它使测试更加困难。它使持久性对象变得很重。
David J.

Answers:


56

ActiveRecord有一些有效的批评。和往常一样,鲍伯叔叔 完美地总结了一下

我对Active Record的问题是,它对这两种截然不同的编程风格产生了混淆。数据库表是一种数据结构。它公开了数据,没有任何行为。但是活动记录似乎是一个对象。它具有“隐藏”数据和公开行为。我将“隐藏”一词用引号引起来,因为实际上数据不是隐藏的。几乎所有ActiveRecord派生类都通过访问器和更改器导出数据库列。实际上,Active Record的用途就像是数据结构。

另一方面,许多人在其Active Record类中添加了业务规则方法。这使它们看起来像是对象。这导致了两难选择。活动记录真正落在哪一边?是物体吗?还是数据结构?

维基百科在可测试性方面总结了批评意见:

在OOP中,封装的概念通常与关注点分离的概念不一致。一般而言,支持关注点分离的模式更适合于隔离的单元测试,而支持封装的模式则更易于使用API​​。Active Record强烈支持封装,以至于没有数据库的测试非常困难。

加文·金Gavin King)专为Ruby on Rails实现而设计(重点是我):

在这一点上,大多数开发人员都在想,好吧,那么我该如何通过查看我的代码来了解公司的属性?我的IDE如何自动完成它们?当然,Rails员工对这个问题有一个快速的答案。噢,只需启动您的数据库客户端并查看数据库!然后,假设您知道ActiveRecord的自动大写和复数规则/ 完全 /,您将能够猜出您自己的Company类的属性名称,并手动键入它们。

同样在Ruby on Rails实施中,John Januszczak写道(重点是我):

问题1:静态方法

...

有人会说使用静态方法仅相当于过程编程,因此是差的面向对象设计。其他人会说静态方法是可测试性的牺牲品。

问题2:全局配置设置

...

因此,在我的示例中,没有对Account类进行依赖注入,也没有对Account实例进行依赖注入。众所周知,寻找事物是非常非常糟糕的!

关于为何通常将ActiveRecord和ORM视为反模式的其他资源:

ActiveRecord一直被认为是一种非常有用的反模式,但我确实同意它违反了SRP,另外,它也违反了依赖反转原则。


Rails 5+的重要更新:“而且我的IDE如何自动完成它们?当然,Rails伙计们对这个问题有一个快速的答案,哦,只启动数据库客户端并查看数据库!。”无效不再。使用属性API,您可以定义模型上所有可用的列
Filip Bartuzi

6

(我假设ActiveRecord类的实现没有任何可能的依赖注入)。

根据个人经验,我可以说ActiveRecord模式成为编写单元测试的主要障碍。持久层和业务逻辑的耦合在单个“ ActiveRecord类”中,使得不可能编写单元测试(除非您首先进行重构)。因此,唯一的选择是编写集成测试。这不如单元测试有效。这将成为一个主要问题,尤其是如果您接管具有许多ActiveRecord类的项目;它会导致难以维护的高度复杂的集成测试。

因此,ActiveRecord非常不利于SRP,并带来一些维护上的麻烦;它似乎剥夺了编写单元测试的能力。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.