2008-12-18 12 views
10

El Diseño impulsado por el dominio lo alienta a utilizar un modelo de dominio enriquecido. Esto significa que toda la lógica de dominio se ubica en el modelo de dominio y que el modelo de dominio es supremo. La persistencia se convierte en una preocupación externa, ya que el modelo de dominio idealmente no sabe nada de persistencia (por ejemplo, la base de datos).Escala de un modelo de dominio enriquecido

He estado usando esto en la práctica en un proyecto de tamaño mediano (> 100k líneas de Java) y estoy descubriendo muchas ventajas, principalmente la flexibilidad y la refactoribilidad que esto ofrece sobre un enfoque orientado a bases de datos . Puedo agregar y eliminar clases de dominio, presionar algunos botones y se implementa un nuevo esquema de base de datos completo y capa SQL.

Sin embargo, a menudo me enfrento a problemas que me resulta difícil conciliar la rica lógica de dominio con el hecho de que hay una base de datos SQL que respalda la aplicación. En general, esto da como resultado el típico "problema de consultas 1 + N", donde se obtienen N objetos y luego se ejecuta un método no trivial en cada objeto que de nuevo activa consultas. Optimizar esto a mano le permite hacer el proceso en un número constante de consultas SQL.

En mi diseño, permito que un sistema conecte estas versiones optimizadas. Hago esto moviendo el código a un "módulo de consulta" que contiene docenas de consultas específicas de dominio (por ejemplo, getActiveUsers), de las cuales tengo ambas implementaciones en memoria (ingenua y no escalable) y basada en SQL (para uso de implementación). Esto me permite optimizar los puntos de acceso, pero hay dos inconvenientes principales:

  • estoy moviendo con eficacia algo de mi lógica de dominio a lugares donde no pertenece realmente, y de hecho incluso presionándolo en sentencias SQL .
  • El proceso requiere que examine detenidamente los registros de consulta para saber dónde están los puntos de acceso, después de lo cual tengo que refactorizar el código, reduciendo su abstracción de nivel al reducirlo a consultas.

¿Existe una manera mejor y más clara de conciliar Domain-Driven-Design y su Rich Domain Model con el hecho de que no puede tener todas sus entidades en memoria y por lo tanto están confinadas a un back-end de base de datos?

Respuesta

0

No, realmente no. No es que yo sepa de todos modos (aunque estoy interesado en escuchar las respuestas de los defensores de DDD en sentido contrario).

Según mi propia experiencia, y la del equipo con mucha experiencia con el que trabajo, si desea un rendimiento óptimo de una aplicación respaldada por una base de datos, la transformación de su arquitectura para estar orientada a servicios es inevitable. Escribí more about this here (el artículo habla de propiedades cargadas perezosas, pero podría considerar el punto para aplicarlo a cualquier método de la clase que necesite recuperar más datos para hacer su trabajo).

Tanto como lo está haciendo ahora, podría comenzar con un modelo de dominio enriquecido y transformarlo para que esté orientado al servicio cuando sea necesario por motivos de rendimiento. Mientras haya definido los objetivos de rendimiento y los esté cumpliendo, no hay necesidad de transformarlo todo. Creo que es un enfoque pragmático bastante decente.

+0

Supongo que un enfoque real de mejora fundamental requeriría un paradigma de lenguaje diferente, donde se describen partes de su lógica declarativamente para que pueda compilarse automáticamente en consultas ... pero este tipo de historia tiene su propia cuota de problemas: -) –

5

Hay al menos dos formas de ver este problema, una es una versión técnica de "qué puedo hacer para cargar mis datos más inteligente". Lo único realmente inteligente que conozco son las colecciones dinámicas que están parcialmente cargadas con el resto cargado a pedido, con la posible precarga de partes. Hubo una charla interesante en JavaZone 2008 about this

