Quanta lógica comercial deve implementar o banco de dados?

90

Trabalhei em alguns projetos em que a maior parte da lógica de negócios foi implementada no banco de dados (principalmente por meio de procedimentos armazenados). Por outro lado, ouvi de alguns colegas programadores que isso é uma prática ruim ("Bancos de dados estão lá para armazenar dados. Os aplicativos estão lá para fazer o resto").

Qual destas abordagens é geralmente melhor?

As vantagens de implementar a lógica de negócios no banco de dados em que consigo pensar são:

  • Centralização da lógica de negócios;
  • Independência do tipo de aplicativo, linguagem de programação, sistema operacional, etc;
  • Bancos de dados são menos propensos à migração de tecnologia ou grandes refatorações (AFAIK);
  • Sem retrabalho na migração da tecnologia de aplicativos (por exemplo, .NET para Java, Perl para Python, etc).

Os contras:

  • O SQL é menos produtivo e mais complexo para a programação de lógica de negócios, devido à falta de bibliotecas e construções de linguagem que a maioria das linguagens orientadas a aplicativos oferece;
  • Reutilização de código mais difícil (se possível) em bibliotecas;
  • IDEs menos produtivos.

Observação: os bancos de dados dos quais estou falando são bancos de dados relacionais e populares, como SQL Server, Oracle, MySql, etc.

Obrigado!

    
por Raphael 09.04.2013 / 17:04
fonte

9 respostas

72

A lógica de negócios não entra no banco de dados

Se estamos falando de aplicativos multicamadas, parece bastante claro que a lógica de negócios, o tipo de inteligência que executa uma determinada empresa, pertence à camada de lógica de negócios, e não à camada de acesso a dados.

Bancos de dados fazem algumas coisas muito bem:

  1. Eles armazenam e recuperam dados
  2. Eles estabelecem e reforçam relacionamentos entre diferentes entidades de dados
  3. Eles fornecem os meios para consultar os dados em busca de respostas
  4. Eles fornecem otimizações de desempenho.
  5. Eles fornecem controle de acesso

Agora, é claro, você pode codificar todos os tipos de coisas em um banco de dados que dizem respeito às suas preocupações comerciais, como taxas de imposto, descontos, códigos de operação, categorias e assim por diante. Mas a ação comercial que é feita com base nos dados geralmente não é codificada no banco de dados, por todos os tipos de motivos já mencionados por outros, embora uma ação possa ser escolhida no banco de dados e executado em outro lugar.

E, claro, pode haver coisas que são realizadas em um banco de dados por desempenho e por outros motivos:

  1. Fechando um período contábil
  2. Processamento de números
  3. Processos em lote noturnos
  4. Failover

Naturalmente, nada está gravado em pedra. Procedimentos armazenados são adequados para uma grande variedade de tarefas, simplesmente porque eles vivem no servidor de banco de dados e possuem certas vantagens e vantagens.

Procedimentos armazenados em todos os lugares

Há um certo fascínio em codificar todas as suas tarefas de armazenamento, gerenciamento e recuperação de dados em procedimentos armazenados e simplesmente consumir os serviços de dados resultantes. Você certamente se beneficiaria do máximo possível de otimizações de desempenho e segurança que o servidor de banco de dados poderia fornecer, e isso não é pouca coisa.

Mas o que você arrisca?

  1. Bloqueio do fornecedor
  2. A necessidade de desenvolvedores com conjuntos de habilidades especiais
  3. Ferramentas de programação espartana, em geral
  4. Acoplamento de software extremamente preciso
  5. Nenhuma separação de interesses

E, claro, se você precisar de um serviço da Web (que provavelmente é o lugar para onde isso está indo, de qualquer forma), você ainda terá que criar isso.

Então, qual é a prática típica?

Eu diria que uma abordagem típica e moderna é usar um Object-Relational Mapper (como o Entity Framework) para criar classes que modelam suas tabelas. Você pode então falar com seu banco de dados através de um repositório que retorna coleções de objetos, uma situação que é muito familiar para qualquer desenvolvedor de software competente. O ORM gera dinamicamente o SQL correspondente ao seu modelo de dados e as informações solicitadas, que o servidor de banco de dados processa para retornar os resultados da consulta.

