¿Me equivoco al pensar que necesitar algo como AutoMapper es una indicación de un diseño deficiente?

35

Automapper es un "mapeador objeto-objeto" para .Net, lo que significa copiar objetos de una clase a otra clase que representa lo mismo.

¿Por qué es esto útil alguna vez? ¿La duplicación de clases es útil / buen diseño?

static_rtti
fuente
Una pequeña referencia: devtrends.co.uk/blog/… Lea especialmente la sección "¿por qué no podemos usar automapper?"
Jani Hyytiäinen

Respuestas:

28

Una búsqueda rápida en Google reveló este ejemplo:

http://www.codeproject.com/Articles/61629/AutoMapper

mostrando un uso perfectamente válido de AutoMapper que definitivamente no es un ejemplo para un diseño pobre. En una aplicación en capas, puede tener objetos en sus datos o en la capa empresarial, y a veces solo necesita un subconjunto de los atributos de esos objetos de datos, o algún tipo de vista en su capa de interfaz de usuario. Por lo tanto, crea un modelo de vista que contiene objetos con exactamente los atributos que necesita en su interfaz de usuario, no más, y usa AutoMapper para proporcionar el contenido de esos objetos con menos código repetitivo.

En tal situación, sus "objetos de vista" no son un duplicado de la clase original. Tienen diferentes métodos y quizás algunos atributos duplicados. Pero eso está bien siempre que use esos objetos de vista solo para fines de visualización de la interfaz de usuario y no comience a usarlos incorrectamente para la manipulación de datos u operaciones comerciales.

Otro tema que puede leer para comprenderlo mejor es el patrón de segregación de responsabilidad de consulta de comandos de Fowlers , en contraste con CRUD. Muestra situaciones en las que tienen sentido diferentes modelos de objetos para consultar datos y actualizarlos en una base de datos. Aquí, el mapeo de un modelo de objeto a otro también puede hacerse mediante una herramienta como AutoMapper.

Doc Brown
fuente
1
Con respecto a su primer ejemplo: ¿no podría componer objetos en lugar de duplicarlos? En ese caso, sus objetos de IU tendrían una referencia a sus objetos de datos originales y expondrían solo los elementos necesarios. ¿No tendría sentido?
static_rtti
1
@static_rtti en teoría sí, pero es posible que no desee que su clase original sea pública o expuesta en una asamblea
Jalayn
2
@static_rtti: sí, ese es un enfoque perfectamente válido y diferente. La principal diferencia entre esos dos diseños es la vida útil de los datos / atributos. El uso de copias le proporciona una instantánea de los datos, y las propiedades que hacen referencia a los datos originales no lo hacen. Ambos enfoques tienen sus pros y sus contras, pero en mi humilde opinión no hay "mejor o peor" en general. Además, puede haber consideraciones de rendimiento, que pueden o no influir en la decisión de qué usar.
Doc Brown
3
Desacoplar tanto como sea posible siempre es una buena idea. No porque sea particularmente beneficioso incluso para proyectos pequeños, sino porque los proyectos crecen.
Tamás Szelei
66
@fish: Estoy de acuerdo en su mayoría, el desacoplamiento a menudo es una buena idea, pero en mi humilde opinión, hay suficientes situaciones en las que mantener las cosas simples supera un enfoque de múltiples capas súper desacopladas por el motivo del desacoplamiento. La parte difícil es no perder el punto durante el crecimiento de un proyecto cuando uno debe comenzar a refactorizar.
Doc Brown
45

¿La duplicación de clases es útil / buen diseño?

Es una buena práctica tener una clase de modelo de vista separada para usar en la capa de IU en lugar de usar la misma clase que se usa en la capa de datos. Su UI / página web puede necesitar mostrar otros bits de información que no están estrictamente relacionados con la entidad de datos. Al crear esta clase adicional, te estás dando la libertad de modificar tu IU fácilmente a medida que los requisitos cambian con el tiempo.

En cuanto al uso de AutoMapper, personalmente lo evito por 3 razones:

Fallas silenciosas más comunes

