Depois de usar o Hibernate na maioria dos meus projetos há cerca de 8 anos, entrei em uma empresa que desencoraja seu uso e deseja que os aplicativos interajam apenas com o banco de dados através de procedimentos armazenados.
Depois de fazer isso por algumas semanas, não consegui criar um modelo de domínio avançado do aplicativo que estou começando a criar, e o aplicativo parece um script transacional (horrível).
Alguns dos problemas que encontrei são:
- Não é possível navegar no gráfico de objetos, pois os procedimentos armazenados apenas carregam a quantidade mínima de dados, o que significa que, às vezes, temos objetos semelhantes com campos diferentes. Um exemplo é: temos um procedimento armazenado para recuperar todos os dados de um cliente e outro para recuperar informações da conta, além de alguns campos do cliente.
- Muita lógica acaba nas classes auxiliares, portanto o código se torna mais estruturado (com entidades usadas como estruturas C antigas).
- Código de andaime mais chato, pois não existe uma estrutura que extraia conjuntos de resultados de um procedimento armazenado e o coloque em uma entidade.
Minhas perguntas são:
- alguém já passou por uma situação semelhante e não concordou com a abordagem do procedimento de armazenamento? o que você fez?
- Existe um benefício real do uso de procedimentos armazenados? além do ponto bobo de "ninguém pode emitir uma tabela suspensa".
- Existe uma maneira de criar um domínio rico usando procedimentos armazenados? Eu sei que existe a possibilidade de usar o AOP para injetar DAOs / Repositórios em entidades para poder navegar no gráfico de objetos. Não gosto dessa opção, pois é muito próxima do vodu.
Conclusão
Primeiro, obrigado a todos por suas respostas. A conclusão que cheguei é que os ORMs não permitem a criação de modelos Rich Domain (como algumas pessoas mencionaram), mas simplificam a quantidade de trabalho (geralmente repetitivo). A seguir, é apresentada uma explicação mais detalhada da conclusão, mas não é baseada em dados concretos.
A maioria dos aplicativos solicita e envia informações para outros sistemas. Para fazer isso, criamos uma abstração nos termos do modelo (por exemplo, um evento de negócios) e o modelo de domínio envia ou recebe o evento. O evento geralmente precisa de um pequeno subconjunto de informações do modelo, mas não de todo o modelo. Por exemplo, em uma loja online, um gateway de pagamento solicita algumas informações e o total para cobrar um usuário, mas não exige o histórico de compras, os produtos disponíveis e toda a base de clientes. Portanto, o evento possui um conjunto pequeno e específico de dados.
Se considerarmos o banco de dados de um aplicativo como um sistema externo, precisamos criar uma abstração que permita mapear as entidades do Modelo de Domínio para o banco de dados ( como NimChimpsky mencionou , usando um mapeador de dados). A diferença óbvia é que agora precisamos criar um mapeamento para cada entidade de modelo no banco de dados (um esquema herdado ou procedimentos armazenados), com a dor extra de que, como os dois não estão sincronizados, uma entidade de domínio pode mapear parcialmente para uma entidade de banco de dados (por exemplo, uma classe UserCredentials que contém apenas nome de usuário e senha é mapeada para uma tabela Usuários que possui outras colunas) ou uma entidade de modelo de domínio pode mapear para mais de uma entidade de banco de dados (por exemplo, se houver uma um mapeamento na tabela, mas queremos todos os dados em apenas uma classe).
Em um aplicativo com poucas entidades, a quantidade de trabalho extra pode ser pequena se não houver necessidade de transversalidade das entidades, mas aumenta quando há uma necessidade condicional de transversalidade das entidades (e, portanto, podemos implementar algum tipo de 'preguiçoso'). Carregando'). À medida que um aplicativo cresce para ter mais entidades, esse trabalho apenas aumenta (e eu tenho a sensação de que aumenta não linearmente). Minha suposição aqui é que não tentamos reinventar um ORM.
Um benefício de tratar o banco de dados como um sistema externo é que podemos codificar situações nas quais queremos 2 versões diferentes de um aplicativo em execução, nas quais cada aplicativo possui um mapeamento diferente. Isso se torna mais interessante no cenário de entregas contínuas para produção ... mas acho que isso também é possível com ORMs em menor grau.
Vou descartar o aspecto de segurança, com base em que um desenvolvedor, mesmo que ele não tenha acesso ao banco de dados, pode obter a maioria, senão todas as informações armazenadas em um sistema, apenas injetando código malicioso (por exemplo, Não acredito que esqueci de remover a linha que registra os detalhes do cartão de crédito dos clientes, prezado senhor! ).
Pequena atualização (6/6/2012)
Os procedimentos armazenados (pelo menos no Oracle) impedem fazer algo como entrega contínua com tempo de inatividade zero, pois qualquer alteração na estrutura das tabelas invalidará os procedimentos e acionadores. Portanto, durante o tempo em que o banco de dados está sendo atualizado, o aplicativo também ficará inativo. A Oracle fornece uma solução para essa redefinição baseada em edição , mas os poucos DBAs que perguntei sobre esse recurso mencionaram que ele estava mal implementado e não o colocaram em um banco de dados de produção.