Mejores prácticas para la serialización de agregados DDD

23

De acuerdo con la lógica de dominio DDD, no debe contaminarse con problemas técnicos como la serialización, el mapeo relacional de objetos, etc.

Entonces, ¿cómo serializa o mapea el estado de los agregados sin exponerlo públicamente a través de getters y setters? He visto muchos ejemplos para, por ejemplo, implementaciones de repositorio, pero prácticamente todos se basaron en accesores públicos en las entidades y objetos de valor para el mapeo.

Podríamos usar la reflexión para evitar los accesos públicos, pero IMO estos objetos de dominio aún dependerían implícitamente de la preocupación de serialización. Por ejemplo, no puede cambiar el nombre o eliminar un campo privado sin modificar su configuración de serialización / mapeo. Por lo tanto, debe considerar la serialización donde debería centrarse en la lógica de dominio.

Entonces, ¿cuál es el mejor compromiso a seguir aquí? ¿Vive con accesores públicos, pero evita usarlos para otra cosa que no sea el código de mapeo? ¿O acabo de perder algo obvio?

Estoy explícitamente interesado en serializar el estado de los objetos de dominio DDD (agregados que consisten en entidades y objetos de valor). Esto NO se trata de serialización en general o escenarios de script de transcripción donde los servicios sin estado operan en objetos de contenedor de datos simples.

ÁguilaPico
fuente

Respuestas:

12

Tipos de objetos

Para fines de nuestra discusión, separemos nuestros objetos en tres tipos diferentes:

Lógica de dominio empresarial

Estos son los objetos que hacen el trabajo. Mueven dinero de una cuenta corriente a otra, cumplen con los pedidos y todas las demás acciones que esperamos que tome el software comercial.

Los objetos lógicos de dominio normalmente no requieren accesores (captadores y establecedores). Más bien, crea el objeto entregándole dependencias a través de un constructor, y luego manipula el objeto a través de métodos (decir, no preguntar).

Objetos de transferencia de datos

Los objetos de transferencia de datos son de estado puro; No contienen ninguna lógica de negocios. Siempre tendrán accesores. Pueden o no tener setters, dependiendo de si los estás escribiendo o no de manera inmutable . Establecerá sus campos en el constructor y sus valores no cambiarán durante la vida útil del objeto, o sus accesos serán de lectura / escritura. En la práctica, estos objetos suelen ser mutables, de modo que un usuario puede editarlos.

Ver objetos del modelo

Los objetos Ver modelo contienen una representación de datos visualizable / editable. Pueden contener lógica empresarial, generalmente limitada a la validación de datos. Un ejemplo de un objeto Modelo de vista podría ser un Modelo de factura de factura, que contiene un objeto Cliente, un objeto Encabezado de factura y Líneas de pedido de factura. Los objetos Ver modelo siempre contienen accesores.

Entonces, el único tipo de objeto que será "puro" en el sentido de que no contiene accesores de campo será el objeto Logic de dominio. Serializar un objeto de este tipo guarda su "estado computacional" actual, de modo que pueda recuperarse más tarde para completar el procesamiento. Los modelos de visualización y los DTO se pueden serializar libremente, pero en la práctica sus datos normalmente se guardan en una base de datos.

Serialización, dependencias y acoplamiento.

Si bien es cierto que la serialización crea dependencias, en el sentido de que debe deserializarse a un objeto compatible, no necesariamente se deduce que deba cambiar su configuración de serialización. Los buenos mecanismos de serialización son de uso general; no les importa si cambia el nombre de una propiedad o miembro, siempre que pueda asignar valores a miembros. En la práctica, esto solo significa que debe volver a serializar la instancia del objeto para que la representación de serialización (xml, json, lo que sea) sea compatible con su nuevo objeto; No deberían ser necesarios cambios en la configuración del serializador.

Es cierto que los objetos no deberían preocuparse por cómo se serializan. Ya ha descrito una forma en que tales preocupaciones se pueden desacoplar de las clases de dominio: reflexión. Pero el serializador debería preocuparse por cómo serializa y deserializa objetos; esa, después de todo, es su función. La forma en que mantiene sus objetos desacoplados de su proceso de serialización es hacer que la serialización sea una función de propósito general , capaz de funcionar en todos los tipos de objetos.

Una de las cosas sobre las que la gente se confunde es que el desacoplamiento tiene que ocurrir en ambas direcciones. No es asi; solo tiene que trabajar en una dirección. En la práctica, nunca puedes desacoplar por completo; siempre hay algo de acoplamiento. El objetivo del acoplamiento flexible es facilitar el mantenimiento del código, no eliminar todas las dependencias.

