Para um ORM que suporta validação de dados, as restrições também devem ser aplicadas no banco de dados?

13

Sempre apliquei restrições no nível do banco de dados, além dos meus modelos (ActiveRecord). Mas eu queria saber se isso é realmente necessário?

Um pouco de fundo

Recentemente, tive que testar por unidade um método básico automatizado de geração de registro de data e hora para um modelo. Normalmente, o teste criaria uma instância do modelo e a salvaria sem validação. Mas existem outros campos obrigatórios que não são anuláveis ​​na definição da tabela, o que significa que não posso salvar a instância, mesmo que pule a validação do ActiveRecord. Então, estou pensando se devo remover essas restrições do próprio banco de dados e deixar o ORM lidar com elas?

Possíveis vantagens se eu pular restrições no db, imo -

  • Pode modificar uma regra de validação no modelo, sem precisar migrar o banco de dados.
  • Pode pular a validação nos testes.

Possível desvantagem?

Se for possível que a validação do ORM falhe ou seja ignorada, o banco de dados não verifica se há restrições.

O que você acha?

EDIT Neste caso, estou usando o Yii Framework , que gera o modelo a partir do banco de dados, portanto as regras do banco de dados também são geradas (embora eu sempre possa escrevê-las também após a geração).

n / D
fonte
3
Se os dados em seu banco de dados puderem ser rotineiramente modificados sem o uso do ORM (outros aplicativos sem o ORM, ou, pior, acesso direto ao banco de dados pelos usuários), a validação realmente precisará estar no banco de dados.
Marjan Venema

Respostas:

16

Seu princípio orientador deve ser Não se repita :

Na engenharia de software, o DRY (Não se repita) é um princípio de desenvolvimento de software que visa reduzir a repetição de informações de todos os tipos, especialmente útil em arquiteturas de várias camadas. O princípio DRY é declarado como "Todo conhecimento deve ter uma representação única, inequívoca e autorizada dentro de um sistema".

O ORM é essencialmente uma camada extra (ou camada, se preferir), situada confortavelmente entre o aplicativo e o (s) armazenamento (s) de dados. Suas restrições devem estar em um local e apenas em um local, seja o ORM ou o armazenamento de dados; caso contrário, em breve, você acabará mantendo versões diferentes deles. Você realmente não quer fazer isso.

No entanto, na prática, a maioria dos ORMs decentes gera automaticamente uma grande quantidade de seus modelos a partir do seu esquema de dados. Embora ainda haja duplicação, as chances de manutenção são mínimas, pois o código ORM duplicado é gerado seguindo o mesmo padrão a cada vez. Seria ideal não ter código duplicado, mas as restrições geradas automaticamente são a próxima melhor opção.

Além disso, ter suas restrições em um local não significa necessariamente que você deve ter todas as restrições no mesmo local. Algumas, como restrições de integridade referencial, podem ser mais adequadas para o armazenamento de dados (mas podem ser perdidas se você mudar para outro armazenamento de dados) e outras, principalmente aquelas que envolvem lógica de negócios complexas, são mais adequadas para o seu ORM. Seria preferível ter todas as suas maçãs na mesma cesta, mas…

Falhas

Você mencionou a falha do ORM. Isso é absolutamente irrelevante para sua pergunta, seu aplicativo deve pensar no ORM e no armazenamento de dados como uma entidade única. Se falhar, falhar, ignorar o ORM para conversar diretamente com o armazenamento de dados não é uma boa ideia.

Ignorando o ORM para qualquer outra coisa

Também não é uma boa ideia. No entanto, isso pode acontecer por vários motivos:

  1. Partes herdadas do aplicativo que foram criadas antes da introdução do ORM.

    Essa é uma pergunta difícil, e exatamente a situação com a qual estou lidando agora , daí a minha repetição constante do "inferno da manutenção". Você continua mantendo as partes que não são do ORM ou as reescreve para usar o ORM. A segunda opção pode fazer mais sentido inicialmente, mas é uma decisão baseada apenas no que exatamente essas partes do seu aplicativo estão fazendo e em quão valiosa seria uma reescrita completa a longo prazo.

    Tente alterar uma chave em uma tabela MySQL 2 * 10 ^ 8 mal projetada (sem tempo de inatividade) e você entenderá de onde estou vindo.

  2. Partes não herdadas do aplicativo que precisam absolutamente conversar diretamente com o armazenamento de dados:

    Ainda mais complicado. Os ORMs são ferramentas sofisticadas e cuidam de quase tudo, mas às vezes atrapalham ou são absolutamente inúteis. A palavra-chave (na verdade, palavra-chave) é incompatibilidade de impedância objeto-relacional ; basta dizer que não é tecnicamente possível para o seu ORM fazer tudo o que seu banco de dados relacional faz e, para algumas das coisas que fazem, há uma penalidade significativa no desempenho.

Comentários

Do ponto de integridade dos dados, as restrições DEVEM estar no banco de dados e DEVEM estar no aplicativo. E se o seu aplicativo for acessado a partir de aplicativos da Web e de desktop, ou aplicativo móvel ou serviço da Web? - Luiz Damim

É aqui que adicionar uma camada extra seria extremamente útil e, se estamos falando de um aplicativo Web, eu usaria uma API REST. Um design excessivamente simplista para isso seria:

insira a descrição da imagem aqui

O ORM fica entre a API e os armazenamentos de dados, e tudo por trás da API (incluindo ela) seria considerado uma entidade única dos vários aplicativos.

