¿Cuál es el uso de DTO en lugar de Entity?

18

Estoy trabajando en la aplicación RCP, soy nuevo en esta aplicación.

Los beans de primavera se utilizan para escribir lógica de negocios para guardar / recuperar entidades.

Pero, en lugar de enviar entidades directamente al cliente , estamos convirtiendo a DTO y completando el cliente. Mientras guardamos, nuevamente estamos convirtiendo DTO en entidad y guardando.

¿Cuál es el beneficio de estas conversiones? Alguien puede explicar?

Naveen Kocherla
fuente
What's the benefit of these conversions?desacoplar el modelo de datos de persistencia del modelo de datos (representación) ofrecido a los consumidores. Los beneficios del desacoplamiento se han discutido ampliamente en SE. Sin embargo, el objetivo debajo de los DTO es reunir en una sola respuesta tanta información como se considere necesaria para que los clientes guarden llamadas al servidor. Lo que hace que la comunicación cliente-servidor sea más fluida.
Laiv
Tu ejemplo es lindo. Cuando eres el cliente (vistas ...) es doloroso cambiar, pero el mayor problema es cuando el sistema ya tiene integraciones de terceros, eso es imposible de cambiar (contrato, tarifas ...). Si su sistema tendrá integración de terceros, alguna vez use DTO.
Lucas Gonçalves

Respuestas:

44

Cada vez que un desarrollador pregunta "¿cuál es el punto de hacer esto?", Lo que realmente quieren decir es "No veo ningún caso de uso en el que hacerlo proporcione un beneficio". Con ese fin, déjame mostrarte algunos ejemplos.


Todos los ejemplos se basarán en este modelo de datos simple:

Una Personentidad tiene cinco propiedades:Id, FirstName, LastName, Age, CityId

Y puede suponer que la aplicación utiliza estos datos de muchas maneras diferentes (informes, formularios, ventanas emergentes, ...).

Toda la aplicación ya existe. Todo lo que menciono es un cambio en la base de código existente. Esto es importante para recordar.


Ejemplo 1 - Cambiar la estructura de datos subyacente - Sin DTO

Los requisitos han cambiado. La edad de la persona debe recuperarse dinámicamente de la base de datos del gobierno (supongamos que se basa en su nombre y apellido).

Como ya no necesita almacenar el Agevalor localmente, por lo tanto, debe eliminarse de la Personentidad. Aquí es importante darse cuenta de que la entidad representa los datos de la base de datos , y nada más. Si no está en la base de datos, no está en la entidad.
Cuando recupera la antigüedad del servicio web del gobierno, se almacenará en un objeto diferente (o int).

Pero su interfaz aún muestra una edad. Todas las vistas se han configurado para usar la Person.Agepropiedad, que ahora ya no existe. Se presenta un problema: todas las vistas que se refieren a la Agede una persona necesitan ser reparadas .


Ejemplo 2 - Cambiar la estructura de datos subyacente - Con DTO

En el antiguo sistema, también hay PersonDTOentidades con los mismos cinco propiedades: Id, FirstName, LastName, Age, CityId. Después de recuperar a Person, la capa de servicio lo convierte en ay PersonDTOluego lo devuelve.

Pero ahora, los requisitos han cambiado. La edad de la persona debe recuperarse dinámicamente de la base de datos del gobierno (supongamos que se basa en su nombre y apellido).

Como ya no necesita almacenar el Agevalor localmente, por lo tanto, debe eliminarse de la Personentidad. Aquí es importante darse cuenta de que la entidad representa los datos de la base de datos , y nada más. Si no está en la base de datos, no está en la entidad.

Sin embargo, dado que tiene un intermediario PersonDTO, es importante ver que esta clase pueda conservar la Agepropiedad. La capa de servicio buscará Person, la convertirá en a PersonDTO, luego también buscará la edad de la persona del servicio web del gobierno, almacenará ese valor PersonDTO.Agey pasará ese objeto.