Debido a que AutoMapper asigna automáticamente entre las propiedades, cambiar un nombre de propiedad en una clase y no en la otra hará que se omita la asignación de propiedades. El compilador no lo sabrá. A Automapper no le importará.

Falta de análisis estático.

Entonces se le ha dado una gran base de código para tratar. Hay un millón de clases con un millón de propiedades. Parece que no se usan o son duplicados. Esa herramienta "Buscar todas las referencias" en Visual Studio lo ayudará a ver dónde se usan las propiedades y ayudará a construir un mapa en su cabeza de cómo se cuelga toda la aplicación. Pero espere, no hay referencias explícitas a la mitad de las propiedades porque se está utilizando Automapper. Mi trabajo ahora es mucho más difícil.

Requisitos tardíos que aumentan la complejidad

Automapper está muy bien cuando todo lo que quiere hacer es copiar los valores de UNA clase a otra (como suele ser el caso al INICIO del desarrollo), pero ¿recuerda esos requisitos que cambian con el tiempo? ¿Qué sucede si ahora necesita obtener valores de otras partes de su aplicación, quizás específicos del usuario que inició sesión o algún otro estado contextual?

El patrón de AutoMapper de crear las asignaciones de clase uno a uno al inicio de la aplicación no se presta bien a este tipo de cambios específicos de contexto. Sí, probablemente hay formas de hacerlo funcionar, pero generalmente me parece más limpio, más simple y más expresivo escribir la lógica yo mismo.

En resumen, antes de buscar Automapper para ahorrarse 30 segundos de asignar manualmente una clase a otra, piense en esto.

La programación es el arte de decirle a otro humano lo que uno quiere que haga la computadora. - Donald Knuth

Con esto en mente, pregúntese "¿AutoMapper es útil hoy y será mañana?"

Dave B 84
fuente
[si hace un desarrollo web moderno] Entonces, si está escribiendo un servicio web REST, ¿tiende a verificar siempre todas y cada una de las propiedades para asegurarse de que su modelo de objetos JavaScript sea coherente con su modelo de objetos .NET?
Den
3
@ Den - sí. Y escribe pruebas para asegurarse de obtener todas las propiedades correctas (es decir, su prueba mostrará las propiedades que ha agregado en 1 lugar que no se propagan a los otros niveles)
gbjbaanb
@gbjbaanb Probablemente usaría la reflexión para hacer esta validación de forma genérica. Quizás explore la posibilidad de extender AutoMapper para agregar alguna validación. Definitivamente evitaría muchas asignaciones manuales.
Den
Totalmente de acuerdo con usted y cree que solo las aplicaciones muy simples pueden usar automapper, pero cuando las cosas se vuelven más complejas necesitamos escribir una nueva configuración para automapper, entonces ¿por qué no escribirlas en un asistente o servicio de mapeo manual?
ahmedsafan86
21

En mi experiencia, cuando alguien se ha quejado de "demasiado repetitivo" y quiere usar AutoMapper, ha sido uno de los siguientes:

  1. Les resulta irritante escribir el mismo código una y otra vez.
  2. Son flojos y no quieren escribir código que haga Ax = Bx
  3. Están bajo demasiada presión de tiempo para pensar si escribir Ax = Bx una y otra vez es una buena idea y luego escribir un buen código para la tarea.

Sin embargo:

  1. Si realmente se trata de evitar la repetición, puede crear un objeto o método para abstraerlo. No necesitas AutoMapper.
  2. Si eres flojo, serás flojo y no aprenderás cómo funciona AutoMapper. En su lugar, adoptará el patrón de 'programación por coincidencia' y escribirá un código horrible donde inserta la lógica de negocios en un perfil de AutoMapper. En este caso, debe cambiar su actitud hacia la programación o buscar algo más que hacer como profesión. No necesitas AutoMapper.
  3. Si tiene demasiada presión de tiempo, su problema no tiene nada que ver con la programación misma. No necesitas AutoMapper.

Si ha elegido un idioma estático, aproveche el idioma. Si está intentando eludir los controles en el lenguaje que ayudan a evitar errores debido al uso excesivo de API de reflexión y magia como AutoMapper, solo significa que ha elegido un lenguaje que no es satisfactorio para sus necesidades.