Quão bem isso funciona? Muito bem e muito mais rapidamente do que escrever procedimentos armazenados e visualizações. Isso geralmente cobre cerca de 80% dos requisitos de acesso a dados, principalmente o CRUD. O que cobre os outros 20%? Você adivinhou: procedimentos armazenados, que todos os principais ORMs suportam diretamente.

Você pode escrever um gerador de código que faz a mesma coisa que um ORM, mas com procedimentos armazenados? Certamente você pode. Mas os ORMs são geralmente independentes do fornecedor, bem compreendidos por todos e melhor suportados.

    
por 09.04.2013 / 17:55
fonte
15

Acredito firmemente em manter lógica de negócios fora do banco de dados, tanto quanto possível. No entanto, como desenvolvedor de desempenho da minha empresa, eu aprecio que às vezes é necessário alcançar um bom desempenho. Mas acho que isso é necessário com muito menos frequência do que as pessoas afirmam.

Eu disputo seus prós e contras.

Você afirma que ele centraliza sua lógica de negócios. Pelo contrário, acho que descentraliza isso. Em um produto em que atualmente trabalho, usamos procedimentos armazenados para grande parte de nossa lógica de negócios. Muitos dos nossos problemas de desempenho vêm de chamar funções repetidamente. Por exemplo

select <whatever>
from group g
where fn_invoker_has_access_to_group(g.group_id)

O problema com essa abordagem é que geralmente (pode haver casos em que isso é falso) força o banco de dados a executar sua função N vezes, uma vez por linha. Às vezes essa função é cara. Alguns bancos de dados suportam índices de função. Mas você não pode indexar todas as funções possíveis contra todas as entradas possíveis. Ou você pode?

Uma solução comum para o problema acima é extrair a lógica da função e mesclá-la na consulta. Agora você quebrou o encapsulamento e a lógica duplicada.

Outro problema que vejo é chamar procedimentos armazenados em um loop porque não há como unir ou interceptar conjuntos de resultados de proc armazenados.

declare some_cursor
while some_cursor has rows
    exec some_other_proc
end

Se você puxar o código do proc aninhado, você descentraliza novamente. Portanto, você é forçado a escolher entre encapsulamento e desempenho.

Em geral, acho que os bancos de dados são ruins em:

  1. Computação
  2. Iteração (eles são otimizados para operações definidas)
  3. Balanceamento de carga
  4. Análise

Bancos de dados são bons em:

  1. Bloqueando e desbloqueando
  2. Mantendo dados e seus relacionamentos
  3. Garantindo a integridade

Ao adotar operações caras, como loops e análise de string e mantê-las na sua camada de aplicativo, você pode dimensionar horizontalmente seu aplicativo para obter melhor desempenho. Adicionar vários servidores de aplicativos atrás de um balanceador de carga geralmente é muito mais barato do que configurar a replicação de banco de dados.

Você está correto, no entanto, que desacopla sua lógica de negócios da linguagem de programação do aplicativo, mas não vejo por que isso é uma vantagem. Se você tem um aplicativo Java, então você tem um aplicativo Java. Converter um monte de código Java em procedimentos armazenados não altera o fato de você ter um aplicativo Java.

Minha preferência é manter o código do banco de dados focado na persistência. Como você cria um novo widget? Você deve inserir em 3 tabelas e elas devem estar em uma transação. Isso pertence a um procedimento armazenado.

Definir o que pode ser feito para um widget e as regras de negócios para encontrar widgets pertencem ao seu aplicativo.

    
por 09.04.2013 / 18:00
fonte
10

Eu trabalhei em duas empresas diferentes que tinham visão diferente sobre o assunto.

Minha sugestão pessoal seria usar Procedimentos Armazenados quando o tempo de execução for importante (desempenho). Como o Stored Procedure é compilado, se você tiver uma lógica complexa para consultar os dados, é melhor manter isso no próprio banco de dados. Além disso, ele só enviará os dados finais para o seu programa no final.

Caso contrário, acho que a lógica de um programa deve estar sempre no próprio software. Por quê? Porque um programa precisa ser testável e não acho que haja uma maneira fácil de testar o procedimento armazenado de unidade. Não se esqueça, um programa que não foi testado é um programa ruim.

