quickly por orientada impulsado example ejemplo driven dominio domain diseƱo ddd arquitectura c# orm architecture domain-driven-design domain-model

c# - por - domain driven design pdf



Tener modelo de dominio separado y modelo de persistencia en DDD (3)

¿Hay alguna razón por la cual la opinión 1) sería preferible a la opinión 2) distinta de acelerar el desarrollo y reutilizar el código?

La opción 1 es simplemente por la pereza pura y la mayor velocidad de desarrollo imaginada. Es cierto que esas aplicaciones tendrán la versión 1.0 más rápida. Pero cuando esos desarrolladores alcanzan la versión 3.0 de la aplicación, no piensan que sea tan divertido mantener la aplicación debido a todos los compromisos que han tenido que hacer en el modelo de dominio debido al mapeador ORM.

¿Hay algún problema en mi enfoque de mapeo de los modelos? ¿Hay algo que eché de menos que plantearía problemas cuando crezca una solución?

Sí. El repositorio debe ser responsable de ocultar el mecanismo de persistencia. Su API solo debería funcionar con entidades de dominio y no con entidades de persistencia.

El repositorio es responsable de realizar conversiones a / desde entidades de dominio (para poder mantenerlas). Un método fetch generalmente usa ADO.NET o un ORM como Entity Framework para cargar el objeto / entidad de la base de datos. Luego, conviértalo en la entidad empresarial correcta y finalmente devuélvelo.

De lo contrario, obligaría a todos los servicios a tener conocimiento sobre la persistencia Y a trabajar con su modelo de dominio, teniendo así dos responsabilidades.

Si trabaja con servicios de aplicaciones según la definición de DDD, probablemente quiera observar el patrón de separación Comando / Consulta que puede ser un reemplazo de los servicios de la aplicación. El código se vuelve más limpio y también obtienes una API mucho más ligera que engloba tu modelo de dominio.

He estado leyendo acerca del diseño impulsado por el dominio y cómo implementarlo al usar el primer enfoque del código para generar una base de datos. De lo que he leído e investigado, hay dos opiniones sobre este tema:

  1. Tener 1 clase que sirva tanto como modelo de dominio como de persistencia

  2. Tener 2 clases diferentes, una que implementa la lógica de dominio y otra que se usa para un enfoque de primer código

Ahora sé que la opinión 1) simplifica las pequeñas soluciones que no tienen muchas diferencias entre el dominio y los modelos de persistencia, pero creo que rompe el principio de responsabilidad única y por eso introduce una gran cantidad de problemas cuando las convenciones de un ORM interfieren con DDD.

Lo que es una sorpresa para mí es que hay numerosos ejemplos de código sobre cómo implementar la opinión 1). Pero no hemos encontrado un solo ejemplo de cómo implementar la opinión 2) y cómo mapear los 2 objetos. (Probablemente hay ejemplos, pero no pude encontrar uno de C #)

Así que traté de implementar un ejemplo yo solo, pero no estoy seguro si esa es una buena manera de hacerlo.

Digamos que tengo un sistema de tickets y las entradas tienen fecha de vencimiento. Mi modelo de dominio se verá así:

/// <summary> /// Domain Model /// </summary> public class TicketEntity { public int Id { get; private set; } public decimal Cost { get; private set; } public DateTime ExpiryDate { get; private set; } public TicketEntity(int id, decimal cost, DateTime expiryDate) { this.Id = id; this.Cost = cost; this.ExpiryDate = expiryDate; } public bool IsTicketExpired() { if (DateTime.Now > this.ExpiryDate) { return true; } else { return false; } } }

El modelo de persistencia que usa Entity Framework como ORM se verá casi igual, pero a medida que la solución crezca, podría no ser el caso.

/// <summary> /// ORM code first Persistence Model /// </summary> public class Ticket { [Key] public int Id { get; set; } public decimal Cost { get; set; } public DateTime ExpiryDate { get; set; } }

Todo se ve muy bien hasta ahora. Ahora, de lo que no estoy seguro es de cuál es el mejor lugar para obtener un modelo de persistencia de Ticket del repositorio y cómo TicketEntity modelo de dominio TicketEntity

Lo he hecho en una capa de aplicación / servicio.

public class ApplicationService { private ITicketsRepository ticketsRepository; public ApplicationService(ITicketsRepository ticketsRepository) { this.ticketsRepository = ticketsRepository; } public bool IsTicketExpired(int ticketId) { Ticket persistanceModel = this.ticketsRepository.GetById(ticketId); TicketEntity domainModel = new TicketEntity( persistanceModel.Id, persistanceModel.Cost, persistanceModel.ExpiryDate); return domainModel.IsTicketExpired(); } }

Mis preguntas son:

  1. ¿Hay alguna razón por la cual la opinión 1) sería preferible a la opinión 2) distinta de acelerar el desarrollo y reutilizar el código?

  2. ¿Hay algún problema en mi enfoque de mapeo de los modelos? ¿Hay algo que eché de menos que plantearía problemas cuando crezca una solución?


