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).
fonte
Respostas:
Seu princípio orientador deve ser Não se repita :
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:
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.
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
É 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:
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.
fonte
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:
Atualizações manuais do banco de dados (elas parecem acontecer em todas as empresas)
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.
fonte
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?
fonte
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".
fonte
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.
fonte