La parte importante aquí es que cualquiera que use la capa de servicio no ve una diferencia entre el sistema antiguo y el nuevo . Esto incluye su interfaz. En el sistema anterior, recibía un PersonDTOobjeto completo . Y en el nuevo sistema, todavía recibe un PersonDTOobjeto completo . Las vistas no necesitan ser actualizadas .

Esto es lo que queremos decir cuando usamos la frase separación de inquietudes : hay dos inquietudes diferentes (almacenar los datos en la base de datos, presentar los datos a la interfaz) y necesitan un tipo de datos diferente cada uno. Incluso si esos dos tipos de datos contienen los mismos datos en este momento, eso podría cambiar en el futuro.
En el ejemplo dado, Agehay una diferencia entre los dos tipos de datos: Person(la entidad de la base de datos) no necesita un Age, pero PersonDTO(el tipo de datos frontend) sí lo necesita.
Al separar las preocupaciones (= crear tipos de datos separados) desde el principio, la base de código es mucho más resistente a los cambios realizados en el modelo de datos.

Podría argumentar que tener un objeto DTO, cuando se agrega una nueva columna a la base de datos, significa que tiene que hacer un doble trabajo, agregando la propiedad tanto en la entidad como en el DTO. Eso es técnicamente correcto. Se requiere un poco de esfuerzo extra para mantener dos clases en lugar de una.

Sin embargo, debe comparar el esfuerzo requerido. Cuando se agregan una o más columnas nuevas, copiar / pegar algunas propiedades no toma tanto tiempo. Cuando el modelo de datos cambia estructuralmente, tener que cambiar la interfaz, posiblemente de formas que solo causen errores en tiempo de ejecución (y no en tiempo de compilación), requiere un esfuerzo considerablemente mayor y requiere que el desarrollador (s) busque errores.


Podría darte más ejemplos, pero el principio siempre será el mismo.

Para resumir

  • Las responsabilidades separadas (inquietudes) deben trabajar por separado una de la otra. No deben compartir ningún recurso, como clases de datos (p Person. Ej. )
  • El hecho de que una entidad y su DTO tengan las mismas propiedades no significa que deba fusionarlas en la misma entidad. No cortes esquinas.
    • Como un ejemplo más descarado, digamos que nuestra base de datos contiene países, canciones y personas. Todas estas entidades tienen a Name. Pero el hecho de que todos tengan una Namepropiedad no significa que debamos hacer que hereden de una EntityWithNameclase base compartida . Las diferentes Namepropiedades no tienen una relación significativa.
    • Si una de las propiedades vez cambia (por ejemplo, una canción del Nameconsigue a llamarse a Title, o una persona recibe un FirstNamee LastName), que se tendrá que invertir un mayor esfuerzo deshacer la herencia , que ni siquiera necesita en primer lugar .
    • Aunque no es tan evidente, su argumento de que no necesita un DTO cuando tiene una entidad es el mismo. Estás viendo el ahora , pero no te estás preparando para ningún cambio futuro. SI la entidad y el DTO son exactamente iguales, y SI puede garantizar que nunca habrá cambios en el modelo de datos; entonces tiene razón en que puede omitir el DTO. Pero la cuestión es que nunca puede garantizar que el modelo de datos nunca cambie.
  • Las buenas prácticas no siempre dan resultado de inmediato. Puede comenzar a dar sus frutos en el futuro, cuando necesite volver a visitar una aplicación anterior.
  • La principal causa de muerte de las bases de código existentes es dejar caer la calidad del código, lo que dificulta continuamente el mantenimiento de la base de código, hasta que se convierte en un desorden inútil de código de espagueti que no se puede mantener.
  • Las buenas prácticas, como la implementación de una separación de las preocupaciones con respecto al inicio, tienen como objetivo evitar esa pendiente resbaladiza de mal mantenimiento, a fin de mantener la base de código mantenible durante el mayor tiempo posible.

Como regla general para considerar las preocupaciones de separación, piense de esta manera:

Suponga que cada inquietud (la interfaz de usuario, la base de datos, la lógica) es manejada por una persona diferente en una ubicación diferente. Solo pueden comunicarse por correo electrónico.

