Czy mylę się myśląc, że potrzeba czegoś takiego jak AutoMapper jest oznaką złego projektu?

35

Automapper to „obiekt-obiekt odwzorowujący” dla .Net, co oznacza kopiowanie obiektów z klasy do innej klasy, która reprezentuje to samo.

Dlaczego to jest zawsze przydatne? Czy powielanie klas jest kiedykolwiek przydatne / dobry projekt?

static_rtti
źródło
Trochę referencji: devtrends.co.uk/blog/… Szczególnie przeczytaj sekcję „Dlaczego nie możemy użyć automappera?”
Jani Hyytiäinen

Odpowiedzi:

28

Szybkie wyszukiwanie w Google ujawniło ten przykład:

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

pokazując doskonale poprawne użycie AutoMapper, co zdecydowanie nie jest przykładem złego projektu. W aplikacji warstwowej możesz mieć obiekty w warstwie danych lub biznesowej, a czasem potrzebujesz tylko podzbioru atrybutów tych obiektów danych lub jakiegoś rodzaju widoku dla nich w warstwie interfejsu użytkownika. Więc tworzysz model widoku, który zawiera obiekty z dokładnie tymi atrybutami, których potrzebujesz w interfejsie użytkownika, a nie więcej, i używasz AutoMapper, aby dostarczyć zawartość tych obiektów z mniejszym kodem wzorcowym.

W takiej sytuacji twoje „obiekty widoku” nie są duplikatem oryginalnej klasy. Mają różne metody i być może kilka zduplikowanych atrybutów. Ale jest to w porządku, o ile używasz tego widoku tylko do wyświetlania celów w interfejsie użytkownika i nie zaczynasz go niewłaściwie wykorzystywać do manipulacji danymi lub operacji biznesowych.

Innym tematem, który możesz przeczytać, aby lepiej to zrozumieć, jest wzorzec segregacji zapytań Fowlers Command Query , w przeciwieństwie do CRUD. Pokazuje sytuacje, w których różne modele obiektów do wyszukiwania danych i aktualizowania ich w bazie danych mają sens. Tutaj mapowanie z jednego modelu obiektu na inny może być również wykonane przez narzędzie takie jak AutoMapper.

Doktor Brown
źródło
1
Jeśli chodzi o twój pierwszy przykład: czy nie możesz komponować obiektów zamiast powielać je? W takim przypadku obiekty interfejsu użytkownika będą miały odniesienie do oryginalnych obiektów danych i ujawnią tylko niezbędne elementy. Czy to nie miałoby sensu?
static_rtti
1
@static_rtti w teorii tak, ale niekoniecznie chcesz, aby twoja oryginalna klasa była publiczna lub / i wystawiona w asemblerze
Jalayn
2
@static_rtti: tak, jest to całkowicie poprawne, inne podejście. Główną różnicą między tymi dwoma projektami jest żywotność danych / atrybutów. Korzystanie z kopii zapewnia migawkę danych, a korzystanie z właściwości odwołujących się do oryginalnych danych nie. Oba podejścia mają swoje zalety i wady, ale w IMHO nie ma ogólnie „lepszego lub gorszego”. Ponadto mogą występować względy wydajności, które mogą wpływać na decyzję, której użyć.
Doc Brown
3
Oddzielenie możliwie największej liczby jest zawsze dobrym pomysłem. Nie dlatego, że jest to szczególnie korzystne w przypadku nawet małych projektów, ale dlatego, że projekty rosną.
Tamás Szelei
6
@fish: Zgadzam się głównie, odsprzężenie jest często dobrym pomysłem, ale w IMHO istnieje wystarczająca liczba sytuacji, w których uproszczenie rzeczy przeważa nad podejściem wielowarstwowym super-odsprzężonym dla samego oddzielenia. Trudność polega na tym, aby nie przegapić sensu podczas rozwoju projektu, kiedy należy rozpocząć refaktoryzację.
Doc Brown
45

Czy powielanie klas jest kiedykolwiek przydatne / dobry projekt?

Dobrą praktyką jest posiadanie osobnej klasy modelu widoku do użytku w warstwie interfejsu użytkownika zamiast używania tej samej klasy, która jest używana w warstwie danych. Twój interfejs użytkownika / strona internetowa może wymagać wyświetlenia innych fragmentów informacji, które nie są ściśle związane z jednostką danych. Tworząc tę ​​dodatkową klasę, dajesz sobie swobodę łatwego dostosowywania interfejsu użytkownika, gdy wymagania zmieniają się z czasem.

Jeśli chodzi o korzystanie z AutoMapper, osobiście go unikam z 3 powodów:

Ciche awarie są częstsze

Ponieważ AutoMapper automatycznie mapuje właściwości, zmiana nazwy właściwości w jednej klasie, a nie w drugiej, spowoduje pominięcie odwzorowania właściwości. Kompilator nie będzie wiedział. Automapper nie będzie się tym przejmował.

