¿Cuánta lógica de negocios debe implementar la base de datos?

108

He trabajado en algunos proyectos donde la mayor parte de la lógica empresarial se implementó en la base de datos (principalmente a través de procedimientos almacenados). Por otro lado, he escuchado de algunos programadores compañeros que esta es una mala práctica ("Las bases de datos están ahí para almacenar datos. Las aplicaciones están ahí para hacer el resto").

¿Cuál de estos enfoques es generalmente mejor?

Las ventajas de implementar la lógica de negocios en la base de datos que se me ocurren son:

  • Centralización de la lógica de negocios;
  • Independencia del tipo de aplicación, lenguaje de programación, sistema operativo, etc.
  • Las bases de datos son menos propensas a la migración de tecnología o grandes refactorizaciones (AFAIK);
  • Sin modificaciones en la migración de la tecnología de la aplicación (por ejemplo: .NET a Java, Perl a Python, etc.).

Los contras:

  • SQL es menos productivo y más complejo para la programación de lógica de negocios, debido a la falta de bibliotecas y construcciones de lenguaje que ofrecen los lenguajes más orientados a aplicaciones;
  • Reutilización de código más difícil (si es posible) a través de bibliotecas;
  • IDE menos productivos.

Nota: Las bases de datos de las que estoy hablando son bases de datos relacionales y populares como SQL Server, Oracle, MySql, etc.

¡Gracias!

Rafael
fuente
3
Puede encontrar útil la respuesta a esta pregunta .
Blrfl
77
Este argumento ya ha sido debatido exhaustivamente . ¿Qué más podríamos agregar significativamente a la conversación aquí?
Robert Harvey
2
@gnat: Ni siquiera cerca.
Robert Harvey
77
Tenga en cuenta que la base de datos va a sobrevivir ( lejos ) a su aplicación. La base de datos podría incluso sobrevivir a la lengua de escribir su aplicación en. Los propios datos normalmente es el negocio, y la base de datos debe ser capaz de proteger la integridad de los datos que contiene. En ese sentido, cada restricción de clave externa es, francamente, la implementación de una regla comercial. A menos que se deshaga de todas las restricciones relacionales en su base de datos relacional, realmente no puede sacar completamente la lógica de negocios de la base de datos.
Craig

Respuestas:

83

La lógica empresarial no entra en la base de datos

Si hablamos de aplicaciones de varios niveles, parece bastante claro que la lógica de negocios, el tipo de inteligencia que ejecuta una empresa en particular, pertenece a la Capa de lógica de negocios, no a la Capa de acceso a datos.

Las bases de datos hacen algunas cosas realmente bien:

  1. Almacenan y recuperan datos.
  2. Establecen y aplican relaciones entre diferentes entidades de datos.
  3. Proporcionan los medios para consultar los datos en busca de respuestas.
  4. Proporcionan optimizaciones de rendimiento.
  5. Proporcionan control de acceso

Ahora, por supuesto, puede codificar todo tipo de cosas en una base de datos relacionadas con sus preocupaciones comerciales, como tasas impositivas, descuentos, códigos de operación, categorías, etc. Pero la acción comercial que se lleva a cabo con esos datos generalmente no se codifica en la base de datos, por todo tipo de razones ya mencionadas por otros, aunque se puede elegir una acción en la base de datos y ejecutarla en otro lugar.

Y, por supuesto, puede haber cosas que se realizan en una base de datos por rendimiento y otras razones:

  1. Cerrar un período contable
  2. Calculo de números
  3. Procesos por lotes nocturnos
  4. Conmutación por error

Naturalmente, nada está grabado en piedra. Los procedimientos almacenados son adecuados para una amplia gama de tareas simplemente porque viven en el servidor de bases de datos y tienen ciertas fortalezas y ventajas.

Procedimientos almacenados en todas partes

Hay un cierto atractivo para codificar todas sus tareas de almacenamiento, gestión y recuperación de datos en procedimientos almacenados, y simplemente consumir los servicios de datos resultantes. Sin duda, se beneficiaría del máximo rendimiento posible y las optimizaciones de seguridad que el servidor de la base de datos podría proporcionar, y eso no es poca cosa.

¿Pero qué arriesgas?

  1. Dependencia de un proveedor
  2. La necesidad de desarrolladores con habilidades especiales
  3. Herramientas de programación espartana, en general
  4. Acoplamiento de software extremadamente ajustado
  5. Sin separación de preocupaciones

Y, por supuesto, si necesita un servicio web (de todos modos, probablemente es a donde se dirige todo esto), todavía tendrá que construirlo.