¿Hay alguna razón por la cual la opinión 1) sería preferible a la opinión 2) distinta de acelerar el desarrollo y reutilizar el código?

Puedo ver uno grande (cosas obstinadas por delante): no hay un "Modelo de persistencia". Todo lo que tiene es un modelo relacional en su base de datos y un modelo de objeto de Dominio. El mapeo entre los dos es un conjunto de acciones, no estructuras de datos . Además, esto es precisamente lo que se supone que deben hacer los ORM.

La mayoría de los ORM ahora admiten lo que deberían haber proporcionado desde el principio, una forma de declarar estas acciones directamente en el código sin tocar las entidades de su dominio. Las configuraciones fluidas de Entity Framework, por ejemplo, le permiten hacer eso.

Puede tener la impresión de que ningún modelo de persistencia = violación de SRP y pisoteo en DDD, porque muchas implementaciones que puede encontrar allí sí lo hacen. Pero no tiene que ser así.


Me metí en este dilema este año en un gran proyecto en el que estaba trabajando y fue una decisión muy difícil de hacer ... Me gustaría hablar sobre este tema durante horas, pero voy a resumir mis ideas para usted:

1) Persistencia y modelo de dominio como la misma cosa

Si está en un proyecto nuevo con una base de datos diseñada desde cero para él, probablemente sugeriría esta opción. Sí, el dominio y su conocimiento sobre él cambiarán constantemente y esto exigirá una refactorización que afectará su base de datos, pero creo que en la mayoría de los casos vale la pena.

Con Entity Framework como su ORM, casi puede mantener sus modelos de dominio libres de preocupaciones ORM utilizando asignaciones fluidas .

Buenas partes:

  • Rápido, fácil, hermoso (si la base de datos está diseñada para ese problema)

Partes malas

  • Tal vez los desarrolladores comiencen a pensar dos veces antes para hacer un cambio / refactorización en el dominio por temor a que afecte a la base de datos. Este miedo no es bueno para el dominio.
  • Si el dominio comienza a divergir demasiado de la base de datos, tendrá algunas dificultades para mantener el dominio en armonía con el ORM. Cuanto más cerca del dominio, más difícil es configurar el ORM. Cuanto más cerca del ORM, más sucio es el dominio.

2) Persistencia y modelo de dominio como dos cosas separadas

Le dará la libertad de hacer lo que quiera con su dominio. Sin miedo a refactorizaciones, sin limitaciones provinciales de ORM y base de datos. Recomiendo este enfoque para los sistemas que se ocupan de una base de datos heredada o mal diseñada, algo que probablemente termine arruinando su dominio.

Buenas partes:

  • Completamente gratis para refactorizar el dominio
  • Será fácil profundizar en otros temas de DDD como Bounded Context .

Partes malas

  • Más esfuerzos con las conversiones de datos entre las capas. El tiempo de desarrollo (tal vez también el tiempo de ejecución) será más lento.

  • Pero el director y, créame, lo que le dolerá más: ¡perderá los beneficios principales de usar un ORM! Me gusta seguir los cambios . Tal vez termine usando frameworks como GraphDiff o incluso abandone ORM''s y vaya a ADO.NET puro.

¿Hay algún problema en mi enfoque de mapeo de los modelos?

Estoy de acuerdo con @jgauffin: "está en el repositorio que el mapeo debería tener lugar" . De esta forma, sus modelos de Persistencia nunca saldrán de la capa Repositorio, de preferencia nadie debería ver esas entidades (a menos que el repositorio mismo).