Le modèle ActiveRecord respecte-t-il / encourage-t-il les principes de conception SOLID?

43

Je suis intéressé à savoir si le modèle ActiveRecord, rendu célèbre par Ruby on Rails, encourage ou décourage l'utilisation des principes de conception SOLID .

Par exemple, il me semble que les objets ActiveRecord contiennent à la fois une logique de domaine et une logique de persistance, ce qui constitue une violation de la responsabilité unique.

Nicholaides
la source
6
Jim Weirich, à la fin de son discours SOLID Ruby Talk lors de la conférence Ruby 2009, demande au public: "Les objets ActiveRecord implémentent un concept de domaine et un concept de persistance. Cela enfreint-il le principe de responsabilité unique (SRP)?" Le public convient qu'il enfreint le PÉR. Jim demande si cela les dérange. Beaucoup de spectateurs disent oui. Pourquoi? Cela rend les tests plus difficiles. Cela alourdit beaucoup l'objet de persistance.
David J.

Réponses:

56

Il y a des critiques valables sur ActiveRecord. Comme toujours, oncle Bob le résume parfaitement :

Le problème que j’ai avec Active Record est qu’il crée une confusion entre ces deux styles de programmation très différents. Une table de base de données est une structure de données. Il a exposé des données et aucun comportement. Mais un enregistrement actif semble être un objet. Il a des données "cachées" et un comportement exposé. Je mets le mot "caché" entre guillemets car les données ne sont en réalité pas cachées. Presque tous les dérivés ActiveRecord exportent les colonnes de la base de données via des accesseurs et des mutateurs. En effet, l'enregistrement actif est destiné à être utilisé comme une structure de données.

D'un autre côté, de nombreuses personnes utilisent des méthodes de règles métier dans leurs classes Active Record. ce qui les fait apparaître comme des objets. Cela conduit à un dilemme. De quel côté de la ligne le disque actif tombe-t-il vraiment? Est-ce un objet? Ou est-ce une structure de données?

Wikipedia résume la critique dans un souci de testabilité :

En POO, le concept d'encapsulation est souvent en contradiction avec le concept de séparation des préoccupations. De manière générale, les modèles qui favorisent la séparation des problèmes conviennent mieux aux tests unitaires isolés, tandis que les modèles qui favorisent l'encapsulation ont des API plus faciles à utiliser. Active Record favorise fortement l'encapsulation au point qu'il est assez difficile de tester sans base de données.

En ce qui concerne Ruby on Rails, Gavin King écrit :

À ce stade, la plupart des développeurs se disent euh, ok, alors comment diable suis-je censé savoir quels attributs une entreprise a en regardant mon code? Et comment mon IDE peut-il les compléter automatiquement? Bien sûr, les gens de Rails ont une réponse rapide à cette question. Oh, lancez simplement votre client de base de données et regardez dans la base de données !. Ensuite, en supposant que vous connaissiez parfaitement / parfaitement / les règles de capitalisation et de pluralisation automagiques d’ActiveRecord , vous serez en mesure de deviner les noms des attributs de votre propre classe Company et de les saisir manuellement.

Toujours sur l'implémentation de Ruby on Rails, John Januszczak écrit :

PROBLÈME N ° 1: MÉTHODES STATIQUES

...

Certains diraient que l'utilisation de méthodes statiques équivaut simplement à une programmation procédurale et constitue donc une conception médiocre orientée objet. D'autres diraient que les méthodes statiques sont mortelles pour la testabilité.

PROBLÈME N ° 2: PARAMÈTRES DE CONFIGURATION GLOBALE

...

Par conséquent, il n'y a pas d'injection de dépendance sur la classe Account dans mon exemple, et par extension, sur les instances Account. Comme nous devrions tous le savoir à présent, rechercher des choses est très, très mauvais!

Quelques ressources supplémentaires expliquant pourquoi ActiveRecord et ORM sont généralement considérés comme des anti-modèles:

ActiveRecord a toujours été perçu comme un anti-motif extrêmement utile , mais je conviens que cela va à l’encontre du SRP et du principe de l’inversion de dépendance.

Yannis
la source
Mise à jour importante pour les rails 5+: "Et comment mon IDE peut-il les compléter automatiquement? Bien sûr, les gens de Rails ont une réponse rapide à cette question. Oh, lancez simplement votre client de base de données et regardez dans la base de données!" N'est pas valide. plus. Avec les attributs de l'API, vous pouvez définir toutes les colonnes disponibles sur le modèle.
Filip Bartuzi
6

(Je suppose que la classe ActiveRecord est implémentée sans aucune possibilité d'injection de dépendance).

D'après mon expérience personnelle, le modèle ActiveRecord devient un obstacle majeur à la rédaction de tests unitaires. Le couplage de la couche de persistance et de la logique métier dans une même "classe ActiveRecord" rend impossible l'écriture de tests unitaires (à moins que vous ne refactoriez d'abord). Par conséquent, la seule option est d'écrire des tests d'intégration. et ce n'est pas aussi efficace que les tests unitaires. Cela devient un problème majeur, surtout si vous prenez en charge un projet comportant de nombreuses classes ActiveRecord; il donne lieu à des tests d'intégration extrêmement compliqués et difficiles à gérer.

Ainsi, ActiveRecord s’applique à peu près à SRP et crée un casse-tête de maintenance; il semble supprimer le pouvoir d'écrire des tests unitaires.

Guven
la source