Estou errado ao pensar que precisar de algo como o AutoMapper é uma indicação de design deficiente?


35

O Automapper é um "mapeador de objeto-objeto" para .Net, o que significa copiar objetos de uma classe para outra classe que representa a mesma coisa.

Por que isso é sempre útil? A duplicação de classes é sempre útil / com bom design?


Uma pequena referência: devtrends.co.uk/blog/… Leia especialmente a seção "por que não podemos usar o automapper?"
Jani Hyytiäinen

Respostas:


28

Uma rápida pesquisa no Google revelou este exemplo:

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

mostrando um uso perfeitamente válido do AutoMapper, que definitivamente não é um exemplo para um design ruim. Em um aplicativo em camadas, você pode ter objetos em sua camada de dados ou de negócios e, às vezes, precisa apenas de um subconjunto dos atributos desses objetos de dados ou de algum tipo de visualização na camada da interface do usuário. Portanto, você cria um modelo de exibição que contém objetos com exatamente os atributos necessários na sua interface do usuário, e não mais, e usa o AutoMapper para fornecer ao conteúdo desses objetos menos código padrão.

Em tal situação, seus "objetos de exibição" não são uma duplicata da classe original. Eles têm métodos diferentes e talvez alguns atributos duplicados. Mas tudo bem, desde que você use esses objetos de exibição apenas para fins de exibição da interface do usuário e não comece a usá-los incorretamente para manipulação de dados ou operações de negócios.

Outro tópico que você pode ler para entender melhor isso é o padrão de Segregação de Responsabilidade de Consulta de Comando do Fowlers , em contraste com o CRUD. Ele mostra situações em que diferentes modelos de objetos para consultar dados e atualizá-los em um banco de dados fazem sentido. Aqui, o mapeamento de um modelo de objeto para outro também pode ser feito por uma ferramenta como o AutoMapper.


11
Em relação ao seu primeiro exemplo: você não conseguiu compor objetos em vez de duplicá-los? Nesse caso, seus objetos de interface do usuário teriam uma referência aos seus objetos de dados originais e exporiam apenas os elementos necessários. Isso não faria sentido?
static_rtti

11
@static_rtti em teoria sim, mas você pode não necessariamente quer que sua classe original para ser público ou / e expostos em uma montagem
Jalayn

2
@static_rtti: sim, essa é uma abordagem perfeitamente válida e diferente. A principal diferença entre esses dois projetos é a vida útil dos dados / atributos. O uso de cópias fornece uma captura instantânea dos dados, mas as propriedades que referenciam os dados originais não. Ambas as abordagens têm seus prós e contras, mas IMHO não existe "melhor ou pior" em geral. Além disso, pode haver considerações de desempenho, que podem ou não influenciar a decisão sobre o que usar.
Doc Brown

3
Desacoplar o máximo possível é sempre uma boa ideia. Não porque seja particularmente benéfico para projetos pequenos, mas porque os projetos crescem.
Tamás Szelei

6
@ fish: Concordo principalmente que a dissociação costuma ser uma boa ideia, mas IMHO há situações suficientes em que manter as coisas simples supera uma abordagem de múltiplas camadas super dissociadas por uma questão de dissociação. A parte difícil é não perder o ponto durante o crescimento de um projeto quando se deve começar a refatorar.
Doc Brown

45

A duplicação de classes é sempre útil / com bom design?

É uma boa prática ter uma classe de modelo de exibição separada para uso na camada da interface do usuário, em vez de usar a mesma classe usada na camada de dados. Sua interface do usuário / página da web pode precisar exibir outros bits de informações que não estão estritamente relacionados à entidade de dados. Ao criar essa classe extra, você terá a liberdade de ajustar sua interface do usuário facilmente, conforme os requisitos mudam com o tempo.

Quanto ao uso do AutoMapper, eu pessoalmente o evito por 3 razões:

Falhas silenciosas mais comuns

Como o AutoMapper mapeia entre propriedades automaticamente, alterar um nome de propriedade em uma classe e não na outra fará com que o mapeamento de Propriedades seja ignorado. O compilador não saberá. Automapper não se importa.