Brak analizy statycznej

Masz więc dużą bazę kodu do rozwiązania. Istnieje milion klas z milionem nieruchomości. Wygląda na to, że nie są używane lub są duplikatami. To narzędzie „Znajdź wszystkie odniesienia” w Visual Studio pomoże ci zobaczyć, gdzie używane są właściwości, i pomoże zbudować mapę w głowie, w jaki sposób cała aplikacja się łączy. Ale czekaj, nie ma wyraźnych odniesień do połowy właściwości, ponieważ używany jest Automapper. Moja praca jest teraz o wiele trudniejsza.

Późne wymagania, które zwiększają złożoność

Automapper jest w porządku i elegancki, gdy wszystko, co chcesz zrobić, to skopiować wartości z JEDNEJ klasy do innej (jak to często ma miejsce na początku rozwoju), ale pamiętasz te wymagania, które zmieniają się z czasem? Co jeśli teraz musisz uzyskać wartości z innych części aplikacji, być może specyficznych dla zalogowanego użytkownika lub innego stanu kontekstowego?

Wzorzec AutoMapper tworzenia odwzorowań klas jeden na jeden na początku aplikacji nie nadaje się dobrze do tego rodzaju zmian kontekstowych. Tak, prawdopodobnie istnieją sposoby, aby to zadziałało, ale zwykle uważam, że pisanie logiki jest czystsze, prostsze i bardziej wyraziste.

Podsumowując, zanim sięgniesz po Automapper, aby zaoszczędzić 30 sekund ręcznego mapowania jednej klasy do drugiej, zastanów się nad tym.

Programowanie to sztuka mówienia innemu człowiekowi, co ma robić komputer. - Donald Knuth

Mając to na uwadze, zadaj sobie pytanie: „czy AutoMapper jest dziś pomocny i czy będzie jutro?”

Dave B 84
źródło
[jeśli robisz modny web dev] Więc jeśli piszesz usługę REST, czy zwykle zawsze sprawdzasz każdą właściwość, aby upewnić się, że model obiektu JavaScript jest zgodny z modelem obiektu .NET?
Den
3
@Den - tak. I piszesz testy, aby upewnić się, że wszystkie właściwości są poprawne (tzn. Twój test pokaże wszystkie właściwości, które dodałeś w 1 miejscu, które nie są propagowane na inne poziomy)
gbjbaanb
@ gbjbaanb Prawdopodobnie użyłbym refleksji, aby przeprowadzić tę weryfikację w ogólny sposób. Być może zbadaj możliwość rozszerzenia AutoMapper, aby dodać sprawdzanie poprawności. Zdecydowanie uniknąłby wielu ręcznych zadań.
Den
Całkowicie Zgadzam się z tobą i myślę, że tylko bardzo proste aplikacje mogą korzystać z automappera, ale kiedy sprawy stają się bardziej złożone, musimy napisać nową konfigurację dla automappera, więc dlaczego nie napisać tych w pomocniku lub usłudze mapera ręcznego.
ahmedsafan86
21

Z mojego doświadczenia wynika, że ​​gdy ktoś narzekał na „zbyt dużo płyty kotłowej” i chce korzystać z AutoMapper, było to jedno z następujących:

  1. Ciągłe pisanie tego samego kodu jest irytujące.
  2. Są leniwi i nie chcą pisać kodu, który robi Ax = Bx
  3. Są pod zbyt dużą presją czasu, aby zastanowić się, czy napisanie Ax = Bx w kółko jest dobrym pomysłem, a następnie napisanie dobrego kodu do zadania.

Jednak:

  1. Jeśli naprawdę chodzi o unikanie powtórzeń, możesz utworzyć obiekt lub metodę jego wyodrębnienia. Nie potrzebujesz AutoMapper.
  2. Jeśli jesteś leniwy, będziesz leniwy i nie dowiesz się, jak działa AutoMapper. Zamiast tego przyjmiesz wzorzec „programowania przez przypadek” i napiszesz okropny kod, w którym umieszczasz logikę biznesową w profilu AutoMapper. W takim przypadku powinieneś zmienić swoje nastawienie do programowania lub znaleźć coś innego do zrobienia jako zawód. Nie potrzebujesz AutoMapper.
  3. Jeśli jesteś pod zbyt dużą presją czasu, twój problem nie ma nic wspólnego z samym programowaniem. Nie potrzebujesz AutoMapper.

Jeśli wybrałeś język pisany statycznie, skorzystaj z niego. Jeśli próbujesz ominąć elementy sterujące w języku, które pomagają zapobiegać błędom wynikającym z nadmiernego użycia refleksów i magicznych interfejsów API, takich jak AutoMapper, oznacza to po prostu, że wybrałeś język, który nie spełnia Twoich wymagań.