Entonces, ¿cuál es la práctica típica?

Yo diría que un enfoque moderno y típico es usar un Mapeador Relacional de Objetos (como Entity Framework) para crear clases que modelen sus tablas. Luego puede hablar con su base de datos a través de un repositorio que devuelve colecciones de objetos, una situación que es muy familiar para cualquier desarrollador de software competente. El ORM genera dinámicamente SQL correspondiente a su modelo de datos y la información solicitada, que el servidor de la base de datos procesa para devolver los resultados de la consulta.

¿Qué tan bien funciona? Muy bien, y mucho más rápido que escribir procedimientos almacenados y vistas. Esto generalmente cubre alrededor del 80% de sus requisitos de acceso a datos, principalmente CRUD. ¿Qué cubre el otro 20%? Lo has adivinado: procedimientos almacenados, que todos los ORM principales admiten directamente.

¿Puedes escribir un generador de código que haga lo mismo que un ORM, pero con procedimientos almacenados? Seguro que puede. Pero los ORM generalmente son independientes del proveedor, bien entendidos por todos y mejor respaldados.

Robert Harvey
fuente
3
Gracias por tu gran respuesta, @Robert Harvey. Pero estaba pensando en el argumento del "bloqueo del proveedor": ¿no utilizar una tecnología en particular (por ejemplo, la pila .NET o Java) para construir una aplicación que también sea un bloqueo del proveedor? ¿O hay ventajas de un bloqueo de proveedor de pila orientado a la aplicación frente a un DB?
Raphael
3
@RobertHarvey, pero la parte de la lógica de la aplicación que está en .NET todavía está bloqueada en .NET. Lo mismo ocurre con PHP y Java.
Pacerier
2
@Pacerier: Por vendor-lockin, me refiero al proveedor de la base de datos. En la práctica real, la base de datos (y la pila de programación) rara vez se reemplazan.
Robert Harvey
2
@kai: Bueno, no puedes tener las dos cosas. O usas trozos y simulacros y vives con el hecho de que el examen es artificial, o escribes un examen que es realista y vives con un poco de retraso. Sin embargo, dudo que su compensación sea de 10 minutos frente a 30 segundos.
Robert Harvey
3
Tal vez tarde, pero soy de la opinión de que los procedimientos almacenados que implementan la lógica de negocios pertenecen a la capa de lógica de negocios, no a la capa de datos. Son una especie de idioma separado sin necesidad de ORM.
Paralife
16

Creo firmemente en mantener la lógica de negocios fuera de la base de datos tanto como sea posible. Sin embargo, como desarrollador de rendimiento de mi empresa, aprecio que a veces sea necesario lograr un buen rendimiento. Pero creo que es necesario con mucha menos frecuencia de lo que la gente dice.

Disputo tus pros y contras.

Afirma que centraliza su lógica empresarial. Por el contrario, creo que lo descentraliza. En un producto en el que actualmente trabajo, utilizamos procedimientos almacenados para gran parte de nuestra lógica empresarial. Muchos de nuestros problemas de rendimiento provienen de llamar a funciones repetidamente. Por ejemplo

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

El problema con este enfoque es que generalmente (puede haber casos en que esto sea falso) obliga a la base de datos a ejecutar su función N veces, una vez por fila. A veces esa función es cara. Algunas bases de datos admiten índices de funciones. Pero no puede indexar todas las funciones posibles contra cada entrada posible. O puedes?

Una solución común al problema anterior es extraer la lógica de la función y fusionarla en la consulta. Ahora ha roto la encapsulación y la lógica duplicada.

Otro problema que veo es llamar a procedimientos almacenados en un bucle porque no hay forma de unir o intersectar conjuntos de resultados de procesos almacenados.

declare some_cursor
while some_cursor has rows
    exec some_other_proc
end

Si extrae el código del proceso anidado, entonces vuelve a descentralizar. Por lo tanto, se ve obligado a elegir entre encapsulación y rendimiento.

En general, encuentro que las bases de datos son malas en:

  1. Cálculo
  2. Iteración (están optimizados para operaciones de configuración)
  3. Balanceo de carga
  4. Analizando

Las bases de datos son buenas en:

  1. Bloqueo y desbloqueo
  2. Mantenimiento de datos y sus relaciones.
  3. Asegurando integridad

Al realizar operaciones costosas como bucles y análisis de cadenas y mantenerlos en el nivel de su aplicación, puede escalar horizontalmente su aplicación para obtener un mejor rendimiento. Agregar múltiples servidores de aplicaciones detrás de un equilibrador de carga suele ser mucho más barato que configurar la replicación de la base de datos.

