Marcelo Daniel Toledo

Marcelo Daniel Toledo

Software Developer | Licenciado en Informática

Volver a Artículos
#1 21 de abr de 2026

Automapper, tu lección me salió cara

Autor

Marcelo Daniel Toledo

#.NET #Anécdota #Refactor #Dependencias
4 min de lectura
¡Link copiado!

Automapper, tu lección me salió cara

La otra vez un desarrollador me mostró una librería que generaba unos dashboards increíbles para React, me preguntó si debería implementarla. Los gráficos eran hermosos, las animaciones fluidas, todo muy pulido. Pero lo primero que hice fue ir directo a la sección de licencia. Sí, ofrecía varios planes. Le expliqué lo costoso que puede ser agregar una dependencia externa para algo que, con un poco de esfuerzo, podés resolver vos mismo.

Terminó la charla y me quedé pensando. No en React ni en dashboards, sino en eso: en normalizar lo que molesta porque “funciona”. Tengo varios proyectos en producción que llevan años tirando warnings de AutoMapper.

Creo que nos sucedió lo mismo a todos los que estamos hace tiempo en el ecosistema .NET, muy seguramente conozcas (y utilizaste) bibliotecas como Automapper, MediatR, etc. Era la parejita de cualquier guía de “Mejora los mapeos en .NET con esta herramienta” o “Implementa CQRS de manera sencilla”. Bueno, hace un tiempo su autor eligió convertirlas a uso bajo licencia comercial, lo que me parece correcto y no es el tema principal del artículo.

Esto me hizo pensar en algo que sabemos pero a veces pasamos por alto por tiempo; las dependencias externas, para el caso de los mapeos quizás unos años atrás se justificaba, convengamos que a nadie le gustaba realizar miles de mapeos manuales de muchos objetos. Pero estamos en 2026, donde un LLM genera esos mapeos en segundos. El argumento de “es muy tedioso hacerlo a mano” ya no se sostiene.

Reemplazar un clavo… ¿con otro clavo?

Mi primer impulso fue buscar alternativas y benchmarks. Porque claro, uno siempre busca esa librería nueva y mejor, no?

Automapper vs Manual Assignment

Bueno, en este caso fue el momento de frenar, y pensar. Si la rueda es sencilla, no me molesta reinventarla si reducimos el riesgo de dependencia externa. Los mapeos manuales no son tan complejos como suenan, no necesitás otra librería para mapear de A a B. Y con IA generativa, esas tareas que antes te quitaban horas las resolvés en minutos. La misma tecnología que usamos para resolver código nos saca la excusa de depender de otra librería para algo tan básico.

Ok, mapeos manuales. ¿Y el mantenimiento?

“El desarrollo inicial se hace una vez, el mantenimiento es para siempre”, acá surge quizás el principal miedo ante cualquier modificación que debamos realizar, ¿y si agrego una propiedad y me olvido de mapearla? Vamos con tests usando reflection!

using System.Reflection;
using FluentAssertions;
using Xunit;

public class MappingTests
{
    [Fact]
    public void UserDto_ShouldHaveAllPropertiesFrom_User()
    {
        // 1. Definimos los tipos que queremos comparar
        var entityType = typeof(User);
        var dtoType = typeof(UserDto);
        // 2. Obtenemos las propiedades de la Entidad (Origen)
        var entityProperties = entityType.GetProperties(BindingFlags.Public | BindingFlags.Instance)
                                         .Select(p => p.Name)
                                         .ToList();
        // 3. Obtenemos las propiedades del DTO (Destino)
        var dtoProperties = dtoType.GetProperties(BindingFlags.Public | BindingFlags.Instance)
                                   .Select(p => p.Name)
                                   .ToList();
        // 4. Comparamos (En este caso, que el DTO contenga todo lo de la Entidad)
        // Si agregas "Age" a la Entidad y olvidas el DTO, el test falla.
        dtoProperties.Should().Contain(entityProperties,
            "porque el DTO debe estar sincronizado con la entidad de dominio");
    }
}

Si hay campos que sabes que no deben estar en el DTO, creas una lista de excepciones para filtrar:

var excludeList = new[] { "PasswordHash", "SecretKey" };
var filteredEntityProps = entityProperties.Except(excludeList);

Listo, nos aseguramos de no mandarnos macanas en el mantenimiento, pero vamos al reemplazo.

Mi plan

Y acá decidí no repetir el mismo error con otra herramienta.

Con un producto en producción y la cantidad de mapeos que tenía el proyecto, no era momento de tirar código a ver qué pasa. Vengo usando Spec-Driven Development hace rato y me siento cómodo con eso — así que primero: documentar todo. Qué mappings existían, qué comportamiento debía mantenerse, qué no podía romperse. Después sí, código.

El plan fue este:

  1. Auditar todos los mapeos existentes (Profiles + estáticos)
  2. Clasificarlos por categoría (Dominio↔DTO, External Service, etc.)
  3. Detectar y planificar resolución de violaciones arquitectónicas
  4. Por “use case” (aprovechando la estructura del proyecto): a. Escribir tests que capturen el comportamiento ACTUAL b. Implementar el mapeo manual c. Eliminar el Profile correspondiente d. Verificar que los tests pasen
  5. Finalmente: remover Automapper del proyecto
PR: remove automapper

Lo que más me sorprendió no fue la cantidad de mapeos, sino lo que había adentro. Algunos profiles escondían lógica de negocio que no tenía nada que hacer ahí. Reglas de negocio disfrazadas de mapeos, que nadie revisaba porque “total AutoMapper lo maneja”. AutoMapper era conveniente, sí. Pero también era un muy buen lugar para esconder cosas.

Ah, me olvidaba!

¿Y qué pasó con el developer de los dashboards? Al final implementó la librería. Me escribió un mes después: habían cambiado la licencia y ahora necesitaban un plan enterprise. No, es chiste. Bueno, no tanto.