En una base de código bien separada, un cambio a una preocupación particular solo deberá ser manejado por una persona:

  • Cambiar la interfaz de usuario solo implica el desarrollo de la interfaz de usuario.
  • Cambiar el método de almacenamiento de datos solo implica el desarrollo de la base de datos.
  • Cambiar la lógica de negocios solo involucra al desarrollador de negocios.

Si todos estos desarrolladores estuvieran usando la misma Personentidad, y se hiciera un cambio menor en la entidad, todos tendrían que participar en el proceso.

Pero al usar clases de datos separadas para cada capa, ese problema no es tan frecuente:

  • Mientras el desarrollador de la base de datos pueda devolver un PersonDTOobjeto válido , al desarrollador de negocios y de la interfaz de usuario no le importa que haya cambiado la forma en que se almacenan / recuperan los datos.
  • Mientras el desarrollador de negocios almacene los datos en la base de datos y proporcione los datos necesarios a la interfaz, a los desarrolladores de la base de datos y de la interfaz de usuario no les importa si decidió volver a trabajar sus reglas de negocio.
  • Siempre que la interfaz de usuario se pueda diseñar en función del `PersonViewModel, el desarrollador de la interfaz de usuario puede construir la interfaz de usuario como lo deseen. La base de datos y los desarrolladores de negocios no les importa cómo se hace, ya que no los afecta.

La frase clave aquí es que no les afecta . La implementación de una buena separación de preocupaciones busca minimizar el afectar (y por lo tanto tener que involucrar) a otras partes.

Por supuesto, algunos cambios importantes no pueden evitar incluir a más de una persona, por ejemplo, cuando se agrega una entidad completamente nueva a la base de datos. Pero no subestimes la cantidad de cambios menores que tienes que hacer durante la vida útil de una aplicación. Los cambios importantes son una minoría numérica.

Flater
fuente
Respuesta integral, gracias. Tengo preguntas; Aprecio si contestas: 1 - Corrígeme, si estoy equivocado. Business Object u View Object es para transferir datos entre Presentation Layer y Business Layer y Entity Object es para transferir datos entre Business Layer y Data Access Layer . y DTO se puede usar como un BO tonto. 2 - Supongamos que dos vistas necesitan información diferente de una empresa, entonces necesitamos dos DTO de empresa diferentes.
Arash el
1
@Arash (1) "DTO" es realmente una definición general para cualquier clase de datos que se utiliza para intercambiar entre dos capas. Un objeto de negocio y un objeto de vista son ambos DTO. (2) Eso depende mucho de muchas cosas. Crear una nueva DTO para cada colección de campos que necesita es una tarea engorrosa. No hay nada intrínsecamente malo en simplemente devolver un DTO completo de la empresa (cuando sea razonable) y luego dejar que la vista elija los campos en los que está interesado. Se trata de encontrar el equilibrio entre implementar una separación adecuada de las preocupaciones y evitar la ingeniería excesiva y la repetición sin sentido.
Flater
Ahora eso tiene sentido para mí. Muchas gracias. Flater.
Arash el
Una pregunta más. Dijiste "objeto comercial y un objeto de vista". Pensé que ambos son iguales. Cuando busqué, me di cuenta de que Business Object tiene un significado general para comparar con View Object . Pero Business Object debe derivarse del caso de uso y Entity Object debe derivarse del Data Model, por lo tanto, son diferentes, ¿estoy en lo cierto? ¿podrías explicarlo un poco, por favor?
Arash
@Arash: La diferencia entre lo que llama un "objeto comercial" y un "objeto de vista" es el contexto . Para nosotros los humanos, esa distinción es importante para entender las cosas correctamente. Pero el compilador (y por extensión el lenguaje en sí) no ve una diferencia técnica entre ellos. Cuando digo que son lo mismo, lo digo desde una perspectiva técnica. Ambos son solo una clase con propiedades destinadas a contener datos y ser transmitidos. En ese sentido, no hay diferencia entre ellos.
Flater