Sbaglio nel pensare che la necessità di qualcosa come AutoMapper sia indice di un design scadente?


35

Automapper è un "mappatore oggetto-oggetto" per .Net, che significa copiare oggetti da una classe in un'altra classe che rappresenta la stessa cosa.

Perché è mai utile? La duplicazione delle lezioni è mai utile / di buon design?


Un piccolo riferimento: devtrends.co.uk/blog/… Leggi in particolare la sezione "Perché non possiamo usare Automapper?"
Jani Hyytiäinen,

Risposte:


28

Una rapida ricerca su Google ha rivelato questo esempio:

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

mostrando un uso perfettamente valido di AutoMapper che sicuramente non è un esempio per un design scadente. In un'applicazione a più livelli, potresti avere oggetti nei tuoi dati o livello aziendale e a volte hai bisogno solo di un sottoinsieme degli attributi di tali oggetti dati o di una sorta di vista su di essi nel tuo livello UI. Quindi si crea un modello di vista che contiene oggetti con esattamente gli attributi necessari nell'interfaccia utente, non di più, e si utilizza AutoMapper per fornire il contenuto di quegli oggetti con un codice di caldaia inferiore.

In una situazione del genere i tuoi "oggetti di visualizzazione" non sono un duplicato della classe originale. Hanno metodi diversi e forse alcuni attributi duplicati. Ma va bene finché usi quegli oggetti di visualizzazione solo per scopi di visualizzazione dell'interfaccia utente e non inizi a usarli in modo improprio per manipolazione dei dati o operazioni aziendali.

Un altro argomento che potresti leggere per capire meglio questo è il modello di segregazione Responsabilità delle query dei comandi di Fowlers , al contrario di CRUD. Mostra le situazioni in cui hanno senso diversi modelli di oggetti per la query dei dati e l'aggiornamento in un database. Qui, la mappatura da un modello a oggetti a un altro può essere eseguita anche da uno strumento come AutoMapper.


1
Per quanto riguarda il tuo primo esempio: non potresti comporre oggetti invece di duplicarli? In tal caso, gli oggetti dell'interfaccia utente avrebbero un riferimento agli oggetti dati originali e esponevano solo gli elementi necessari. Non avrebbe senso?
static_rtti,

1
@static_rtti in teoria sì, ma potresti non voler necessariamente che la tua classe originale sia pubblica o / ed esposta in un'assemblea
Jalayn,

2
@static_rtti: sì, è un approccio perfettamente valido e diverso. La differenza principale tra questi due progetti è la durata dei dati / attributi. L'uso delle copie fornisce un'istantanea dei dati, mentre le proprietà che fanno riferimento ai dati originali no. Entrambi gli approcci hanno i suoi pro e contro, ma IMHO non c'è "meglio o peggio" in generale. Inoltre, ci possono essere considerazioni sulle prestazioni, che possono o meno influenzare la decisione su cosa usare.
Doc Brown,

3
Il disaccoppiamento il più possibile è sempre una buona idea. Non perché sia ​​particolarmente vantaggioso anche per piccoli progetti, ma perché i progetti crescono.
Tamás Szelei,

6
@fish: concordo principalmente, il disaccoppiamento è spesso una buona idea, ma IMHO ci sono abbastanza situazioni in cui mantenere le cose semplici supera un approccio multi-strato-super-disaccoppiato per il bene del disaccoppiamento. La parte difficile è non perdere il punto durante la crescita di un progetto quando si dovrebbe iniziare il refactoring.
Doc Brown,

45

La duplicazione delle lezioni è mai utile / di buon design?

È buona norma disporre di una classe del modello di vista separata da utilizzare nel livello dell'interfaccia utente anziché utilizzare la stessa classe utilizzata nel livello dati. Potrebbe essere necessario che la tua UI / pagina web visualizzi altri bit di informazioni non strettamente correlati all'entità dati. Creando questa classe extra, ti stai dando la libertà di modificare facilmente la tua interfaccia utente man mano che i requisiti cambiano nel tempo.

Per quanto riguarda l'utilizzo di AutoMapper, lo evito personalmente per 3 motivi:

Insuccessi silenziosi più comuni

Poiché AutoMapper esegue il mapping automatico tra le proprietà, la modifica di un nome di proprietà su una classe e non sull'altra farà saltare la mappatura delle proprietà. Il compilatore non lo saprà. A Automapper non importa.