Portanto, use o Stored Procedure com cuidado quando for necessário.

    
por 09.04.2013 / 17:20
fonte
9

Existe um meio-termo que você precisa encontrar. Eu vi projetos assustadores onde os programadores usam o banco de dados como nada mais do que um armazenamento de chave / valor superfaturado. Eu vi outros onde os programadores não conseguem usar chaves estrangeiras & índices. No outro extremo do espectro, vi projetos em que a maioria, senão toda a lógica de negócios, é implementada no código do banco de dados.

Como você observou, o T-SQL (ou seu equivalente em outros RDBMSs populares) não é exatamente o melhor lugar para codificar uma lógica de negócios complexa.

Eu tento criar um modelo de dados razoavelmente decente, usar recursos do banco de dados para proteger minhas suposições sobre esse modelo (ou seja, FKs e restrições) e usar o código do banco de dados com moderação. O código do banco de dados é útil quando você precisa de algo (ou seja, uma soma) que o banco de dados é muito bom em fazer e pode poupá-lo de mover um zilhão de registros sobre o fio quando você não precisa deles.

    
por 09.04.2013 / 17:17
fonte
8

Se a sua lógica de negócios envolve operações de conjunto, provavelmente um bom lugar para isso está no banco de dados, porque os sistemas de banco de dados são realmente bons em realizar operações de conjunto.

link

Se a lógica de negócios envolve algum tipo de cálculo, ela provavelmente pertence fora do procedimento de banco de dados / armazenamento, pois os bancos de dados não são realmente projetados para loop e cálculo.

Embora não sejam regras rígidas e rápidas, é um bom ponto de partida.

    
por 09.04.2013 / 17:29
fonte
5

Não há uma resposta certa para isso. Depende do que você usa o banco de dados. Em um aplicativo ENterprise, você pode invocar o banco de dados por meio de chaves estrangeiras, restrições e acionadores, etc., porque ele é o único local em que todos os aplicativos possíveis compartilham código. Além disso, colocar a lógica necessária no código geralmente significa que o banco de dados é inconsistente e os dados são de baixa qualidade. Isso pode parecer trivial para um desenvolvedor de aplicativos que só é útil com o funcionamento da GUI, mas garanto que as pessoas que tentam usar os dados em relatórios de conformidade acham muito irritante e caro quando recebem multas de bilhões de dólares por ter dados que não siga as regras corretamente.

Em um ambiente não-regulatório, quando você não se importa tanto com o conjunto de registros e apenas um ou dois aplicativos atingem o banco de dados, talvez você consiga manter tudo isso no aplicativo.

    
por 09.04.2013 / 23:25
fonte
3

Depois de alguns anos, a questão ainda é importante ...

Regra geral simples para mim: se é uma restrição lógica ou uma expressão onipresente (declaração única), coloque-a no banco de dados (sim, chaves estrangeiras e restrições de verificação também são lógica de negócios!). Se for processual, contendo loops e ramificações condicionais (e realmente não pode ser alterado em uma expressão), coloque-o no código.

Evite DBs de despejo de lixo

As tentativas de colocar toda a lógica de negócios no código do aplicativo provavelmente degeneram o banco de dados (relacional) em um lixo, onde o design relacional é quase totalmente omitido, onde os dados podem ter qualquer estado inconsistente e a normalização está ausente (geralmente Colunas de trashbin XML, JSON, CSV etc.).

Esse tipo de lógica somente de aplicação é provavelmente uma das principais razões para o surgimento do NoSQL - claro que com a desvantagem de o aplicativo ter que cuidar de toda a lógica em si, o que foi construído no banco de dados relacional por décadas . No entanto, os bancos de dados NoSQL são mais adequados para esse tipo de manipulação de dados, por exemplo, documentos de dados mantêm uma "integridade relacional" implícita em si mesmos. Para bancos de dados relacionais, é simplesmente abuso, causando ainda mais problemas.

Expressões (baseadas em conjunto) em vez de código de procedimento