Sin embargo, tiene razón en que desacopla su lógica empresarial del lenguaje de programación de su aplicación, pero no veo por qué eso es una ventaja. Si tiene una aplicación Java, entonces tiene una aplicación Java. La conversión de un montón de código Java en procedimientos almacenados no cambia el hecho de que tenga una aplicación Java.

Mi preferencia es mantener el código de la base de datos enfocado en la persistencia. ¿Cómo se crea un nuevo widget? Debe insertar en 3 tablas y deben estar en una transacción. Eso pertenece a un procedimiento almacenado.

La definición de lo que se puede hacer a un widget y las reglas de negocio para encontrar widgets pertenece a su aplicación.

Brandon
fuente
8
En el servidor SQL, solo se deben llamar sps mal escritos en un bucle, puede enviarle conjuntos de datos en un parámetro y hacer un proceso basado en conjuntos.
HLGEM
2
SQL Server generará un plan de consulta subóptimo siempre que haya una UDF en una cláusula WHERE.
Jim G.
77
Parece que su problema de rendimiento no es culpa de la lógica en la base de datos frente a la aplicación ... solo está mal escrito y diseñado. Ese problema te seguirá en el mundo ORM de todos modos. Los ORM pueden ser un verdadero dolor de cabeza fuera de las operaciones CRUD. Si su sistema tiene muchos datos y un tipo de sistema de informes, tenga cuidado.
sam yi
Eso es verdad. La mayoría de nuestros problemas de rendimiento se deben simplemente a un código mal escrito y a una arquitectura demasiado compleja. Pero todavía creo que pusimos el tipo de trabajo incorrecto en nuestras bases de datos. Codificar tanto como sea posible en la base de datos nos ha hecho hacer cosas en las que una base de datos no es buena.
Brandon
1
Este ejemplo es incluso un argumento para colocar partes centrales de la lógica de negocios en la base de datos: para evitar el enfoque iterativo (código o bucles de cursor en lugar de expresiones basadas en conjuntos) como la peste. Los programadores tienden a tratar conjuntos de objetos de manera iterativa (bucle, recorrido), lo que probablemente conlleva cargas innecesarias o el problema SELECT N + 1 de muchos viajes de ida y vuelta de consulta única. Al utilizar SQL o expresiones basadas en el lenguaje (por ejemplo, LINQ), se verán obligados a utilizar un enfoque basado en conjuntos, siempre que sea posible.
Erik Hart
10

He trabajado en 2 compañías diferentes que tenían una visión diferente sobre el tema.

Mi sugerencia personal sería utilizar procedimientos almacenados cuando el tiempo de ejecución es importante (rendimiento). Dado que los procedimientos almacenados se compilan, si tiene una lógica compleja para consultar los datos, es mejor mantenerlos en la base de datos. Además, solo enviará los datos finales a su programa al final.

De lo contrario, creo que la lógica de un programa siempre debe estar en el propio software. ¿Por qué? Debido a que un programa debe ser comprobable y no creo que haya una manera fácil de probar un procedimiento almacenado. No olvide que un programa que no se prueba es un mal programa.

Por lo tanto, use el Procedimiento almacenado con precaución, cuando sea necesario.

Jean-François Côté
fuente
3
Los procedimientos almacenados son comprobables por unidad. Vea aquí algunas técnicas.
Robert Harvey
44
afaik, una prueba unitaria nunca usa base de datos o archivo. Entonces, técnicamente, "prueba unitaria" un procedimiento almacenado no es una prueba unitaria y será lento como el infierno. Un conjunto de pruebas unitarias debe ejecutarse en segundos (o tal vez minutos con una aplicación muy grande) en cualquier momento durante el desarrollo.
Jean-François Côté
1
El OP estaba hablando de "lógica de negocios" y la lógica de negocios debería ser probada por unidad. Al ponerlo en un procedimiento almacenado, lo mezcla con la consulta de la base de datos que ralentiza todo el proceso. Como dije, puede usar el Procedimiento almacenado (no es un delito) pero borrará la línea entre la lógica de negocios y la capa de la base de datos, lo cual es malo. Úselo con cuidado :)
Jean-François Côté
1
Si crea la base de datos y los objetos necesarios, la sp, la prueba y luego la derriba, es una prueba unitaria. Prueba una unidad de trabajo.
Tony Hopkinson el
2
¿No se ha desacreditado el aumento de rendimiento con el mito de los procedimientos almacenados?
JeffO
9

