Archivo por meses: marzo 2014

El uso de Data Transfer Objects (DTO’s)

En muchas de nuestras aplicaciones, estamos usando ORM cómo Entity Framework. Los objetos (clases) de nuestra modelo E/R (DB) son mapeados mediante un modelo orientado objeto que representa sus relaciones físicas en formato lógico.

Estos objetos, que se pueden abstraer cómo entidades POCO de este ORM, pueden llegar a contener muchas relaciones entre los diferentes objetos dependiendo de la complejidad de nuestro modelo E/R.

En las tecnologías visibles para nuestros usuarios, es decir, las interfaces de usuario (UI) cómo puede ser ASP.NET MVC, Aplicaciones móviles… entre otros, necesitamos dar una experiencia rica, ágil y rápida teniendo en cuenta que en muchas ocasiones nuestro modelo de datos es complejo y la interfaz del usuario es sencilla.

Justo en este momento es dónde entran en contexto los Objeto de transferencia de datos (DTO con sus siglas en inglés) dónde nace (no es nuevo, este concepto lleva años con nosotros pero gana peso en las aplicaciones actuales :)) con el objetivo de minimizar el coste de la comunicación entre procesos y por lo tanto, la transferencia de datos entre estos en cada una de sus llamadas cliente – servidor minimizando así su tiempo de respuesta y transportando únicamente los datos necesarios para la operación destino.

La diferencia entre los objetos DTO y los objetos de negocio es que los primeros únicamente tienen el comportamiento de transformar los datos desde el origen y entregar los datos a su destino. Estos objetos son simples y sin lógica de negocio, es decir, son objetos que no están contenidos en nuestro dominio si no que se nutren de su resultado.

A la conclusión que podemos llegar es que si usamos las entidades POCO cómo DTO nos saltamos justo la S (SPR) de los principios SOLID que os explicava en un anterior post y le damos 2 responsabilidades diferentes a nuestro objeto: sirve de entidad del ORM y por otro de transferencia de datos.

Además darle dos responsabilidades a un objeto, obligas a que los procesos envíen gran parte la información que almacenas en la base de datos, y quizá solo hace falta una parte de esa información. Y con eso estarás enviando demasiada o poca información creando procesos muy poco eficientes.

¿Cuándo se debe usar DTO?
– Cuándo debamos reducir el nombre de llamadas al servidor.
– Cuándo debamos considerar el rendimiento y la latencia de las comunicaciones de la red.
– Cuándo debamos minimizar la transferéncia de datos.

¿Cómo se usan los DTO?
Los DTO no son mas que clases sencillas con propiedades get y set. Estas clases son llenadas en desde la capa de aplicación que estas obtienen los datos desde el repositorio a través de una llamada a nuestra DB.

Los DTO deben ser definidos en una librería a parte dentro de nuestro dominio pero sin formar parte de él pues carecen de comportamiento y en una capa superior, dónde recibimos la respuesta de la aplicación, debemos realizar la conversión de nuestra respuesta de entidad POCO a nuestro DTO.

Para ello podemos usar diferentes métodos pero en .NET y con las últimas versiones podemos usar dos formas de hacer esta conversión,
– La primera de ellas es mediante Automapper que es una librería que es capaz de convertir un objeto a otro mediante un mapeo (Lo podéis instalar mediante Nugget). Si en ambos objetos, las propiedades get y set tienen el mismo nombre, el mapeo es muy sencillo pero si no, nos permite manejar esa conversión de forma muy sencilla.

public static ContactDto Binding(Contact contact)
{
  ContactDto contactDto = new ContactDto();
  Mapper.CreateMap<Contact, ContactDto>()
        .ForMember(c => c.Name, dto => dto.MapFrom(co => co.Person.Name))
        .ForMember(c => c.FirstName, dto => dto.MapFrom(co => co.Person.FirstName))
        .ForMember(c => c.LastName, dto => dto.MapFrom(co => co.Person.LastName))
        .ForMember(c => c.Gender, dto => dto.MapFrom(co => co.Person.Gender))
        .ForMember(c => c.IdPerson, dto => dto.MapFrom(co => co.Person.IdPerson))
        .IgnoreAllNonExisting();
  Mapper.AssertConfigurationIsValid();
  contactDto = Mapper.Map<Contact, ContactDto>(contact);
  return contactDto;
}

A grandes rasgos, lo que nos permite hacer el objeto Mapper es crear un mapeo entre dos clases (Contact y ContactDto), le indicamos mediante .ForMember cómo debe ser la conversión (solo es necesario si es diferente) y le indicamos que IgnoreAllNonExisting, es decir, que no mapea lo que no exista. Finalmente hacemos un AssertConfigurationIsValid  que nos devuelve una excepción si no puede hacer la conversión.

Para terminar, hacemos el Map y obtenemos nuestro DTO con los datos que vamos a usar o representar y descartamos el resto.
En otro post, explicaré cómo usar Automapper a fondo pues da para escribir más de un post.

– La segunda de ellas, es mediante una consulta Linq to Objects y escojer que queremos devolver y que no.

var report = await _ourLayerApplication
.Contact
.Where(cnt => cnt.SequenceNumber == contactCode)
.Select(cnt => new ContactDTO
{
  Name = cnt.Person.Name,
  FirstName = cnt.Person.FirstName,
  LastName = cnt.Person.LastName,
  Gender = cnt.Person.Gender,
  IdPerson = cnt.Person.IdPerson
}).SingleOrDefaultAsync();

¿Cuál usar?
Personalmente, ambas formas nos proporcionan la misma potencia aunque al estar contextualizado en el entorno de EF y .NET la segunda forma no necesita del uso de librerías de terceros y la primera, debemos usar una librería externa y que a nivel de rendimiento, no nos oferecerá el mismo rendimiento que una consulta Linq to objects nativa de .NET.

En todo caso y resumiendo, lo que no debemos hacer es devolver los objetos obtenidos mediante consultas a la DB si usamos ORM cómo EF pues contienen sus relaciones y estas, pueden ser complejas, pesadas y transmitir datos que no son necesarios para nuestra aplicación, sobretodo, si su destino son entornos que deben ser fluidos cómo la web, el cloud y las app.

A desarrollar :)
Saludos!