No melhor dos casos, todas as consultas ou operações de dados devem ser codificadas como uma expressão, em vez de código de procedimento. Um ótimo suporte para isso é quando as linguagens de programação suportam expressões, como LINQ no mundo .NET (infelizmente, somente consultas atualmente, nenhuma manipulação). No lado do banco de dados relacional, aprendeu há muito tempo a preferir expressões de instrução SQL sobre loops de cursor procedurais. Assim, o banco de dados pode otimizar, fazer a operação paralela ou o que for útil.

Utilize os mecanismos de integridade de dados do banco de dados

Quando se trata de RDBMS com restrições de Chave Estrangeira e Verificação, colunas calculadas, possivelmente acionadores e visualizações, este é o local para armazenar a lógica de negócios básica no banco de dados. A normalização adequada ajuda a manter a integridade dos dados, para garantir uma instância única e distinta dos dados. Mesmo se você tiver que duplicá-lo no código e no banco de dados, esses mecanismos básicos de integridade de dados não devem ser omitidos!

Procedimentos armazenados?

Procedimentos armazenados raramente são necessários hoje em dia, já que os bancos de dados mantêm planos de execução compilados para o SQL e os reutilizam quando a mesma consulta vem novamente, apenas com diferentes parâmetros. Portanto, o argumento de pré-compilação para SPs não é mais válido. É possível armazenar ou gerar automaticamente consultas SQL no aplicativo ou no ORM, que localizará planos de consulta pré-compilados na maioria das vezes. SQL é uma linguagem de expressão, desde que você não use explicitamente elementos processuais. Então, no melhor dos casos, você usa expressões de código que podem ser traduzidas em SQL.

Enquanto o lado do aplicativo, incluindo ORM gerado, SQL, não está mais dentro do banco de dados, ao contrário de Stored Procedures, eu ainda o considero como código de banco de dados. Porque ainda requer conhecimento de SQL e banco de dados (exceto o CRUD mais simples) e, se aplicado corretamente, funciona muito diferente do código de procedimento normalmente criado com linguagens de programação como C # ou Java.

    
por 01.10.2016 / 15:06
fonte
2

Depende realmente do negócio, da cultura e do legado. Considerações técnicas à parte (estas foram cobertas de ambos os lados), as respostas dadas dizem que se trata de onde as pessoas estão vindo. Em algumas organizações, os dados são importantes e o DBA é uma figura poderosa. Este é o seu ambiente centralizado típico, um data center com vários terminais conectados a ele. A preferência neste tipo de ambiente é clara. A área de trabalho pode mudar radicalmente muitas vezes antes que algo mude no data center e haverá pouco tempo entre eles.

O outro extremo do espectro é a arquitetura pura de 3 camadas. Ou talvez multi-tier em uma empresa orientada para a web. Você provavelmente ouvirá uma história diferente aqui. O DBA, se houver algum, será apenas um sidekick que executa algumas tarefas administrativas.

Um desenvolvedor de aplicativos moderno terá mais afinidade com o segundo modelo. Se você cresceu com um grande sistema cliente-servidor, você provavelmente estaria no outro campo.

Muitas vezes há tantos fatores não-técnicos relacionados ao ambiente envolvidos aqui, que não há uma resposta geral para essa questão.

    
por 01.10.2016 / 19:40
fonte
2

O termo lógica de negócios está aberto à interpretação. Ao construir sistemas, queremos garantir a integridade do banco de dados e seu conteúdo. Como primeiro passo, deve haver diferentes concessões de acesso de usuário. Como um exemplo muito simples, vamos considerar uma aplicação ATM.

Para obter o saldo da conta, fazer um seleto em uma visualização apropriada deve ser concluído. Mas, para transferir fundos, você deseja que a transação seja encapsulada por um procedimento armazenado. A lógica de negócios não deve ter permissão para atualizar diretamente as tabelas para os valores de crédito e débito.

Neste exemplo, a lógica de negócios pode verificar o saldo antes de solicitar a transferência ou simplesmente invocar o procedimento armazenado para a transferência e relatar a falha. IMHO, a lógica de negócios, neste exemplo, deve verificar preventivamente que fundos suficientes estão disponíveis e que a conta de destino existe e só então invocar os fundos de transferência. Se outro débito ocorrer entre as etapas iniciais e a chamada do procedimento armazenado, somente um erro será retornado.

    
por 15.03.2017 / 01:30
fonte