Hay un término medio que debes encontrar. He visto proyectos aterradores en los que los programadores usan la base de datos como nada más que un almacén de clave / valor demasiado caro. He visto otros en los que los programadores no usan claves e índices extranjeros. En el otro extremo del espectro, he visto proyectos en los que la mayoría, si no toda, la lógica empresarial se implementa en el código de la base de datos.

Como ha notado, T-SQL (o su equivalente en otros RDBMS populares) no es exactamente el mejor lugar para codificar una lógica empresarial compleja.

Trato de construir un modelo de datos razonablemente decente, utilizo características de la base de datos para proteger mis suposiciones sobre ese modelo (es decir, FK y restricciones), y uso el código de la base de datos con moderación. El código de la base de datos es útil cuando necesita algo (es decir, una suma) que la base de datos es muy buena para hacer y puede evitar que mueva millones de registros a través del cable cuando no los necesita.

Dan Pichelman
fuente
2
Usar la base de datos como un almacén de clave / valor "caro" es una técnica perfectamente válida, como lo atestiguarán las legiones de profesionales de NoSQL.
Robert Harvey
1
@RobertHarvey Obviamente tienes razón, pero de alguna manera mi instinto continúa insistiendo en que debe haber una solución más simple / más barata / más rápida que una base de datos si todo lo que necesitas es un almacén de clave / valor. Necesito aprender más sobre NoSQL.
Dan Pichelman
2
No veo el uso de procedimientos almacenados como una cura para una base de datos mal diseñada.
JeffO
2
@RobertHarvey, leí literalmente "almacén de clave / valor demasiado caro". Pagar una licencia de Oracle o SQL Server para algo así, cuando hay opciones como MongoDB disponibles de forma gratuita, parece desperdiciar dinero.
Raphael
@Raphael O podrías usar PostgreSQL 😉
Demi
9

Si su lógica de negocios involucra operaciones de conjuntos, lo más probable es que sea un buen lugar para ello en la base de datos porque los sistemas de bases de datos son realmente buenos para realizar operaciones de conjuntos.

http://en.wikipedia.org/wiki/Set_operations_(SQL)

Si la lógica de negocios implica algún tipo de cálculo, probablemente pertenezca fuera del procedimiento de la base de datos / tienda, ya que las bases de datos no están realmente diseñadas para realizar bucles y cálculos.

Aunque estas no son reglas duras y rápidas, es un buen punto de partida.

Jon Raynor
fuente
6

No hay una respuesta correcta para esto. Depende de para qué use la base de datos. En una aplicación empresarial, necesita la lógica en la base de datos a través de claves externas, restricciones, desencadenantes, etc. porque es el único lugar donde todas las aplicaciones posibles comparten código. Además, poner la lógica requerida en el código generalmente significa que la base de datos es inconsistente y los datos son de baja calidad. Eso puede parecer trivial para un desarrollador de aplicaciones que solo entiende cómo funciona la GUI, pero le aseguro que las personas que intentan usar los datos en los informes de cumplimiento lo encuentran muy molesto y costoso cuando reciben multas de mil millones de dólares por tener datos que no funcionan. No sigas las reglas correctamente.

En un entorno no regulatorio cuando no le importa tanto el conjunto completo de registros y solo una o dos aplicaciones llegan a la base de datos, tal vez pueda salirse con la suya manteniendo todo en la aplicación.

HLGEM
fuente
3

Después de unos años, la pregunta sigue siendo importante ...

Una regla general simple para mí: si se trata de una restricción lógica o una expresión ubicua (declaración única), colóquela en la base de datos (sí, ¡las claves externas y las restricciones de verificación también son lógicas comerciales!). Si es de procedimiento, al contener bucles y ramas condicionales (y realmente no se puede cambiar en una expresión), póngalo en código.

Evite los basureros de basura

Los intentos de colocar realmente toda la lógica empresarial en el código de la aplicación probablemente degenerarán la base de datos (relacional) en un basurero, donde el diseño relacional se omitirá por completo, donde los datos pueden tener un estado inconsistente y falta la normalización (a menudo principalmente XML, JSON , CSV, etc. columnas de basura).

Este tipo de lógica de solo aplicación es probablemente una de las principales razones del surgimiento de NoSQL, por supuesto, con la desventaja de que la aplicación tiene que ocuparse de toda la lógica en sí, lo que se ha incorporado en la base de datos relacional durante décadas. Sin embargo, las bases de datos NoSQL son más adecuadas para este tipo de manejo de datos, por ejemplo, los documentos de datos mantienen una "integridad relacional" implícita dentro de sí mismos. Para bases de datos relacionales, es simplemente abuso, causando aún más problemas.