Mancanza di analisi statiche

Quindi ti è stata data una grande base di codice da gestire. Ci sono un milione di classi con un milione di proprietà. Sembra che non vengano utilizzati o siano duplicati. Lo strumento "Trova tutti i riferimenti" in Visual Studio ti aiuterà a vedere dove vengono utilizzate le proprietà e ti aiuterà a costruire una mappa nella testa di come l'intera applicazione si blocca. Ma aspetta, non ci sono riferimenti espliciti a metà delle proprietà perché viene utilizzato Automapper. Il mio lavoro ora è molto più difficile.

Requisiti tardivi che aumentano la complessità

Automapper è tutto a posto quando vuoi solo copiare i valori da UNA classe a un'altra (come spesso accade all'inizio dello sviluppo), ma ricordi quei requisiti che cambiano nel tempo? Cosa succede se ora è necessario ottenere valori da altre parti dell'applicazione, forse specifici dell'utente che ha effettuato l'accesso o di qualche altro stato contestuale?

Il modello di AutoMapper per la creazione dei mapping di classe one-to-one all'avvio dell'applicazione non si presta bene a questo tipo di cambiamenti specifici del contesto. Sì, probabilmente ci sono modi per farlo funzionare, ma di solito trovo più pulito, semplice ed espressivo scrivere la logica da solo.

In sintesi, prima di raggiungere Automapper per risparmiare 30 secondi di mappatura manuale di una classe su un'altra, pensaci.

La programmazione è l'arte di dire a un altro essere umano cosa si vuole fare dal computer. - Donald Knuth

Con questo in mente, chiediti "AutoMapper è utile oggi e sarà domani?"


[se fai un web dev di tendenza] Quindi se stai scrivendo un servizio web REST tendi sempre a controllare ogni singola proprietà per assicurarti che il tuo modello di oggetti JavaScript sia coerente con il tuo modello di oggetti .NET?
Den

3
@Den - si. E scrivi dei test per assicurarti di avere tutte le proprietà corrette (cioè il tuo test mostrerà tutte le proprietà che hai aggiunto in 1 posto che non vengono propagate agli altri livelli)
gbjbaanb

@gbjbaanb Probabilmente userei semplicemente la riflessione per fare questa validazione in modo generico. Forse esplorare la possibilità di estendere AutoMapper per aggiungere un po 'di convalida. Eviterei sicuramente molte assegnazioni manuali.
Den

Totalmente d'accordo con te e pensa che solo le app molto semplici possano usare automapper, ma quando le cose diventano più complesse dobbiamo scrivere una nuova configurazione per automapper, perché non scrivere quelle in un supporto o servizio di mapper manuale.
ahmedsafan86,

21

Nella mia esperienza, quando qualcuno si è lamentato di "troppo boilerplate" e desidera utilizzare AutoMapper, è stato uno dei seguenti:

  1. Trovano irritante scrivere più volte lo stesso codice.
  2. Sono pigri e non vogliono scrivere codice che fa Ax = Bx
  3. Sono troppo sotto pressione per pensare davvero se scrivere Ax = Bx più volte sia una buona idea e quindi scrivere un buon codice per l'attività.

Tuttavia:

  1. Se si tratta davvero di evitare la ripetizione, è possibile creare un oggetto o un metodo per sottrarlo. Non hai bisogno di AutoMapper.
  2. Se sei pigro, sarai pigro e non imparerai come funziona AutoMapper. Invece adotterai il modello di "programmazione per coincidenza" e scriverai codice orribile in cui inserirai la logica aziendale in un profilo AutoMapper. In questo caso, dovresti cambiare il tuo atteggiamento nei confronti della programmazione o trovare qualcos'altro da fare come professione. Non hai bisogno di AutoMapper.
  3. Se hai troppa pressione del tempo, il tuo problema non ha nulla a che fare con la programmazione stessa. Non hai bisogno di AutoMapper.

Se hai scelto una lingua tipicamente statica, approfitta della lingua. Se stai tentando di eludere i controlli nella lingua che aiutano a prevenire errori dovuti a un uso eccessivo di API di riflessione e magiche come AutoMapper, significa solo che hai scelto un linguaggio che non è soddisfacente per le tue esigenze.