El segundo enfoque ha sido más de mi enfoque en el tiempo que he estado trabajando con DDD; ¿Cómo puedo hacer mi modelo para que sea más "cargable" sin sacrificar demasiado de la bondad DDD.Mi hipótesis a lo largo de los años siempre ha sido que muchos modelos de DDD modelan conceptos de dominio que en realidad son la suma de todos los estados de dominio permitidos, en todos los procesos comerciales y en los diferentes estados que ocurren en cada proceso de negocio a lo largo del tiempo. Creo que muchos de estos problemas de carga se reducen si los modelos de dominio se normalizan un poco más en términos de los procesos/estados. Esto generalmente significa que no existe un objeto "Orden" porque un ordrer típicamente existe en múltiples estados distintos que tienen una semántica bastante diferente (ShoppingCartOrder, ShippedOrder, InvoicedOrder, HistoricalOrder). Si intentas encapsular esto es un único objeto Order, invariablemente terminas con muchos problemas de carga/construcción.

Pero no hay bala de plata aquí ..

+0

Los problemas que describes se refieren principalmente a problemas de herencia, proxying y estado perezoso (al menos en mi contexto) y los he "solucionado" bastante para mi proyecto. Gracias por la sugerencia, pero realmente no veo cómo los cambios en la forma en que se expresa mi modelo pueden hacer una diferencia en mi problema. –

+0

Excepto por supuesto si hago menos datos calculados, y más datos almacenados explícitamente en los campos, pero eso es realmente una forma de desnormalización. –

+0

Creo que eso es válido; No he encontrado que las técnicas de modelado sean universalmente válidas. Muy a menudo puede elegir entre múltiples enfoques para el modelo de dominio, pero no siempre. – krosenvold

1

En mi experiencia, esto es la única manera de hacer las cosas. Si escribe un sistema que intenta ocultar o abstraer por completo la capa de persistencia, entonces no hay forma de que pueda optimizar las cosas usando los detalles de la capa de persistencia.

He estado enfrentando este problema recientemente y he estado trabajando en una solución donde las capas de persistencia pueden elegir implementar interfaces que representan optimizaciones. Acabo de jugar con él, pero para usar su ejemplo de ListAUsers dice así ...

Primero escriba un método ListAllUsers que hace todo en el nivel de dominio. Por un tiempo, esto funcionará, entonces comenzará a volverse demasiado lento.

Cuando se usa lentamente el modelo de dominio enriquecido, cree una interfaz llamada "IListActiveUsers" (o probablemente algo mejor). Y haga que su código de persistencia implemente esta interfaz usando las técnicas que sean apropiadas (probablemente SQL optimizado).

Ahora puede escribir una capa que compruebe estas interfaces y llame al método específico si existe.

Esto no es perfecto y no tengo mucha experiencia con este tipo de cosas. Pero me parece que la clave es garantizar que si está utilizando un método de persistencia totalmente ingenuo, entonces todo el código debería funcionar. Cualquier optimización debe hacerse como una adición a esto.

+0

Lo que describes es más o menos exactamente cómo lo hago. Excepto que mis consultas son métodos en una clase abstracta QueryModule, en lugar de pares separados de interfaz/implementación, pero eso realmente no es una gran diferencia.Al menos me siento menos solo ahora :-) –

+1

Udi Dahan habla sobre esta técnica en la siguiente presentación: http://www.infoq.com/presentations/Making-Roles-Explicit-Udi-Dahan –

0

Creo que debería considerar la capa de consulta como parte de la lógica de su dominio. Debe permitirse escribir consultas optimizadas que solo se pueden realizar con conocimiento "íntimo" de su solución de persistencia. No trates de abstraer todo. Además, el procesamiento por lotes es otra parte de su aplicación que también debe tener conocimiento de su dominio. Me parece innecesario tratar de evitar el procesamiento por lotes simplemente porque no puedo adaptarlo a mi modelo de dominio. Sin embargo, puede combinar los enfoques: use las consultas para descubrir qué objetos deben cambiar, luego ponga en cola sus identificadores y maneje cada uno por su cuenta, usando su lógica de dominio.

Cuestiones relacionadas