yannis
fonte
Normalmente, você definiria um esquema no seu ORM que será espelhado no banco de dados para ter um segundo nível de garantia.
Josh K
2
@ Josh Você diz o segundo nível de garantia, eu digo o inferno da manutenção. Não estou dizendo que você não está certo, embora ...
yannis
Faz sentido. Estou seguindo esta rota agora. Obrigado!
na
1
Depois que você passa do ponto em que um ou dois desenvolvedores estão trabalhando com código e banco de dados, isso se torna um mal necessário. Se você usar um bom ORM, também gerará migrações para você. Quando você chega ao ponto de ter um DBA dedicado, não há uma maneira de contornar isso, eles não permitirão que as tabelas flutuem sem restrições. A maneira simples de impedir que as pessoas se inscrevam sem um e-mail é restringir o nível de armazenamento.
21412 Josh K
1
Do ponto de integridade dos dados, as restrições DEVEM estar no banco de dados e DEVEM estar no aplicativo. E se o seu aplicativo for acessado a partir de aplicativos da Web e de desktop, ou aplicativo móvel ou serviço da Web?
Luiz Damim 21/06/12
20

Esta é realmente uma pergunta muito difícil de responder e eu achei que era um assunto muito controverso.

Como Yannis Rizos apontou em sua resposta, ter a lógica de restrição no banco de dados e na camada ORM parece violar o DRY, o que "pode ​​levar a pesadelos de manutenção, fatoração deficiente e contradições lógicas".

No entanto, remover a lógica de restrição do banco de dados e mantê-la apenas na camada ORM não funcionaria se você tiver alguma das seguintes condições:

  1. Atualizações manuais do banco de dados (elas parecem acontecer em todas as empresas)

  2. Atualizações de banco de dados de outro sistema que nem sempre pode compartilhar facilmente a lógica de restrição ORM (ex / um script Perl que executa tarefas de rotina quando a camada ORM é implementada no Hibernate e usada por um aplicativo Java para a atividade diária)

Isso sugere que você adicione apenas a lógica de restrição ao banco de dados e remova-a da camada ORM para evitar uma violação DRY. No entanto, isso pode levar a casos em que o código do aplicativo não pode capturar com êxito o problema real e retransmitir para o usuário (embora, como desenvolvedor, depure o problema, você provavelmente pode). Isso pode não ser aceitável para alguns projetos.

Sua última opção é automatizar a criação das restrições no ORM (e em qualquer outro sistema) a partir das restrições do banco de dados (ou, realmente ... vice-versa). Embora você acabe com duas ou mais implementações das restrições, não será uma violação do princípio DRY, conforme descrito em "O Programador Pragmático", pois recomenda a utilização da geração de código para evitar violações DRY. Obviamente, não é tão simples, porque, por exemplo, todas as alterações em uma restrição de banco de dados podem forçar uma recriação e reimplantação de todos os aplicativos que o utilizam (não é fácil automatizar).

Realmente, teria que ser avaliado caso a caso . Posso dizer-lhe que, até este ponto, me deparei com olhares em branco quando sugiro que a lógica da restrição não seja repetida.

smp7d
fonte
2
Acabei de sair do trabalho e estava pensando em expandir minha resposta para ser mais ou menos o que você acabou de postar. Boa resposta!
yannis
3

Definitivamente adicionaria restrições ao banco de dados como minha opção padrão. Isso ocorre porque, para uma empresa, os dados são importantes e a qualidade dos dados é fundamental. @Yannis Rizos trouxe o princípio DRY para a discussão. Bem, outro princípio é a Defesa em Profundidade. Para dados, eu usaria esse princípio.

Eu trabalhei em empresas reais, onde o banco de dados tem dados criados há 30 anos. Foi e ainda é acessado pelo aplicativo COBOL e agora por um aplicativo .Net. Em 10 anos, pode ser um aplicativo de fornecedor, quem sabe. Houve uma fusão e milhões de linhas de dados foram convertidas e migradas da outra empresa para esse banco de dados usando SQL. Nenhum ORM pode fazer isso. A linha inferior é que os dados permanecem, os aplicativos mudam, assim como os dados são gerados mudam. Então, por que não reduzir a chance de corrupção de dados?

softveda
fonte
2

Eu acho que você faz as duas coisas até certo ponto.

  • As principais restrições devem estar no ORM - as linguagens de programação são muito mais flexíveis, é mais fácil de testar e mais fácil de ajustar quando os requisitos mudam; não precisa se preocupar com correções de DDL, pelo menos. E você geralmente evita problemas de regressão de dados difíceis de testar.

  • Algumas restrições muito difíceis e rápidas também devem estar no banco de dados. Não estou falando de nomes não anuláveis, por exemplo. Estou falando de coisas como integridade referencial ou exigindo alguns identificadores absolutamente cruciais. Requisitos estruturais para que seu código não precise lidar com "e se o Pedido tiver um produto inexistente".

Wyatt Barnett
fonte
1

O banco de dados é o IMO, o único local em que o DRY pode ser violado, porque se algo ignora seu ORM e possui dados incorretos, é isso. Fim de jogo. Ter dados corrompidos é o golpe final.

Wayne Molina
fonte
Apenas banco de dados? Posso pensar em muitos casos em que o comportamento associado aos dados deve existir em várias camadas (lógicas ou físicas), mesmo se os dados não persistirem. Às vezes, é possível ter um único código-fonte e reduzir a "duplicação" para as dlls implantadas.
precisa saber é o seguinte