Tener un Modelo de Dominio Separado y un Modelo de Persistencia en DDD


He estado leyendo sobre el diseño impulsado por dominio y cómo implementarlo mientras se usa el enfoque de código primero 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 sirve tanto como modelo de dominio como modelo de persistencia

  2. Tener 2 clases diferentes, una implementando la lógica de dominio y otra usada para un enfoque de código primero

Ahora sé que la opinión 1) se dice que simplifica 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 muchos problemas cuando las convenciones de un OR interfieren con el DDD.

Lo que me sorprende es que hay numerosos ejemplos de código de cómo implementar la opinión 1). Pero no he encontrado un solo ejemplo de cómo implementar la opinión 2) y cómo mapear los 2 objetos. (Probablemente hay tales ejemplos, pero no pude encontrar una C# uno)

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

Digamos que tengo un sistema de tickets y los tickets 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 usando Entity Framework como Entity se verá casi igual, pero a medida que la solución crezca, este 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 parece genial hasta ahora. Ahora lo que no estoy seguro es cuál es el mejor lugar para obtener un Ticket modelo de persistencia del repositorio y cómo asignarlo al modelo de dominio TicketEntity

He hecho esto 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 opinión 1) sería preferible a la opinión 2) que no sea acelerar el desarrollo y la reutilización de código.

  2. ¿Hay algún problema en mi enfoque de mapear los modelos? ¿Hay algo que me perdí que podría traer problemas cuando crece una solución?

Author: marc_s, 2014-07-11

3 answers

Hay alguna razón opinión 1) sería preferible a la opinión 2) que no sea acelerar el desarrollo y la reutilización de código.

La opción 1 es solo debido a la pereza pura y la velocidad de desarrollo aumentada imaginada. Es cierto que esas aplicaciones obtendrán la versión 1.0 construida más rápido. Pero cuando esos desarrolladores llegan a la versión 3.0 de la aplicación, no creen 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 OR.

¿Hay algún problema en mi enfoque de mapear los modelos? ¿Hay algo que me perdí que podría traer problemas cuando crece una solución?

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

El repositorio es responsable de hacer conversiones a/desde entidades de dominio (para poder persistirlas). Un método fetch normalmente usa ADO.NET o un Entity como Entity Framework para cargar el objeto/entidad de la base de datos. Luego conviértalo en la entidad comercial correcta y finalmente devuélvalo.

De lo contrario, obligaría a cada servicio a tener conocimiento sobre la persistencia Y el trabajo con su modelo de dominio, teniendo así dos responsabilidades.

Si trabaja con servicios de aplicaciones según la definición DDD, probablemente querrá ver el patrón de separación de comandos/consultas que puede ser un reemplazo de la aplicación Servicio. El código se vuelve más limpio y también obtienes una API mucho más liviana que envuelve tu modelo de dominio.

 21
Author: jgauffin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-12-29 15:23:20

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 tomar... Me gustaría hablar sobre este tema durante horas, pero resumiré mis pensamientos para usted:

1) Modelo de persistencia y 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á 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 Framework puede casi mantener sus modelos de dominio completamente libres de preocupaciones OR utilizando asignaciones fluidas.

Buenas piezas:

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

Partes malas:

  • Tal vez los desarrolladores comienzan a pensar dos veces antes de hacer un cambiar / refactorizar en el dominio temiendo 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, enfrentará algunas dificultades para mantener el dominio en armonía con el OR. Cuanto más cerca del dominio, más difícil será configurar el OR. Cuanto más cerca del OR, más sucio se vuelve el dominio.

2) Modelo de persistencia y dominio como dos cosas separadas

Te liberará para hacer lo que sea que quiere con su dominio. Sin miedo a refactorizaciones, sin limitaciones provinientes de provin y base de datos. Recomendaría este enfoque para los sistemas que se ocupan de una base de datos heredada o mal diseñada, algo que probablemente terminará arruinando su dominio.

Buenas piezas:

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

Malo partes:

  • Más esfuerzos con 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 principal y, créanme, lo que va a doler más: Perderá los beneficios principales de usar un OR! Como seguimiento de cambios. Tal vez termines usando frameworks como GraphDiff o incluso abandones OR y vayas al puro ADO.NET

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

Estoy de acuerdo con @jgauffin: "es en el repositorio donde debería tener lugar la asignación". De esta manera sus modelos de Persistencia nunca saldrán de la capa de Repositorio, en preferencia nadie debería ver esas entidades (a menos que el propio repositorio).

 6
Author: fabriciorissetto,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-04-03 20:47:41

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

Puedo ver uno grande (cosas obstinadas por delante) : no hay un "Modelo de Persistencia". Todo lo que tienes es un modelo relacional en tu base de datos y un modelo de objeto de dominio. El mapeo entre los dos es un conjunto de acciones, no estructuras de datos. Es más, esto es precisamente lo que se supone que deben hacer los OR.

La mayoría de los OR ahora apoyan lo que debería haber proporcionado desde el principio a una forma de declarar estas acciones directamente en 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 no persistence model = violating SRP and pisoteando DDD, porque muchas implementaciones que puede encontrar allí lo hacen. Pero no tiene que ser así.

 2
Author: guillaume31,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-07-22 12:12:36