¿El patrón ActiveRecord sigue / fomenta los principios de diseño SÓLIDO?

43

Me interesa saber si el patrón ActiveRecord, famoso por Ruby on Rails, fomenta o desalienta el uso de principios de diseño SOLID .

Por ejemplo, me parece que los objetos ActiveRecord contienen lógica de dominio y lógica de persistencia, lo cual es una violación de la responsabilidad única.

Nicholaides
fuente
66
Jim Weirich, al final de su SOLID Ruby Talk en la Ruby Conference 2009, pregunta a la audiencia: "Los objetos ActiveRecord implementan un concepto de dominio y un concepto de persistencia. ¿Esto viola el SRP (Principio de Responsabilidad Única)?" El público acuerda que viola el SRP. Jim pregunta si esto les molesta. Muchos miembros de la audiencia dicen que sí. ¿Por qué? Hace que las pruebas sean más difíciles. Hace que el objeto de persistencia sea mucho más pesado.
David J.

Respuestas:

56

Hay algunas críticas válidas en ActiveRecord. Como siempre, el tío Bob lo resume perfectamente :

El problema que tengo con Active Record es que crea confusión sobre estos dos estilos de programación muy diferentes. Una tabla de base de datos es una estructura de datos. Tiene datos expuestos y ningún comportamiento. Pero un registro activo parece ser un objeto. Tiene datos "ocultos" y comportamiento expuesto. Pongo la palabra "oculto" entre comillas porque los datos, de hecho, no están ocultos. Casi todos los derivados de ActiveRecord exportan las columnas de la base de datos a través de accesores y mutadores. De hecho, el registro activo está destinado a ser utilizado como una estructura de datos.

Por otro lado, muchas personas ponen métodos de reglas de negocio en sus clases de Active Record; lo que los hace parecer objetos. Esto lleva a un dilema. ¿De qué lado de la línea cae realmente el registro activo? ¿Es un objeto? ¿O es una estructura de datos?

Wikipedia resume las críticas en una preocupación de comprobabilidad :

En OOP, el concepto de encapsulación a menudo está en desacuerdo con el concepto de separación de preocupaciones. En términos generales, los patrones que favorecen la separación de preocupaciones son más adecuados para pruebas unitarias aisladas, mientras que los patrones que favorecen la encapsulación tienen API más fáciles de usar. Active Record favorece en gran medida la encapsulación hasta el punto en que las pruebas sin una base de datos son bastante difíciles.

Específicamente para la implementación de Ruby on Rails, Gavin King escribe (el énfasis es mío):

En este punto, la mayoría de los desarrolladores están pensando um, ok, entonces, ¿cómo demonios se supone que debo saber qué atributos tiene una Compañía al mirar mi código? ¿Y cómo puede mi IDE completarlos automáticamente? Por supuesto, la gente de Rails tiene una respuesta rápida a esta pregunta. ¡Oh, simplemente inicie su cliente de base de datos y mire en la base de datos !. Luego, suponiendo que conozca las reglas de capitalización y pluralización automáticas de ActiveRecord / perfectamente /, podrá adivinar los nombres de los atributos de su propia clase Compañía y escribirlos manualmente.

También en la implementación de Ruby on Rails, John Januszczak escribe (el énfasis es mío):

PROBLEMA # 1: MÉTODOS ESTÁTICOS

...

Algunos dirían que usar métodos estáticos simplemente equivale a programación de procedimientos y, por lo tanto, es un diseño orientado a objetos deficiente. Otros dirían que los métodos estáticos son la muerte de la comprobabilidad.

PROBLEMA # 2: CONFIGURACIÓN GLOBAL DE CONFIGURACIÓN

...

Por lo tanto, no hay inyección de dependencia en la clase Cuenta en mi ejemplo, y por extensión, en las instancias de Cuenta. Como todos deberíamos saber ahora, ¡buscar cosas es muy, muy malo!

Algunos recursos más sobre por qué ActiveRecord y ORM generalmente se consideran un antipatrón:

ActiveRecord siempre se sintió como un anti-patrón extremadamente útil , pero estoy de acuerdo en que va en contra de SRP y, además, va en contra del principio de inversión de dependencia.

Yannis
fuente
Actualización IMPORTANTE para rails 5+: "¿Y cómo puede mi IDE completarlos automáticamente? Por supuesto, la gente de Rails tiene una respuesta rápida a esta pregunta. ¡Oh, simplemente inicie su cliente de base de datos y mire en la base de datos!". nunca más. Con los atributos API puede definir todas las columnas disponibles en el modelo
Filip Bartuzi
6

(Supongo que la clase ActiveRecord se implementa sin ninguna posibilidad de inyección de dependencia).

Por experiencia personal, puedo decir que el patrón ActiveRecord se convierte en un obstáculo importante para escribir pruebas unitarias. El acoplamiento de la capa de persistencia y la lógica de negocios en una sola "clase ActiveRecord" hace que sea imposible escribir pruebas unitarias (a menos que refactorice primero). Por lo tanto, la única opción es escribir pruebas de integración; y eso no es tan efectivo como las pruebas unitarias. Esto se convierte en un problema importante, especialmente si se hace cargo de un proyecto con muchas clases de ActiveRecord; da lugar a pruebas de integración altamente complicadas que son difíciles de mantener.

Por lo tanto, el ActiveRecord viene bastante en contra de SRP y crea un dolor de cabeza de mantenimiento; parece quitarle el poder de escribir pruebas unitarias.

Guven
fuente