Również fakt, że Microsoft dodał funkcje do C #, nie oznacza, że ​​są uczciwą grą w każdej sytuacji lub że wspierają najlepsze praktyki. Na przykład refleksji i słowa kluczowego „dynamicznego” należy używać w przypadkach, w których po prostu nie można osiągnąć tego, czego potrzebujesz bez nich. AutoMapper nie jest rozwiązaniem dla żadnego przypadku użycia, który bez tego nie mógłby zostać rozwiązany.

Czy duplikacja klas jest złym projektem? Niekoniecznie.

Czy AutoMapper to zły pomysł? Tak, absolutnie.

Zastosowanie AutoMapper wskazuje na systemowe braki w projekcie. Jeśli potrzebujesz go, przestań i pomyśl o swoim projekcie. Zawsze znajdziesz lepszy, bardziej czytelny, łatwiejszy w utrzymaniu i pozbawiony błędów projekt.

Shashi Penumarthy
źródło
1
Dobrze powiedziane, szczególnie 2.
Mardoxx
2
Wiem, że to bardzo stary wątek, ale muszę się nie zgodzić z 1. Nie można stworzyć metody abstrakcyjnego mapowania. Możesz dla 1 klasy, ale jeśli masz 2, potrzebujesz 2 metod. 3 - 3 metody. W przypadku AM jest to 1 linia kodu - definicja mapowania. Plus, naprawdę zmagałem się ze scenariuszem, w którym miałem List <BaseType> wypełniony 10 podtypami DTO. Jeśli chcesz to zmapować, musisz włączyć typ ORAZ metodę kopiowania wartości pól. A co, jeśli jedno z pól musi zostać oddzielnie zmapowane? Twoja odpowiedź jest dobra tylko wtedy, gdy masz kilka prostych zajęć. AutoMapper wygrywa w bardziej złożonych scenariuszach.
user3512524
1
(char limit) Jedyną pułapką AM myślę, że jest możliwość zmiany nazwy własności w jednej klasie, a nie w drugiej. Ale tak naprawdę, jak często to robisz po zakończeniu projektowania? Możesz napisać ogólną metodę testową, która wykorzystuje odbicie i porównuje nazwy właściwości. Podobnie jak wszystkie narzędzia, AM musi być używane poprawnie - nie na ślepo, nie we wszystkich sytuacjach, zgadzam się. Ale powiedzenie „nie powinieneś go używać” jest po prostu błędne.
user3512524
7

Jest głębszy problem tutaj: fakt, że C # i Java nalegać większość / wszystkie typy muszą być rozróżnialne przez nazwę zamiast struktury: przykład class MyPoint2Di class YourPoint2Dsą oddzielne typy nawet jeśli mają dokładnie te same definicje. Gdy pożądanym typem jest „anonimowa rzecz z xpolem i ypolem” (tj. Rekord ), nie masz szczęścia. Kiedy więc chcesz zamienić YourPoint2Dna a MyPoint2D, masz trzy opcje:

  1. Napisz żmudny, powtarzalny, przyziemny szablon na wzór this.x = that.x; this.y = that.y
  2. Jakoś wygeneruj kod.
  3. Użyj refleksji.

Wybór 1 jest dość łatwy w małych dawkach, ale szybko staje się obowiązkiem, gdy liczba typów, które musisz zmapować, jest duża.

Wybór 2 jest mniej niż pożądany, ponieważ teraz musisz dodać dodatkowy krok do procesu kompilacji, aby wygenerować kod i upewnić się, że cały zespół otrzyma notatkę. W najgorszym przypadku musisz także uruchomić własny generator kodów lub system szablonów.

To pozostawia refleksję. Możesz to zrobić samodzielnie lub użyć AutoMapper.

Doval
źródło
3

Automapper to jedna z tych bibliotek / narzędzi, w których cesarz dosłownie biegnie nago po tyłku. Kiedy miniesz błyszczące logo, zdajesz sobie sprawę, że nie robi nic, czego nie możesz zrobić ręcznie, ze znacznie lepszymi wynikami.

Chociaż nie jestem do końca pewien, w jaki sposób sugeruje to członkom automatycznego mapowania, najprawdopodobniej wiąże się to z dodatkową logiką środowiska wykonawczego i możliwą refleksją. Może to stanowić znaczną utratę wydajności w zamian za oszczędność czasu. Z drugiej strony, ręczne mapowanie jest wykonywane na długo przed czasem kompilacji.

W przypadkach, w których AutoMapper nie ma pojęcia, musisz skonfigurować mapowanie za pomocą kodu i ustawić flagi. Jeśli masz zamiar zawracać sobie głowę instalacją i kodowaniem, musisz zapytać, ile to oszczędza na ręcznym mapowaniu.

użytkownik148298
źródło