Me estoy sumergiendo en el diseño impulsado por dominio (DDD) y, aunque profundizo en él, hay algunas cosas que no entiendo. Según tengo entendido, un punto principal es dividir la lógica de dominio (lógica de negocios) de la infraestructura (DB, sistema de archivos, etc.).
Lo que me pregunto es, ¿qué sucede cuando tengo consultas muy complejas, como una consulta de cálculo de recursos materiales? En ese tipo de consulta trabajas con operaciones de conjuntos pesados, el tipo de cosas para las que SQL fue diseñado. Hacer esos cálculos dentro de la capa de dominio y trabajar con muchos conjuntos es como descartar la tecnología SQL.
Hacer estos cálculos en la infraestructura no puede suceder también, porque el patrón DDD permite cambios en la infraestructura sin cambiar la capa de dominio y sabiendo que MongoDB no tiene las mismas capacidades de, por ejemplo, SQL Server, eso no puede suceder.
¿Es eso una trampa del patrón DDD?
fuente
... is like throwing away the SQL technology
El hecho de que una tecnología en particular pueda hacer algo no significa que sea la mejor opción. Es una evidencia anecdótica, pero he conocido demasiadas empresas que solían almacenar la lógica empresarial en la base de datos y están migrando lejos de ella debido a los dolores de cabeza de mantenimiento a largo plazo que causa. Simplificando demasiado, pero las bases de datos están destinadas a almacenar datos y los lenguajes de programación están destinados a transformar datos. No me gustaría usar una base de datos para la lógica de negocios más de lo que me gustaría tratar de usar mi aplicación para almacenar mis datos directamente.Respuestas:
En estos días, es probable que vea lecturas (consultas) manejadas de manera diferente que escrituras (comandos). En un sistema con una consulta complicada, es poco probable que la consulta pase por el modelo de dominio (que es el principal responsable de mantener la consistencia de las escrituras ).
Tiene toda la razón en que deberíamos representar a SQL lo que es SQL. Por lo tanto, diseñaremos un modelo de datos optimizado en torno a las lecturas, y una consulta de ese modelo de datos generalmente tomará una ruta de código que no incluye el modelo de dominio (con la posible excepción de alguna validación de entrada, asegurando que los parámetros en la consulta son razonables)
fuente
Esta es la base del malentendido: el propósito de DDD no es separar las cosas a lo largo de una línea dura como "esto está en el servidor SQL, por lo que no debe ser BL", el propósito de DDD es separar dominios y crear barreras entre aquellos que permiten que los elementos internos de un dominio estén completamente separados de los elementos internos de otro dominio, y que definan elementos externos compartidos entre ellos.
No piense en "estar en SQL" como la barrera BL / DL, eso no es lo que es. En cambio, piense en "este es el fin del dominio interno" como la barrera.
Cada dominio debe tener API externas que le permitan trabajar con todos los demás dominios: en el caso de la capa de almacenamiento de datos , debe tener acciones de lectura / escritura (CRUD) para los objetos de datos que almacena. Esto significa que SQL en sí no es realmente la barrera, lo son los componentes
VIEW
yPROCEDURE
. Nunca debe leer directamente de la tabla: ese es el detalle de implementación que DDD nos dice que, como consumidor externo, no deberíamos preocuparnos.Considera tu ejemplo:
Esto es exactamente lo que debería estar en SQL entonces, y no es una violación de DDD. Es para lo que hicimos DDD . Con ese cálculo en SQL, eso se convierte en parte de BL / DL. Lo que debería hacer es usar una vista separada / procedimiento almacenado / lo que tenga, y mantener la lógica de negocios separada de la capa de datos, ya que esa es su API externa. De hecho, su capa de datos debe ser otra capa de dominio DDD, donde su capa de datos tiene sus propias abstracciones para trabajar con las otras capas de dominio.
Ese es otro malentendido: dice que los detalles de implementación internamente pueden cambiar sin cambiar otras capas de dominio. No dice que puede reemplazar una pieza de infraestructura completa.
Nuevamente, tenga en cuenta que DDD se trata de ocultar elementos internos con API externas bien definidas. La ubicación de esas API es una pregunta totalmente diferente, y DDD no define eso. Simplemente define que estas API existen y que nunca deberían cambiar .
DDD no está configurado para permitirle reemplazar ad-hoc MSSQL con MongoDB; esos son dos componentes de infraestructura totalmente diferentes.
En cambio, usemos una analogía para lo que DDD define: autos de gasolina versus eléctricos. Ambos vehículos tienen dos métodos completamente diferentes para crear propulsión, pero tienen los mismos API: un encendido / apagado, un acelerador / freno y ruedas para impulsar el vehículo. DDD dice que deberíamos poder reemplazar el motor (gas o eléctrico) en nuestro automóvil. No dice que podamos reemplazar el automóvil con una motocicleta, y eso es efectivamente lo que es MSSQL → MongoDB.
fuente
Si alguna vez ha estado en un proyecto donde la organización que paga para alojar la aplicación decide que las licencias de la capa de base de datos son demasiado caras, apreciará la facilidad con la que puede migrar su base de datos / almacenamiento de datos. A fin de cuentas, si bien esto sucede, no sucede a menudo .
Puedes obtener lo mejor de ambos mundos, por así decirlo. Si considera realizar las funciones complejas de la base de datos como una optimización, puede usar una interfaz para inyectar una implementación alternativa del cálculo. El problema es que debe mantener la lógica en varias ubicaciones.
Desviarse de un patrón arquitectónico
Cuando se encuentre en desacuerdo con la implementación de un patrón puramente, o con una desviación en alguna área, entonces tiene que tomar una decisión. Un patrón es simplemente una forma de hacer cosas para ayudar a organizar su proyecto. En este punto, tome tiempo para evaluar:
Encontrará que algunos patrones arquitectónicos se ajustan bien al 80-90% de su aplicación, pero no tanto para los bits restantes. La desviación ocasional del patrón prescrito es útil por razones de rendimiento o logísticas.
Sin embargo, si encuentra que sus desviaciones acumulativas representan más del 20% de la arquitectura de su aplicación, probablemente sea un mal ajuste.
Si elige continuar con la arquitectura, hágase un favor y documente dónde y por qué se desvió de la forma prescrita de hacer las cosas. Cuando obtenga un nuevo miembro entusiasta en su equipo, puede indicarle esa documentación que incluye las mediciones de rendimiento y las justificaciones. Eso reducirá la probabilidad de que se repitan solicitudes para solucionar el "problema". Esa documentación también ayudará a desincentivar las desviaciones desenfrenadas.
fuente
La lógica de manipulación de conjuntos en la que SQL es bueno puede integrarse con DDD sin problemas.
Digamos, por ejemplo, que necesito saber algún valor agregado, recuento total de productos por tipo. Fácil de ejecutar en sql, pero lento si cargo todos los productos en la memoria y los agrego a todos.
Simplemente presento un nuevo objeto de dominio,
y un método en mi repositorio
Claro, tal vez ahora estoy confiando en que mi DB tenga ciertas habilidades. Pero técnicamente todavía tengo la separación y mientras la lógica sea simple, puedo argumentar que no es 'lógica de negocios'
fuente
Query
como parámetros.repository.find(query);
. He leído lo mismo pero conSpecs. That opens a door to leave
Query` como abstracción y /QueryImpl
o la implementación de consultas específicas para la capa de infraestructura.I know some people do that
Algunas personas son fundamentales y su marco. SpringFramework tiene mucho de esto :-). De todos modos, como ha sugerido @VoiceOfUnreason, la clave en torno a DDD es mantener la consistencia de los escritos. No estoy seguro de forzar el diseño con modelos de dominio cuyo único propósito es consultar o parametrizar consultas. Eso podría abordarse fuera del dominio con estructuras de datos (pocos, pojos, dtos, mapeadores de filas, lo que sea).Una de las formas posibles de resolver este dilema es pensar en SQL como un lenguaje ensamblador: rara vez, si es que lo hace, codifica directamente en él, pero cuando el rendimiento es importante, debe ser capaz de comprender el código producido por su C / C ++ / Golang / Rust compilador y tal vez incluso escribir un pequeño fragmento en el ensamblaje, si no puede cambiar el código en su lenguaje de alto nivel para producir el código de máquina deseado.
Del mismo modo, en el ámbito de las bases de datos y SQL, varias bibliotecas de SQL (algunas de las cuales son ORM ), por ejemplo, SQLAlchemy y Django ORM para Python, LINQ para .NET, proporcionan abstracciones de nivel superior pero utilizan código SQL generado cuando sea posible para lograr el rendimiento. También proporcionan cierta portabilidad en cuanto a la base de datos utilizada, posiblemente con un rendimiento diferente, por ejemplo, en Postgres y MySQL, debido a algunas operaciones que utilizan un SQL específico de base de datos más óptimo.
Y al igual que con los lenguajes de alto nivel, es fundamental comprender cómo funciona SQL, incluso si solo se trata de reorganizar las consultas realizadas con las bibliotecas SQL mencionadas anteriormente, para poder lograr la eficiencia deseada.
PD: Prefiero hacer de esto un comentario, pero no tengo suficiente reputación para eso.
fuente
Como de costumbre, esta es una de esas cosas que depende de varios factores. Es cierto que hay mucho que puedes hacer con SQL. También existen desafíos con su uso y algunas limitaciones prácticas de las bases de datos relacionales.
Como Jared Goguen señala en los comentarios, SQL puede ser muy difícil de probar y verificar. Los principales factores que conducen a esto son que no puede (en general) descomponerse en componentes. En la práctica, una consulta compleja debe considerarse in toto. Otro factor complicado es que el comportamiento y la corrección de SQL dependen en gran medida de la estructura y el contenido de sus datos. Esto significa que probar todos los escenarios posibles (o incluso determinar cuáles son) a menudo es inviable o imposible. La refactorización de SQL y la modificación de la estructura de la base de datos también es problemática.
El otro gran factor que ha llevado a alejarse de SQL es que las bases de datos relacionales tienden a escalar solo verticalmente. Por ejemplo, cuando crea cálculos complejos en SQL para ejecutarlos en SQL Server, se ejecutarán en la base de datos. Eso significa que todo ese trabajo está utilizando recursos en la base de datos. Cuanto más haga en SQL, más recursos necesitará su base de datos tanto en términos de memoria como de CPU. A menudo es menos eficiente hacer estas cosas en otros sistemas, pero no hay un límite práctico para la cantidad de máquinas adicionales que puede agregar a dicha solución. Este enfoque es menos costoso y más tolerante a fallas que construir un servidor de base de datos monstruoso.
Estos problemas pueden o no aplicarse al problema en cuestión. Si puede resolver su problema con los recursos de base de datos disponibles, tal vez SQL esté bien para su espacio de problemas. Sin embargo, debe considerar el crecimiento. Puede que esté bien hoy, pero dentro de unos años, el costo de agregar recursos adicionales puede convertirse en un problema.
fuente
Permítanme primero aclarar algunos conceptos erróneos.
DDD no es un patrón. Y en realidad no prescribe patrones.
El prefacio del libro DDD de Eric Evan dice:
Por lo tanto, es una forma de abordar el desarrollo de software y el modelado de dominios, además de un vocabulario técnico que respalda esas actividades (un vocabulario que incluye varios conceptos y patrones). Tampoco es algo completamente nuevo.
Otra cosa a tener en cuenta es que un modelo de dominio no es la implementación OO del mismo que se puede encontrar en su sistema, esa es solo una forma de expresarlo o expresar alguna parte de él. Un modelo de dominio es la forma en que piensa sobre el problema que está tratando de resolver con el software. Es cómo entiendes y percibes las cosas, cómo hablas de ellas. Es conceptual . Pero no en un sentido vago. Es profundo y refinado, y es el resultado del trabajo duro y la recopilación de conocimientos. Se refina aún más y probablemente evolucionó con el tiempo, e implica consideraciones de implementación (algunas de las cuales pueden restringir el modelo). Debe ser compartido por todos los miembros del equipo. (y expertos en dominios involucrados), y debería conducir la forma en que implementa el sistema, para que el sistema lo refleje de cerca.
Nada de eso es inherentemente pro o anti-SQL, aunque los desarrolladores de OO son quizás generalmente mejores para expresar el modelo en lenguajes de OO, y la expresión de muchos conceptos de dominio está mejor respaldada por OOP. Pero a veces partes del modelo deben expresarse en un paradigma diferente.
Bueno, en general, hay dos escenarios aquí.
En el primer caso, algún aspecto de un dominio realmente requiere una consulta compleja, y tal vez ese aspecto se exprese mejor en el paradigma SQL / relacional, así que use la herramienta adecuada para el trabajo. Refleje esos aspectos en su pensamiento de dominio y el lenguaje utilizado en la comunicación de conceptos. Si el dominio es complejo, tal vez sea parte de un subdominio con su propio contexto acotado.
El otro escenario es que la necesidad percibida de expresar algo en SQL es el resultado de un pensamiento restringido. Si una persona o un equipo siempre han estado orientados a la base de datos en su pensamiento, puede ser difícil para ellos, solo debido a la inercia, ver una forma diferente de abordar las cosas. Esto se convierte en un problema cuando la vieja forma no satisface las nuevas necesidades y requiere un poco de pensamiento fuera de la caja. DDD, como un enfoque para el diseño, se trata en parte de formas de salir de esa caja reuniendo y destilando el conocimiento sobre el dominio. Pero todo el mundo parece ignorar esa parte del libro, y se enfoca en algunos de los vocabulario y patrones técnicos enumerados.
fuente
La secuela se hizo popular cuando la memoria era costosa, porque el modelo de datos relacionales brindaba la posibilidad de normalizar sus datos y almacenarlos efectivamente en el sistema de archivos.
Ahora la memoria es relativamente barata, por lo que podemos omitir la normalización y almacenarla en el formato que la usamos o incluso duplicar una gran cantidad de datos por razones de velocidad.
Considere la base de datos como un simple dispositivo IO , cuya responsabilidad es almacenar datos en el sistema de archivos; sí, sé que es difícil imaginarlo, porque escribimos muchas aplicaciones con lógica comercial importante escrita en consultas SQL, pero solo trate de imaginar ese SQL Server Es solo otra impresora.
¿Incrustaría el generador de PDF en el controlador de la impresora o agregaría un activador que imprima la página de registro para cada pedido de venta impreso desde nuestra impresora?
Supongo que la respuesta será no, porque no queremos que nuestra aplicación esté acoplada al tipo de dispositivo específico (ni siquiera hablando de la eficiencia de tal idea)
En los años 70-90, la base de datos SQL era eficiente, ¿ahora? - No estoy seguro, en algunos escenarios, la consulta asíncrona de datos devolverá los datos requeridos más rápido que las combinaciones múltiples en la consulta SQL.
SQL no fue diseñado para consultas complicadas, fue diseñado para almacenar datos de manera eficiente y luego proporcionar interfaz / lenguaje para consultar datos almacenados.
Yo diría que construir su aplicación alrededor del modelo de datos relacionales con consultas complicadas es abuso del motor de base de datos. Por supuesto, los proveedores de motores de bases de datos están contentos cuando acoplas estrechamente tu negocio a su producto; estarán más que felices de proporcionar más funciones que fortalezcan este límite.
fuente