O padrão ActiveRecord segue / incentiva os princípios de design do SOLID?

43

Estou interessado em saber se o padrão ActiveRecord, popularizado pelo Ruby on Rails, incentiva ou desencoraja o uso dos princípios de design do SOLID .

Por exemplo, parece-me que os objetos ActiveRecord contêm lógica de domínio e lógica de persistência, o que é uma violação da responsabilidade única.

nicholaides
fonte
6
Jim Weirich, no final de seu SOLID Ruby Talk na Ruby Conference de 2009, pergunta ao público: "os objetos ActiveRecord implementam um conceito de domínio e um conceito de persistência. Isso viola o SRP (princípio de responsabilidade única)?" O público concorda que viola o SRP. Jim pergunta se isso os incomoda. Muitos membros da platéia dizem que sim. Por quê? Isso torna os testes mais difíceis. Isso torna o objeto de persistência muito mais pesado.
David J.

Respostas:

56

Há algumas críticas válidas no ActiveRecord. Como sempre, o tio Bob resume perfeitamente :

O problema que tenho com o Active Record é que ele cria confusão sobre esses dois estilos muito diferentes de programação. Uma tabela de banco de dados é uma estrutura de dados. Ele expôs dados e nenhum comportamento. Mas um registro ativo parece ser um objeto. Possui dados "ocultos" e comportamento exposto. Coloquei a palavra "oculto" entre aspas, porque os dados não estão ocultos. Quase todos os derivados do ActiveRecord exportam as colunas do banco de dados através de acessadores e mutadores. De fato, o Active Record deve ser usado como uma estrutura de dados.

Por outro lado, muitas pessoas colocam métodos de regras de negócios em suas classes do Active Record; o que os faz parecer objetos. Isso leva a um dilema. De que lado da linha o Active Record realmente cai? É um objeto? Ou é uma estrutura de dados?

A Wikipedia resume as críticas em uma preocupação de testabilidade :

Na OOP, o conceito de encapsulamento está frequentemente em desacordo com o conceito de separação de preocupações. De um modo geral, os padrões que favorecem a separação de preocupações são mais adequados para testes de unidade isolados, enquanto os padrões que favorecem o encapsulamento têm APIs mais fáceis de usar. O Active Record favorece fortemente o encapsulamento a ponto de testar sem um banco de dados ser bastante difícil.

Especificamente para a implementação do Ruby on Rails, Gavin King escreve (ênfase minha):

Neste ponto, a maioria dos desenvolvedores está pensando, ok, então como diabos eu devo saber quais atributos uma empresa possui olhando meu código? E como meu IDE pode preenchê-los automaticamente? Obviamente, o pessoal do Rails tem uma resposta rápida para essa pergunta. Oh, basta iniciar o seu cliente de banco de dados e procurar no banco de dados !. Então, assumindo que você conhece as regras de maiúsculas e pluralização automagicas do ActiveRecord / perfeitamente /, você poderá adivinhar os nomes dos atributos da sua própria classe Company e digitá-los manualmente.

Também na implementação do Ruby on Rails, John Januszczak escreve (ênfase minha):

PROBLEMA Nº 1: MÉTODOS ESTÁTICOS

...

Alguns diriam que o uso de métodos estáticos simplesmente equivale a programação procedural e, portanto, é um projeto pobre orientado a objetos. Outros diriam que métodos estáticos são a morte da testabilidade.

PROBLEMA # 2: CONFIGURAÇÕES GLOBAIS DE CONFIGURAÇÃO

...

Portanto, não há injeção de dependência na classe Account no meu exemplo e, por extensão, nas instâncias de Account. Como todos já sabemos, procurar coisas é muito, muito ruim!

Mais alguns recursos sobre por que o ActiveRecord e o ORM geralmente são considerados um antipadrão:

O ActiveRecord sempre pareceu um anti-padrão extremamente útil , mas eu concordo que ele vai contra o SRP e, adicionalmente, contra o princípio da inversão de dependência.

yannis
fonte
Atualização IMPORTANTE para o Rails 5+: "E como o meu IDE pode completá-lo automaticamente? É claro que o pessoal do Rails tem uma resposta rápida para essa pergunta. Ah, basta iniciar o seu cliente de banco de dados e procurar no banco de dados !." não é válido não mais. Com atributos API você pode definir todas as colunas disponíveis no modelo
Filip Bartuzi
6

(Suponho que a classe ActiveRecord seja implementada sem nenhuma possibilidade de injeção de dependência).

Por experiência pessoal, posso dizer que o padrão ActiveRecord se torna um grande obstáculo para escrever testes de unidade. O acoplamento da camada de persistência e da lógica de negócios em uma única "classe ActiveRecord" torna impossível a gravação de testes de unidade (a menos que você refatore primeiro). Portanto, a única opção é escrever testes de integração; e isso não é tão eficaz quanto os testes de unidade. Isso se torna um problema importante, especialmente se você assumir um projeto com muitas classes do ActiveRecord; ele produz testes de integração altamente complicados e difíceis de manter.

Portanto, o ActiveRecord vem praticamente contra o SRP e cria alguma dor de cabeça na manutenção; parece tirar o poder de escrever testes de unidade.

Guven
fonte