Inoltre, solo perché Microsoft ha aggiunto funzionalità a C # non significa che sono un gioco equo in ogni situazione o che supportano le migliori pratiche. Reflection e la parola chiave "dinamica", per esempio, dovrebbero essere usati nei casi in cui semplicemente non puoi realizzare ciò di cui hai bisogno senza di loro. AutoMapper non è una soluzione per nessun caso d'uso che non può essere risolto senza di essa.

Quindi, la duplicazione delle classi è cattiva progettazione? Non necessariamente.

AutoMapper è una cattiva idea? Si assolutamente.

L'uso di AutoMapper indica carenze sistemiche nel progetto. Se ti senti di averne bisogno, fermati e pensa al tuo design. Troverai sempre un design migliore, più leggibile, più gestibile e più privo di bug.


1
Ben detto, in particolare 2.
Mardoxx,

2
So che questo è un thread molto vecchio, ma non sono d'accordo con 1. Non è possibile creare un metodo per astrarre la mappatura. Puoi per 1 classe, ma se ne hai 2, hai bisogno di 2 metodi. 3 - 3 metodi. Con AM si tratta di 1 riga di codice - definizione di mappatura. Inoltre, ho davvero lottato con uno scenario, in cui avevo un elenco <BaseType> riempito con 10 sottotipi DTO. Quando si desidera mapparlo, è necessario un tipo di attivazione E un metodo per copiare i valori dei campi. E se uno dei campi dovesse essere mappato separatamente? La tua risposta è buona solo se hai poche lezioni semplici. AutoMapper vince a mani basse in scenari più complessi.
user3512524

1
(limite di caratteri) L'unica trappola di AM penso sia la possibilità di cambiare il nome della proprietà in una classe e non nell'altra. Ma davvero, quanto spesso lo fai dopo che il design è finito? E puoi scrivere un metodo di prova generico che utilizza la riflessione e confronta i nomi delle proprietà. Come tutti gli strumenti, AM deve essere usato correttamente - non ciecamente, non in tutte le situazioni, sono d'accordo. Ma dire "non dovresti usarlo" è semplicemente sbagliato.
user3512524,

7

C'è un problema più profondo qui: il fatto che C # e Java insistano sul fatto che la maggior parte / tutti i tipi devono essere distinguibili per nome piuttosto che per struttura: ad esempio, class MyPoint2De class YourPoint2Dsono tipi separati anche se hanno le stesse identiche definizioni. Quando il tipo che desideri è "qualcosa di anonimo con un xcampo e un ycampo" (cioè un record ), sei sfortunato. Quindi, quando vuoi trasformare a YourPoint2Din a MyPoint2D, hai tre opzioni:

  1. Scrivi una scialuppa noiosa, ripetitiva, banale lungo le righe di this.x = that.x; this.y = that.y
  2. Genera il codice in qualche modo.
  3. Usa la riflessione.

La scelta 1 è abbastanza facile a piccole dosi ma diventa rapidamente un lavoro ingrato quando il numero di tipi che è necessario mappare è elevato.

La scelta 2 è meno desiderabile perché ora è necessario aggiungere un ulteriore passaggio al processo di generazione per generare il codice e assicurarsi che l'intero team riceva il memo. Nel peggiore dei casi è necessario creare anche il proprio generatore di codice o sistema di template.

Questo ti lascia con la riflessione. Puoi farlo da solo o puoi usare AutoMapper.


3

Automapper è una di quelle librerie / strumenti in cui l'imperatore corre letteralmente in giro nudo. Quando superi il logo sfarzoso, ti rendi conto che non fa nulla che non puoi fare manualmente con risultati molto migliori.

Sebbene non sia del tutto sicuro di come accenni ai membri di auto-mapping, molto probabilmente comporta una logica di runtime aggiuntiva e una possibile riflessione. Questa potrebbe essere una penalità di prestazione significativa in cambio di un risparmio di tempo. La mappatura manuale, d'altra parte, il suggerimento viene eseguito molto prima del tempo di compilazione.

Nei casi in cui AutoMapper non ha idea, è necessario configurare la mappatura con codice e flag di impostazione. Se hai intenzione di preoccuparti di fare tutto il lavoro di installazione e codice, devi chiederti quanto risparmia sulla mappatura manuale.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.