Falta de análise estática

Então, você recebeu uma grande base de código para lidar. Há um milhão de classes com um milhão de propriedades. Parece que eles não são usados ​​ou são duplicados. Essa ferramenta "Localizar todas as referências" no Visual Studio ajudará você a ver onde as propriedades são usadas e a criar um mapa na sua cabeça de como o aplicativo inteiro fica junto. Mas espere, não há referências explícitas à metade das propriedades porque o Automapper está sendo usado. Meu trabalho agora é muito mais difícil.

Requisitos atrasados ​​que aumentam a complexidade

O Automapper é excelente e elegante quando tudo o que você deseja fazer é copiar os valores de UMA classe para outra (como costuma acontecer no início do desenvolvimento), mas lembre-se dos requisitos que mudam com o tempo? E se você agora precisar obter valores de outras partes do seu aplicativo, talvez específicas para o usuário que está conectado ou algum outro estado contextual?

O padrão do AutoMapper de criar os mapeamentos de classe um-para-um no início do aplicativo não se presta bem a esses tipos de alterações específicas do contexto. Sim, provavelmente existem maneiras de fazê-lo funcionar, mas geralmente acho mais limpo, mais simples e mais expressivo escrever a lógica.

Em resumo, antes de procurar o Automapper para economizar 30 segundos ao mapear manualmente uma classe para outra, pense sobre isso.

Programar é a arte de dizer a outro ser humano o que se quer que o computador faça. - Donald Knuth

Com isso em mente, pergunte a si mesmo "o AutoMapper é útil hoje e será amanhã?"


[se você faz um web dev moderno] Então, se você estiver escrevendo um serviço web REST, tende a sempre verificar todas as propriedades para garantir que seu modelo de objeto JavaScript seja consistente com o modelo de objeto .NET?
Den

3
@ Den - sim. E você escrever testes para ter certeza de obter todas as propriedades corrigir (ou seja, o teste vai mostrar todas as propriedades que você adicionou em 1 lugar que não se propagado para outros níveis)
gbjbaanb

@gbjbaanb Eu provavelmente usaria reflexão para fazer essa validação de uma maneira genérica. Talvez explore a possibilidade de estender o AutoMapper para adicionar alguma validação. Definitivamente evitaria muitas tarefas manuais.
Den

Concordo totalmente com você e acho que apenas aplicativos muito simples podem usar o automapper, mas quando as coisas se tornam mais complexas, precisamos escrever uma nova configuração para o automapper, por que não escrevê-las em um serviço ou auxiliar de mapeador manual.
ahmedsafan86 13/01

21

Na minha experiência, quando alguém se queixou de 'excesso de clichê' e deseja usar o AutoMapper, foi um dos seguintes:

  1. Eles acham irritante escrever o mesmo código repetidamente.
  2. Eles são preguiçosos e não querem escrever código que faça Ax = Bx
  3. Eles estão sob muita pressão para realmente pensar se escrever Ax = Bx repetidamente é uma boa ideia e depois escrever um bom código para a tarefa.

Contudo:

  1. Se realmente se trata de evitar repetições, você pode criar um objeto ou método para abstraí-lo. Você não precisa do AutoMapper.
  2. Se você é preguiçoso, será preguiçoso e não aprenderá como o AutoMapper funciona. Em vez disso, você adotará o padrão 'programação por coincidência' e escreverá um código horrível no qual inserirá a lógica comercial em um perfil do AutoMapper. Nesse caso, você deve mudar sua atitude em relação à programação ou encontrar outra coisa para fazer como profissão. Você não precisa do AutoMapper.
  3. Se você estiver com muita pressão, seu problema não tem nada a ver com a programação em si. Você não precisa do AutoMapper.

Se você escolheu um idioma estaticamente digitado, aproveite-o. Se você está tentando contornar os controles no idioma que ajudam a evitar erros devido ao uso excessivo de APIs de reflexão e mágica como o AutoMapper, isso significa que você escolheu um idioma que não é satisfatório para suas necessidades.

