Camada de serviço de aplicativo que chama funções de banco de dados. Arquitetura ruim?

11

Cenário:

  • Pilha: Java, Spring, Hibernação.
  • Modelo: Aplicativo Cliente-Servidor.
  • Padrão: Model-View-Controller (MVC).

As classes da camada de serviço têm três comportamentos:

  1. Alguns serviços têm a regra de negócios dentro dos métodos e delegam a persistência ao aplicativo. Gostar:

    EntityManager.save (entidade);

  2. Alguns serviços simplesmente chamam uma função de banco de dados (passando parâmetros)

    CallableStatement cls = con.prepareCall ("{chamar databaseFunction (args)}");

  3. Alguns serviços têm métodos com ambos os comportamentos.

Minhas perguntas:

  1. Existe algum problema em ter os serviços de aplicativos chamando diretamente as funções do banco de dados? Isso não é considerado uma prática ruim? O que seria um modelo de arquitetura aplicável a um projeto como este?
  2. Existe algum problema em ter o comportamento misturado no mesmo serviço? Tais como transações e consistência?
  3. No caso de manutenção, esse encapsulamento torna obscuro para o desenvolvedor que ele também deve alterar as funções no banco de dados? Como evitar isso?
  4. Esse cenário ocorre em outros aplicativos ao redor do mundo ou foi apenas um erro de arquitetura?
linuxunil
fonte

Respostas:

7

Existe algum problema em ter os serviços de aplicativos chamando diretamente as funções do banco de dados? Isso não é considerado uma prática ruim?

Eu acho que existe. Você está colocando um conhecimento sobre os internos do banco de dados no serviço de aplicativo. Alterar o banco de dados de qualquer forma (alterar o mecanismo de armazenamento ou até renomear um campo ou criar um índice) pode exigir a alteração do serviço de aplicativo e isso viola o SRP .

O que seria um modelo de arquitetura aplicável a um projeto como este?

Veja o comentário abaixo.

Existe algum problema em ter o comportamento misturado no mesmo serviço? Tais como transações e consistência?

Não acredito que haja um problema técnico, mas existe um lógico. Você apenas mistura duas abordagens no aplicativo, tornando-o vago, menos estruturado e difícil de se adaptar às mudanças. Veja os comentários acima sobre a violação do SRP também.

No caso de manutenção, esse encapsulamento torna obscuro para o desenvolvedor que ele também deve alterar as funções no banco de dados?

Claro que sim.

Como evitar isso?

Coloque métodos e funções que trabalham diretamente com o banco de dados em um nível separado de abstração (seja uma camada DAO ou um padrão de repositório simples - depende da complexidade do seu aplicativo)

Esse cenário ocorre em outros aplicativos ao redor do mundo ou foi apenas um erro de arquitetura?

Eu acho que no nosso mundo tudo acontece;)

Vladislav Rastrusny
fonte
Se bem entendi, pode haver um problema técnico, pois, se houver atualizações nas funções / procs armazenados e também através de um ORM, é muito difícil argumentar sobre os estados de uma determinada transação. Embora o aplicativo possa funcionar em seu estado atual, uma pequena alteração pode causar alguns problemas realmente grandes. Minha experiência com o Hibernate é que, se você não permitir que ele gerencie todo o conjunto de tabelas com as quais trabalha, você terá muitos problemas irritantes.
precisa saber é o seguinte
resposta agradável e concisa. O SRP foi a primeira coisa que me veio à cabeça quando olhei o código pela primeira vez. Alguns colegas de trabalho dizem que o método não viola o SRP devido ao fato de chamar apenas a função de banco de dados. Mas algumas dessas funções selecionam, inserções e atualizações. Portanto, viola ou não o SRP? (talvez isso em si é outra questão para discutir separatedly?)
linuxunil
1
+1 para essa linha eu acho que em nosso mundo tudo acontece;)
linuxunil
O SRP do @linuxunil deve ser respeitado em todos os níveis da arquitetura. No meu caso, eu quis dizer SRP no nível do serviço, não no nível do método. @ JimmyJames Sim. A maioria dos ORMs não funciona bem com os procedimentos armazenados. Mas, às vezes, processos armazenados são necessários.
Vladislav Rastrusny
3

De acordo com o que você disse, há uma camada de serviço, portanto o padrão arquitetural que parece adequado é a Arquitetura em Camadas. Referência adicional

Sim, geralmente é uma prática ruim fazer chamadas diretas ao banco de dados que não sejam uma camada de acesso a dados, para que a camada comercial acesse apenas uma abstração do banco de dados.

Quanto aos comportamentos de mistura, o uso de algum padrão de design como padrão DAO ou padrão de repositório pode ajudar a delegar essas responsabilidades, melhorando assim o código.

Algumas das vantagens de usar um padrão de design e um ORM é a legibilidade do seu código, o encapsulamento das responsabilidades, portanto, se o acesso ao seu banco de dados mudar, a camada de negócios não deve mudar muito.

J. Pichardo
fonte
Não sei por que isso foi rejeitado. Esta resposta recomenda separar o código que lida com diferentes preocupações . Parece um diretor de programação aqui ... não sei o que é ... Cara. Se ao menos eu pudesse pensar no nome. +1 BTW
Greg Burghardt
Não é um dos princípios sólidos?
J. Pichardo
3
No. O "S" no estado sólido é a S ingle responsabilidade principal (SRP). Mas a Separação de Preocupações, que você recomenda, é um motivo válido para separar a lógica de serviço da lógica de acesso a dados. A outra resposta de Vladislav menciona o diretor de responsabilidade única. Francamente, o SRP e o Separation of Concerns andam bem, como vinho e queijo.
Greg Burghardt