Además, el hecho de que Microsoft haya agregado características a C # no significa que sean un juego justo en todas las situaciones o que admitan las mejores prácticas. La reflexión y la palabra clave "dinámica", por ejemplo, deben usarse en casos en los que simplemente no puede lograr lo que necesita sin ellas. AutoMapper no es una solución para ningún caso de uso que no pueda resolverse sin él.

Entonces, ¿la duplicación de clases es un mal diseño? No necesariamente.

¿AutoMapper es una mala idea? Si, absolutamente.

El uso de AutoMapper indica deficiencias sistémicas en el proyecto. Si lo necesita, deténgase y piense en su diseño. Siempre encontrará un diseño mejor, más legible, más fácil de mantener y más libre de errores.

Shashi Penumarthy
fuente
1
Bien dicho, particularmente 2.
Mardoxx
2
Sé que este es un hilo muy antiguo, pero tengo que estar en desacuerdo con 1. No se puede hacer un método para el mapeo abstracto. Puede para 1 clase, pero si tiene 2, necesita 2 métodos. 3 - 3 métodos. Con AM, esta es una línea de código: definición de mapeo. Además, realmente luché con un escenario, donde tenía un List <BaseType> lleno de 10 subtipos DTO. Cuando desee asignar eso, necesita un interruptor de tipo Y un método para copiar valores de campo. ¿Y qué pasa si uno de los campos tiene que ser mapeado por separado? Su respuesta solo es buena si tiene pocas clases simples. AutoMapper gana manos abajo en escenarios más complejos.
user3512524
1
(límite de char) Creo que la única trampa de AM es la posibilidad de cambiar el nombre de la propiedad en una clase y no en la otra. Pero realmente, ¿con qué frecuencia haces eso después de que el diseño está hecho? Y puede escribir un método de prueba genérico que use reflexión y compare nombres de propiedades. Como todas las herramientas, AM tiene que usarse correctamente, no a ciegas, no en todas las situaciones, estoy de acuerdo. Pero decir "no deberías usarlo" es simplemente incorrecto.
user3512524
7

Aquí hay un problema más profundo: el hecho de que C # y Java insisten en que la mayoría / todos los tipos deben distinguirse por nombre en lugar de estructura: por ejemplo, class MyPoint2Dy class YourPoint2Dson tipos separados incluso si tienen las mismas definiciones exactas. Cuando el tipo que desea es "algo anónimo con un xcampo y un ycampo" (es decir, un registro ), no tiene suerte. Entonces, cuando quieras convertir un YourPoint2Da MyPoint2D, tienes tres opciones:

  1. Escribe algunas repeticiones aburridas, repetitivas y mundanas en la línea de this.x = that.x; this.y = that.y
  2. Genera el código de alguna manera.
  3. Usa la reflexión.

La opción 1 es bastante fácil en pequeñas dosis, pero rápidamente se convierte en una tarea cuando la cantidad de tipos que necesita mapear es grande.

La opción 2 es menos que deseable porque ahora tiene que agregar un paso adicional a su proceso de compilación para generar el código y asegurarse de que todo el equipo reciba la nota. En el peor de los casos, también debe rodar su propio generador de códigos o sistema de plantillas.

Eso te deja con la reflexión. Puede hacerlo usted mismo o puede usar AutoMapper.

Doval
fuente
3

Automapper es una de esas bibliotecas / herramientas donde el emperador está literalmente corriendo desnudo. Cuando pasa el logo deslumbrante, se da cuenta de que no hace nada que no pueda hacer manualmente con mejores resultados.

Si bien no estoy completamente seguro de cómo insinúa a los miembros de mapeo automático, lo más probable es que implique una lógica de tiempo de ejecución adicional y una posible reflexión. Esto puede ser una penalización de rendimiento significativa a cambio de un ahorro de tiempo. El mapeo manual, por otro lado, la sugerencia se ejecuta mucho antes del tiempo de compilación.

En los casos en que AutoMapper no tiene idea, debe configurar la asignación con código y establecer banderas. Si va a molestarse en hacer todo el trabajo de configuración y código, debe preguntarse cuánto ahorra con el mapeo manual.

usuario148298
fuente