Robert Harvey
fuente
Estoy de acuerdo con su punto de vista sobre el desacoplamiento. El serializador depende del objeto de dominio y eso está bien. Pero no al revés. Sin embargo, no estoy de acuerdo con su opinión sobre los accesos públicos en los objetos de dominio. En la práctica, a menudo los tienen, sí. Pero en mi opinión, sería preferible implementar la lógica de dominio en un diseño limpio orientado a objetos: decir, no preguntar . Pero aún necesita accesores para propósitos de mapeo (ORM, serialización, GUI ...). Y eso es lo que me gustaría evitar, si es posible.
EagleBeak
¿Cómo planea acceder a sus campos, si no tiene accesores?
Robert Harvey
En realidad, no me refiero a ninguno de los tres tipos de objetos que describe, sino a "agregados" en la terminología DDD y sus subobjetos (enidades, objetos de valor). Ahora me doy cuenta de que mi pregunta no era lo suficientemente explícita sobre esto. ¡Lo siento! Por favor vea mi edición arriba.
EagleBeak
1
Este es básicamente un problema no resuelto: no puede tener encapsulación, desacoplamiento y serialización \ codificación al mismo tiempo exponer DTO, es una forma de lograr un compromiso. Sin embargo, hay formas mucho menos intrusivas: yegor256.com/2016/07/06/data-transfer-object.html
Basilevs
1
Eso elimina la encapsulación, cualquiera puede implementar o usar la clase de amigo para leer los elementos internos del objeto.
Basilevs
-1

El propósito subyacente de la serialización es asegurar que los datos producidos por un sistema puedan ser consumidos por uno o más sistemas compatibles.

El enfoque más sencillo y robusto para la serialización es traducir los datos a un formato independiente del tipo que mantenga la estructura en un formato simple y fácil de consumir. Por ejemplo, los formatos de serialización más ubicuos (es decir, JSON, XML) utilizan un formato basado en texto bien definido. El texto es simple de producir, transmitir y consumir.

Hay 2 razones por las cuales usar uno de estos formatos puede no ser ideal.

  1. Eficiencia

    Hay un costo inherente involucrado en la traducción de todos los datos a sus equivalentes basados ​​en texto. Los tipos de datos no existirían si el texto fuera la forma más eficiente de expresar todas las diferentes formas de datos. Además, la estructura de estos formatos no es ideal para recuperar subconjuntos de datos de forma asincrónica o en partes.

    Por ejemplo, XML y JSON suponen que los datos que se utilizan se escribirán y leerán de principio a fin. Para procesar conjuntos de datos muy grandes donde la memoria es escasa, el sistema que consume los datos puede requerir la capacidad de procesar los datos en partes. En ese caso, se puede requerir una implementación de serialización / deserialización de propósito especial para manejar los datos.

  2. Precisión

    La conversión requerida para serializar / deserializar los datos de su tipo previsto al tipo agnóstico de datos da como resultado una pérdida de precisión.

Se podría argumentar que producir una representación binaria de los objetos y datos es claramente la solución más eficiente y precisa. El principal inconveniente es que la implementación de todos los sistemas que consumen y producen datos debe seguir siendo compatible. Es una restricción simple en teoría, pero es una pesadilla mantener en la práctica ya que los sistemas de producción tienden a cambiar / evolucionar con el tiempo.

Con eso dicho. El desacoplamiento de la serialización / deserialización de los detalles específicos del dominio tiene sentido como una regla general porque los formatos de propósito general son más robustos, mejor soportados en diversos sistemas y requieren poco o ningún aumento en la sobrecarga de mantenimiento para su uso.

Evan Plaice
fuente
Lo siento, pero esto no responde mi pregunta. Se trata de desacoplar los objetos de dominio de la serialización, no se trata de los motivos de la serialización o los pros y los contras de varios formatos. ¿Cómo serializo objetos de dominio sin exponer públicamente su estado privado?
EagleBeak
@EagleBeak Oh, no me di cuenta de que su preocupación era específicamente sobre el manejo de miembros privados. En su caso, podría serializar en binario (suponiendo que el sistema receptor siga las mismas reglas / estructura con las que se crearon los objetos de dominio) o escribir alguna lógica que extraiga solo los datos públicos antes de la serialización.
Evan Plaice
Creo que la suposición 'habitual' es que los datos que se serializan en un formato de propósito general (por ejemplo, xml, json) serán públicos y ese privilegio se controla a través de la API a través de ACL o algún otro equivalente. La serialización / deserialización de propósito general cae más en la línea de desacoplar datos de la lógica de negocios que va de un sistema a otro.
Evan Plaice
Estoy de acuerdo en que los accesores públicos se suponen generalmente en los objetos que se serializan. Pero aún me gustaría saber más sobre cómo esto se relaciona con DDD y su fuerte enfoque en la encapsulación de la lógica de dominio. ¿Todos los profesionales de DDD simplemente exponen el estado del modelo de dominio a través de los accesos públicos para la serialización (y nunca lo mencionan en sus ejemplos)? Lo dudo. Por favor, no me malinterpretes. Agradezco mucho tu aportación. Es solo que estoy interesado en un aspecto diferente. (Hasta ahora no creo que mi pregunta sea demasiado vaga, pero la respuesta de Robert Harvey y la suya me hicieron pensar en eso ...)
EagleBeak