Expresiones (basadas en conjuntos) en lugar de código de procedimiento

En el mejor de los casos, cada consulta u operación de datos debe codificarse como una expresión, en lugar de un código de procedimiento. Un gran soporte para esto es cuando los lenguajes de programación admiten expresiones, como LINQ en el mundo .NET (desafortunadamente, solo consultas actualmente, sin manipulación). En el lado de la base de datos relacional, se ha enseñado durante mucho tiempo a preferir expresiones de sentencias SQL en lugar de bucles de cursor de procedimiento. Por lo tanto, la base de datos puede optimizar, hacer la operación en paralelo o lo que sea útil.

Utilizar mecanismos de integridad de datos DB.

Cuando se trata de RDBMS con restricciones de clave externa y verificación, columnas calculadas, posiblemente disparadores y vistas, este es el lugar para almacenar la lógica empresarial básica en la base de datos. La normalización adecuada ayuda a mantener la integridad de los datos, para garantizar una instancia única y distinta de los datos. Incluso si tiene que duplicarlo en código y DB, ¡estos mecanismos básicos de integridad de datos no deben omitirse!

¿Procedimientos almacenados?

Los procedimientos almacenados son raramente necesarios hoy en día, ya que las bases de datos mantienen planes de ejecución compilados para SQL y los reutilizan cuando vuelve la misma consulta, solo con diferentes parámetros. Por lo tanto, el argumento de precompilación para SP ya no es válido. Uno puede almacenar o generar automáticamente consultas SQL en la aplicación u ORM, que encontrará planes de consulta precompilados la mayor parte del tiempo. SQL es un lenguaje de expresión, siempre que no utilice explícitamente elementos de procedimiento. Entonces, en el mejor de los casos, usa expresiones de código que se pueden traducir a SQL.

Si bien el lado de la aplicación, incluido ORM generado, SQL, ya no está dentro de la base de datos, a diferencia de los Procedimientos almacenados, todavía lo cuento como código de base de datos. Porque todavía requiere conocimientos de SQL y de la base de datos (excepto el CRUD más simple) y, si se aplica correctamente, funciona de manera muy diferente al código de procedimiento que generalmente se crea con lenguajes de programación como C # o Java.

Erik Hart
fuente
2

Realmente depende del negocio, su cultura y legado. Dejando a un lado las consideraciones técnicas (se han cubierto desde ambos lados), las respuestas dadas le dicen que se trata de dónde provienen las personas. En algunas organizaciones, los datos son el rey y el DBA es una figura poderosa. Este es su entorno centralizado típico, un centro de datos con un montón de terminales conectados. La preferencia en este tipo de entorno es clara. El escritorio puede cambiar radicalmente muchas veces antes de que algo cambie en el centro de datos y habrá poco en el medio.

El otro extremo del espectro es la arquitectura pura de 3 niveles. O tal vez de varios niveles en un negocio orientado a la web. Probablemente escucharás una historia diferente aquí. El DBA, si lo hay, será solo un compinche que realizará algunas tareas administrativas.

Un desarrollador de aplicaciones de los tiempos modernos tendrá más afinidad con el segundo modelo. Si creciste con un gran sistema cliente-servidor, probablemente estarías en el otro campamento.

A menudo hay tantos factores relacionados con el entorno no técnico involucrados aquí, que no hay una respuesta general a esta pregunta.

Martin Maat
fuente
2

El término lógica de negocios está abierto a interpretación. Al construir sistemas, queremos asegurar la integridad de la base de datos y sus contenidos. Como primer paso, debe haber diferentes concesiones de acceso de usuarios. Como un ejemplo muy simple, consideremos una aplicación de cajero automático.

Para obtener el saldo de la cuenta, debe hacer una selección en una vista adecuada. Pero para transferir fondos, desearía que la transacción se encapsule mediante un procedimiento almacenado. No se debe permitir que la lógica de negocios actualice directamente las tablas para los montos de crédito y débito.

En este ejemplo, la lógica de negocios podría verificar el saldo antes de solicitar la transferencia o simplemente invocar el proceso almacenado para la transferencia e informar la falla. En mi humilde opinión, la lógica de negocios, en este ejemplo, debería verificar de manera preventiva que hay suficientes fondos disponibles y que la cuenta objetivo existe y solo entonces invocar los fondos de transferencia. Si ocurre otro débito entre los pasos iniciales y la invocación de proceso almacenada, solo entonces se devolverá un error.

CyberFonic
fuente
Buen ejemplo y explicación.