Além disso, o fato de a Microsoft ter adicionado recursos ao C # não significa que eles são honestos em todas as situações ou que suportam as melhores práticas. A reflexão e a palavra-chave 'dinâmica', por exemplo, devem ser usadas nos casos em que você simplesmente não pode realizar o que precisa sem elas. O AutoMapper não é uma solução para nenhum caso de uso que ainda não possa ser resolvido sem ele.

Então, a duplicação de classes é um design ruim? Não necessariamente.

O AutoMapper é uma má ideia? Sim absolutamente.

O uso do AutoMapper indica deficiências sistêmicas no projeto. Se você precisar, pare e pense no seu design. Você sempre encontrará um design melhor, mais legível, mais sustentável e mais livre de erros.


11
Bem dito, particularmente 2.
Mardoxx

2
Eu sei que esse é um encadeamento muito antigo, mas tenho que discordar de 1. Você não pode fazer um método para abstrair o mapeamento. Você pode fazer 1 aula, mas se tiver 2, precisará de 2 métodos. 3 - 3 métodos. Com AM, essa é uma linha de código - definição de mapeamento. Além disso, eu realmente lutei com um cenário em que eu tinha uma lista <BaseType> preenchida com 10 subtipos de DTO. Quando você deseja mapear isso, precisa de um tipo e um método para copiar valores de campo. E se um dos campos tiver que ser mapeado separadamente? Sua resposta só é boa se você tiver poucas aulas simples. O AutoMapper vence as mãos em cenários mais complexos.
precisa saber é o seguinte

11
(limite de caracteres) A ​​única armadilha da AM que acho é a possibilidade de alterar o nome da propriedade em uma classe e não na outra. Mas, na verdade, com que frequência você faz isso depois que o design é concluído? E você pode escrever um método de teste genérico que usa reflexão e compara nomes de propriedades. Como todas as ferramentas, o AM deve ser usado corretamente - não cegamente, nem em todas as situações, eu concordo. Mas dizer "você não deve usá-lo" está errado.
user3512524

7

Há uma questão mais profunda aqui: o fato de que C # e Java insistem que a maioria dos tipos deve ser distinguida por nome, em vez de estrutura: por exemplo, class MyPoint2De class YourPoint2Dsão tipos separados, mesmo que tenham exatamente as mesmas definições. Quando o tipo que você deseja é "algo anônimo com um xcampo e um ycampo" (ou seja, um registro ), você fica sem sorte. Portanto, quando você deseja transformar um YourPoint2Dem MyPoint2D, você tem três opções:

  1. Escreva alguns clichês tediosos, repetitivos e mundanos ao longo das linhas de this.x = that.x; this.y = that.y
  2. Gere o código de alguma forma.
  3. Use reflexão.

A escolha 1 é bastante fácil em pequenas doses, mas rapidamente se torna uma tarefa árdua quando o número de tipos que você precisa mapear é grande.

A opção 2 é menos do que desejável, porque agora você precisa adicionar uma etapa extra ao processo de criação para gerar o código e garantir que toda a equipe receba o memorando. Na pior das hipóteses, você também precisa lançar seu próprio sistema de gerador de código ou modelo.

Isso deixa você com reflexão. Você pode fazer isso sozinho ou usar o AutoMapper.


3

Automapper é uma daquelas bibliotecas / ferramentas em que o imperador está literalmente correndo pelado. Quando você passa pelo logotipo chamativo, percebe que ele não faz nada que não pode ser feito manualmente com resultados muito melhores.

Embora eu não tenha muita certeza de como isso sugere membros de mapeamento automático, provavelmente envolve lógica de tempo de execução adicional e possível reflexão. Isso pode ser uma penalidade de desempenho significativa em troca de uma economia de tempo. Mapeamento manual, por outro lado, a dica é executada bem antes do tempo de compilação.

Nos casos em que o AutoMapper não tem idéia, você deve configurar o mapeamento com código e sinalizadores de configuração. Se você vai se preocupar em fazer todo o trabalho de configuração e código, você deve questionar quanto ele economiza no mapeamento manual.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.