fbpx
devstyle.pl - Blog dla każdego programisty
devstyle.pl - Blog dla każdego programisty
5 minut

Trochę inna organizacja kodu w ASP.NET MVC


30.06.2011

ASP MVC 3 jest w dużej części spoko – znajdą się elementy bardzo irytujące, ale ogólnie mogę powiedzieć że jestem z pracy z tym frameworkiem raczej zadowolony. Denerwuje mnie jednak to, że pracując nad jedną daną akcją w jakimś kontrolerze muszę śmigać po kilku plikach:

  • plik kontrolera
  • plik z routingiem
  • plik z modelem parametru akcji
  • plik z modelem zwracanym przez akcję
  • plik z mapowaniami AutoMappera
  • plik widoku .cshtml
  • plik skryptów .js
  • … o czymś zapomniałem?

Jakiś czas temu postanowiłem wypróbować alternatywne podejście do organizacji kodu w swoim projekcie webowym…

[Przyszło mi ono do głowy zimą podczas przeglądania materiałów dotyczących frameworka FubuMVC, ale właściwie momentalnie zarzuciłem zapoznawanie się z tym rozwiązaniem, więc nie jestem w stanie na dzień dzisiejszy powiedzieć, jak poniższe podejście i praktyki Fubu “ze sobą korespondują“;)… co z kolei teraz staram się nadrabiać, eksperymentując ponownie z Fubu]

Najlepiej zobrazuje to przykład, żeby było wiadomo o co mi CHO. Poniżej przedstawiam kawałek kodu odpowiedzialny za akcję “administrator dodaje notatkę do firmy”:

  1:  public partial class CompaniesManagementController
  2:  {
  3:      [HttpPost]
  4:      public virtual ActionResult SaveNote(SaveNoteModel model)
  5:      {
  6:          var company = _session.Load<Company>(model.CompanyId);
  7:  
  8:          Note newNote = model.Map<Note>();
  9:  
 10:          company.AddNote(newNote);
 11:  
 12:          return Json(new SaveNoteResponse()
 13:                          {
 14:                              SavedSuccessfully = true,
 15:                              Message = MessagesContent.CompanyNote_SaveSuccess
 16:                          });
 17:      }
 18:  
 19:      public class SaveNoteModel
 20:      {
 21:          public int CompanyId { get; set; }
 22:  
 23:          [Required]
 24:          [DisplayName("Notatka")]
 25:          public string Content { get; set; }
 26:      }
 27:  
 28:      public class SaveNoteResponse
 29:      {
 30:          public bool SavedSuccessfully { get; set; }
 31:          public string Message { get; set; }
 32:      }
 33:  
 34:      public class Routes : IRouteProvider
 35:      {
 36:          public void RegisterRoutes(RouteCollection routes)
 37:          {
 38:              routes.MapRoute(
 39:                  "Admin_SaveNote",
 40:                  "Admin/ZapiszNotatke",
 41:                  MVC.Administration.CompaniesManagement.SaveNote()
 42:              );
 43:          }
 44:      }
 45:  
 46:      public class Mappings : IMappingProvider
 47:      {
 48:          public void RegisterMap()
 49:          {
 50:              AutoMapper.Mapper.CreateMap<SaveNoteModel, Note>();
 51:          }
 52:      }
 53:  }

Cóż tu widzimy? Jeden plik zawierający prawie wszystko, co jest potrzebne do oprogramowania jednej akcji. Kontroler jest partial – bo w innych plikach (które nazywam CompaniesManagement_SaveNote.cs, CompaniesManagement_DeleteCompany.cs etc…) piszę inne akcje, będące częściami tego samego kontrolera. Modele są zagnieżdżone – więc nigdy nie nastąpi żaden konflikt nazw z innymi mikroskopijnymi klaskami rozsianymi po projekcie. Tak samo definicje routingu oraz mapowań – każda akcja sama sobie definiuje pod jakim URLem chce się znajdować i w jaki sposób skorzystać z AutoMappera.

Dostrzegłem bowiem, że tak naprawdę NIC mi nie daje trzymanie modeli w jednym katalogu – bo nigdy nie potrzebuję dostępu do więcej niż jednego naraz. Tylko powoduje bałagan i zamieszanie podczas nawigacji. To samo z mapowaniami – i tak każda akcja ma własny model (lub dwa), więc i mapowania są wyłącznie dla niej charakterystyczne. A routing… No tutaj wiele już zależy od specyfiki danego systemu, ale generalnie podoba mi się swoboda, jaką daje przedstawione rozwiązanie: hierarchia URLi nie musi wcale pokrywać się z organizacją kontrolerów w “aree” oraz grupowanie akcji w kontrolery.

Wszystkie zależności wymagane przez wszystkie akcje kontrolera znajdują się w jednym konstruktorze, zdefiniowanym w głównym pliku CompaniesManagement.cs, który nie zawiera żadnych akcji. Zadaniem tego pliku jest przyjęcie zależności, dziedziczenie z odpowiedniej klasy bazowej oraz nałożenie atrybutów wspólnych dla wszystkich akcji (jak [Authorize]).

Okazało się, że taka organizacja kodu w projekcie webowym znacznie ułatwia mi pracę. Początkowo podchodziłem do tego bardzo sceptycznie, ale… po jakimś czasie wszystkie nowe funkcjonalności powstawały właśnie w ten sposób.

Zastanawiałem się czy nie pójść o krok dalej i nie “scustomizować” zachowania MVC tak, aby jeszcze bardziej wyeksponować akcję jako główny element rozwiązania webowego. Chodzi o to, aby każda akcja otrzymała osobny katalog, a w nim zarówno przedstawiony wyżej kod C#, jak i widok cshtml. Ale tego jeszcze nie wypróbowałem.

Co o tym myślicie? Tak jak napisałem – w moim przypadku takie coś naprawdę się sprawdza. Pliczki z akcjami są niewielkie i łatwo się po nich poruszać, a mają wszystko co potrzeba.

 

P.S.: Proszę po powyższym kodzie zbytnio nie jechać – ma on służyć jedynie demonstracji mojej koncepcji i nie jest żywcem wzięty z żadnego systemu.

0 0 votes
Article Rating
28 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
procent
13 years ago

Uwaga, Gutek właśnie zwrócił mi uwagę, że klasa Mappings w powyższym kodzie nie ma metody – i faktycznie, to nie jest żadna magiczna sztuczka, tylko po prostu zapomniałem:). Tak jak pisałem, kod nie jest skopiowany z żadnego projektu, a dostosowany w Notatniku na potrzeby posta aby przedstawić ideę/koncepcję.
Posta poprawiam, ale do RSSów poszła głupota. Dzięki Gutek za uwagę!

Gutek
13 years ago

organizacja calkiem spoko, jednak ja troche inaczej do tego podchodze:

controllers
Name
ViewModels
ClassInput.css -> ClassInput { p FileInput F {get;set;} class FileInput {} }
ClassDisplay.css
Mappings
… -> other folders and classes req by controller
NameController.cs
views
ControllerName
View.cshtlm
GrouppedByControllerType
ControllerName
View.cshtml
public
css
js
app.js -> app.views.controllerName(); all views in one file

ale pomysl by przezucic jeszcze view jest calkiem niezly

rozbicia zas na akcje bym pewnie nie robil, raczej bym pomyslal o czyms takim http://lostechies.com/jimmybogard/2011/06/22/cleaning-up-posts-in-asp-net-mvc/

ja
ja
13 years ago

Zawsze mnie to zastanawia i w końcu muszę gdzieś o to zapytać. Load w NHibernate pobiera cały rekord w bazy po identyfikatorze. Rozumiem, jeżeli akurat w danej tabeli jest tylko kilka pól, np id, nazwa, to nie ma problemu. Co jednak w sytuacji, gdy w takiej tabeli jest pól przykładowo 30, a my potrzebujemy przerzucić do widoku tylko kilka wybranych, bo szczegóły w danej chwili nie są nam potrzebne? Używać get/load i później mapować to na na własne view modele? Czy w takich sytuacjach korzystać właśnie z Projections, którą udostępnia NHib? Wydaje mi się, że w celach wydajnościowych oczywiście należałoby używać projekcji, jednak wszędzie, gdzie nie spojrze, nawet w projektach z codeplexa, wszyscy jadą to właśnie w taki sposób, get/load i później dopiero mapowanie.

Gutek
13 years ago

@ja

load tworzy proxy tak samo jak get, roznica polega na tym:
1) get-> jezeli nie ma w cache i 2nd level cache entity, robi hit do bazy, jak nie ma entity to zwraca null, lub proxy
2) load-> tworzy proxy i nie uderza do bazy, jednak jak robi sie transaction commit i entity o danym ID nie istnieje w bazie danych zwracany jest wyjatek

ogolnie powinno sie uzywac Get i Load jak chce sie miec proxy ale to czy get czy load zalezy od sytuacji. napewno nie powinno sie robic Criteria po ID – w sensie, nie powinno sie robic by zwrocic tylko proxy po to by moc je przypisac gdzie indziej. zas oplaca sie robic QueryOver, LINQ whatever jezeli chce sie pominac SELECT N+1.

a wiec mapowanie na viewmodels, jest uzaleznione od tego czy istnieje mozliwosci select n+1 -> na przyklad blog post i comments do blog postu, chca pobrac to wszystko na raz, lepiej zrobic QueryOver etc. niz get. Ale jezeli nie ma szans na select n+1 to nalezy sie zastanowic jak chce sie to obsluzyc po stronie controllera -> get nie zwroci exception, load zwroci.

moze ktos jeszcze cos doda do tego :)

eric
eric
13 years ago

Podoba mi się takie rozłożenie kodu. Jednak gdy zapragniesz dodać kolejną akcję w innym pliku, to się posypie
na klasach do routngu i mappingu, bo nazwy te same. Interesuje mnie jeszcze, jak wywołujesz dodanie tych routingów i mappingów.
Gdyby to były tylko dwie klasy, ktore zapisałeś, to można z konstruktora. ale w takim przypadku? Chyba że w kolejnych akcjach jakoś można dodać kolejne mappingi/routingi do już tych istniejących klas. Prosiłbym o rozwinięcie tematu w tym kierunku.

procent
13 years ago

ja,
To zależy od kontekstu, od systemu, od przewidywanego obciążenia, od ilości danych… Tutaj skupiłem się na całkowicie innej kwestii.
1) w takim scenriuszu użyłbym Get() a nie Load(), ale w kontekście posta nie ma to znaczenia
2) nic nie stoi na przeszkodzie aby mieć więcej niż jedną klasę mapowaną na tabelę Company – może być Company zawierająca właściwości dla wszystkich kolumn, a może być np CompanyWithNotes zawierająca tylko id, nazwę i referencję do notatek
Z tym że nie ma sensu bawić się w takie rozróżnienia w systemie, dla którego nie zrobi to żadnej różnicy.
Z kolei przy pobieraniu więcej niż jednego rekordu często mapuję już na poziomie samego zapytania, żądając tylko tych danych które muszę wyświetlic w danym widoku (czyli pokrywające się np z kolumnami grida na ekranie).

procent
13 years ago

eric,
Masz rację w takim przypadku klasy mapowań i routingu zrobiłbym partial albo tworzył o unikalnych nazwach, np RoutingForSaveNote, MappingsForSaveNote etc.. Ale pewnie stanęłoby na partialach.

Rejestrację mapowań i routingu robię w jakimś app_start czy innym bootstraperze – wszystko automatycznie rejestruje mi się w Autofac, więc gdzieś przy starcie aplikacji mam coś takiego:
foreach (var m in container.Resolve<IEnumerable<IMappingProvider>>())
{
m.RegisterMap();
}

Szymon Pobiega
13 years ago

Awesome:) Bardzo mi się podoba. Chociaż ja osobiście nie wrzucałbym tego w partial classę opakowującą, tylko wrzucił jako osobne klasy do jednego katalogu. Ale idea jest cudowna:)

procent
13 years ago

Szymon,
Od 2 dni zagłębiam się bardziej w Fubu (w sumie napisanie tego posta mnie skłoniło do przyjrzenia się Fubu bliżej:) ) i tam wszystko opiera się na podejściu: coś takiego jak kontroler w ogóle nie jest potrzebne, ważne sa tylko AKCJE. I ta idea, jak i implementacja, BARDZO mi się podobają, polecam rzucenie okiem (pewnie coś o tym skrobnę za jakiś czas).

Łukasz
Łukasz
13 years ago

"Zastanawiałem się czy nie pójść o krok dalej i nie "scustomizować" zachowania MVC tak, aby jeszcze bardziej wyeksponować akcję jako główny element rozwiązania webowego. Chodzi o to, aby każda akcja otrzymała osobny katalog, a w nim zarówno przedstawiony wyżej kod C#, jak i widok cshtml. Ale tego jeszcze nie wypróbowałem."

To bardzo ciekawe podejście a ASP.NET MVC, coś podobnego jest u konkurencji chyba w Zend Framework, gdzie można dowolnie ustawiać sobie strukturę katalogów. Takie rozwiązanie które zaproponowałeś to zajebiście czytelna i skompresowana struktura projektu. Niby MapAreas ma poprawiać czytelność ale nadal jak widać tu http://haacked.com/archive/2008/11/04/areas-in-aspnetmvc.aspx na zrzucie struktura jest to nadal rozwleczona.

procent
13 years ago

Łukasz,
Areas to moim zdaniem trochę pomyłka. Co prawda korzystam z nich, ale… one po prostu dodają kolejny poziom organizacyjny, nie zajmując się źródłem problemu. A źródłem problemu jest zbyt chaotyczna i skomplikowana struktura. Po wprowadzeniu Areas nadal mam burdel – tyle że każdy burdel zamknięty jest we własnym folderze. Kilka odseparowanych od siebie burdeli może i jest lepsze niż jeden mega-burdel, ale im dłużej się nad tym zastanawiam tym mniej to do mnie przemawia.

Whut
13 years ago

Hej, w moim projekcie też się zastanawialiśmy nad organizacją katalogów tak, by wszystko dotyczące jednego "feature" było w jednym miejscu.

Wygrał układ, który dokładniej opisałem tutaj: http://dotnet.uni.lodz.pl/whut/post/2011/07/03/Better-ASPNET-MVC-folder-structure.aspx

Pokrotce wygląda on tak:
Areas\ // wolałbym nazwę "Features", ale Areas jest wymagane przez ASP.NET MVC
AREA#1\
Views\ // ten katalog też istnieje tylko po to by zadowolić ASP.NET MVC
CONTROLLER#1\ // bezpośrednio w tym katalogu są widoki
Code\ // tu jest controler, modele, mapowania, itp.
Content\ // tu js i css
Images\
CONTROLLER#2\
Code\
Content\
Images\

Shared\ // zwykle tu nic nie ma
Code\
Content\
Images\
AREA#2\

Views\
CONTROLLER#3\

Shared\ // layout page, error page, itp
Code\ // wspólny kod, np action filters
Content\ // css od layout page, wspólne javascripty
Images\

Zalety:
– gdy pracujesz na jednym kontrolerem, wszystko jest w jednym katalogu: Areas\AREANAME\Views\CONTROLLERNAME
– taki układ wyraźnie oddziela modele/js/css jednego kontrolera od drugiego, współdzielenie ich jest niezalecane
Wady
– głęboka struktura katalogów, zatem nawigowanie pomiędzy kontrolerami jest trudniejsze

Co sądzicie?

Whut
13 years ago

BTW. twoja koncepcja przypomina mi MVVM: partial klasa z jedna akcją kontrolera i modelami do niej to odpowiednik jednego ViewModelu.

Whut
13 years ago

Jeszcze jeden komentarz: rozbicie akcji kontrolera na oddzielne pliki jest fajny: zwiększa czytelność i mniej kodu jest do przejrzenia, by zrozumieć co się dzieje. Ale IMO prostszym rozwiązaniem jest rozbicie kontrolera na oddzielne klasy, czyli np. zamiast PersonController z metodami SaveNew/Edit dwa kontrolery: SavePersonController i EditPersonController.

Ten opisany przeze mnie wyżej układ katalogów jest pod takie podejście do kontrolerów: byłby tam area Persons z kontrolerami SaveController i EditController

procent
13 years ago

Whut,
Czy jeden kontroler partial, czy osobne kontrolery – nie ma to dla mnie znaczenia. Kontroler jest tylko paczką z akcjami.
A Twoja koncepcja mi pasuje, chociaż wydaje mi się że nie idzie o wiele dalej niż to co napisałem. Ale faktycznie akie wykorzystanie "Area" jest bardziej wygodne niż "standardowe", zalecane przez MS.
A nawigacja w kodzie nie jest problemem – Resharper to załatwia. Bez Resharpera to nie wiem czy bym w ogóle został przy VS:).

Whut
13 years ago

Fakt, jedyne praktyczna różnica to to, że zamiast partial klas używam areas:)

"Kontroler jest tylko paczką z akcjami" – muszę spojrzeć na FuBu żeby to poczuć

pawelek
pawelek
13 years ago

Witam,

u nas podobnie jak u WHUT’a.

Areas/
Nazwa Featura (zazwyczaj opcji w menu)/
Views/
Nazwa Controllera/
Code, Content, pliki cshtml

Projekt z testami odpowiada powyższemu tylko do 2 poziomu.
Areas/
Nazwa Feature/
pliki .cs z testami

Natomiast w projekcie odpowiadającym warstwie logiki.
Domain/
główne klasy + mapowiania nHibernate

Features/
Nazwa Featura (która niestety nie odpowiada Nazwie Featura z apliacji MVC)/
głównie pliki z handlerami agathy

W sumie tyle. Staramy się dzielić kod w stylu: jeśli masz jakiś Feature w aplikacji
to jest to osobny folder.

procent
13 years ago

pawelek,
Ayende pisał kiedyś o czymś podobnym, dodatkowo ekxplorując podziału architektury oprogramowania na "features and concepts": http://ayende.com/blog/4333/effectus-isolated-features

whut
whut
13 years ago

Właśnie się spotkałem z pawelkiem, okazało się, że siedzi biurko obok:)

Pomysł na podział jest z bloga Ayende:)

PrzypadkowyObserwator
PrzypadkowyObserwator
13 years ago

[quote]
wolałbym nazwę "Features", ale Areas jest wymagane przez ASP.NET MVC
[/qoute]
[quote]
// ten katalog też istnieje tylko po to by zadowolić ASP.NET MVC
[/quote]
Można w prosty sposób pozbyć się tych ograniczeń, dziedzicząc ViewEngine i podstawiając mu swoje ścieżki. Taką technikę stosuje np. SharpArchitecture (https://github.com/sharparchitecture/Sharp-Architecture/blob/1.9.6.0/src/SharpArch/SharpArch.Web/Areas/AreaViewEngine.cs)
Pozdrawiam
H.

PrzypadkowyObserwator
PrzypadkowyObserwator
13 years ago

Jeszcze odnosząc się do zaprezentowanego pomysłu – podoba mi się, ale mam kilka uwag :)
1. Chyba w każdym większym projekcie najwięcej czasu poświęca się na nawigację pomiędzy plikami. Jestem użytkownikiem SharpArchitecture, gdzie wraz z dobrodziejstwem inwentarza przychodzi oddzielenie widoków od kontrolerów (osobne biblioteki), więc gonitwy mam dwa razy więcej :)
2. Naprawdę piszecie osobne modele dla wejścia i wyjścia każdej metody? Matko ile wy musicie mieć klas w projektach… A potem aktualizacja tego to musi być masakra…
Przy klasach na których ‘cykl życia’ polega jedynie na istnieniu, kontroler ogranicza się do CRUD, a modele mam zwykle dwa – jeden dla listy i drugi do tworzenia i edycji – ten funkcjonuje zarówno dla wejścia jak i wyjścia. Obydwa dziedziczą po klasach bazowych, których świadomy jest kontroler. W dodatku operacja mapowania i "odmapowania" odbywa się w samym modelu a nie w kontrolerze. Dzięki temu sam kontroler często jest "anemiczny" bo po prostu dziedziczy po klasie bazowej a poszczególne metody są przeciążane jedynie w celu nadania uprawnień poprzez dekorację atrybutami.
3. Podoba mi się pomysł z przerzuceniem routingu w to miejsce. Ale znowu – dla większości zastosowań z którymi mam styczność, wystarczają mi 2-3 modele routingu które załatwiają sprawę. Znowu klasa bazowa i anemiczni potomkowie załatwiają problem
Ale… Może ja się nie znam? Chętnie podyskutuję jakby co :)

H.

procent
13 years ago

PrzypadkowyObserwator,
Ano z ViewEngine racja, spoko tip.

1. Co do nawigacji – resharper to the rescue, ale i tak otwieranie kilku malutkich plików jednoczesnie (nawet jesli samo ich znalezienie jest banalne z R#) to dla mnie osobiscie pewien dyskomfort.
2. Klas mogę mieć i milion, co za różnica? Tekst to tekst. A problemu z aktualizacją nie do końca rozumiem. Aktualizacja czego musi być masakrą? Przecież nie trzeba nigdy zmieniać wszystkich klas naraz, jednocześniej, tylko każda z nich odpowiada za jeden malutki wycinek systemu i jest niezależna od reszty.
No i te klasy są zwykle po prostu zbiorem get/set i niczym więcej, zwykłe DTO.
3. Akurat w ostatnim projekcie nadawałem ręcznie URL dla prawie każdej akcji osobno. Po 1) URLe musiały być po polsku, a po 2) – nie były zgodne ze strukturą kontrolerów. Więc tych definicji miałem masę.

Przypadkowy Obserwator
Przypadkowy Obserwator
13 years ago

ad1 ahhh więc do tego używa się resharpera ;) Robiłem do niego kilka podejść i nigdy się nie przekonałem. Ale może trzeba jeszcze raz…
ad2 Co do ilości klas – sama w sobie nic nie zmienia, choć ma wpływ np. na kompilację. Dlaczego masakrą – dlatego że jak dodajesz jakieś pole do klasy biznesowej to musisz je później propagować na co najmniej 2 miejsca. A potem jeszcze reguły walidacji, testowanie itp…
Chyba że masz jakąś sztuczkę która to automatyzuje?
ad3 Jak już pisałem – pomysł mi się podoba, a w szczególności jeśli wymagania narzucają tak rozbudowaną strukturę routingu.
pozdrawiam
H.

procent
13 years ago

Przypadkowy Obserwator,
1. Przedstawianie R# jako "narzędzia do nawigacji" jest dla niego krzywdzące, ALE gdyby faktycznie tak było (tzn gdyby R# oferował wyłącznie nawigację w kodzie) to i tak byłby warty dzisiejszej ceny. A że przy okazji dostaje się milion razy więcej to tym lepiej:).
2. Wpływ liczby klas/plików na kompilację… no nie wiem czy powinniśmy w ogóle się takimi rzeczami przejmować, to dla mnie trochę przesada. A właśnie mnogość tych klas powoduje, że modyfikacja klasy biznesowej NIE WYMUSZA zmian w X innych miejsc – a tylko w tych, gdzie jest to konieczne, czyli dla ekranów które faktycznie tych nowych informacji potrzebują. Dla mnie łatwiej tak, niż mieć 10x więcej informacji w jednym wspólnym modelu.

PrzypadkowyObserwator
PrzypadkowyObserwator
13 years ago

1. Co zabawne, licencję na R# mam – wygrałem na jakiejś konferencji, ale poważnie nie mogę się przekonać. Jestem przyzwyczajony do skrótów i własnych szablonów w VS, a R# zawsze mi wszystko rozwala. Pewnie gdyby go skonfigurować to dałby radę ale jakoś zawsze brakuje mi cierpliwości. A może strzelisz jakąś serię artykułów "Resharper dla starych wyjadaczy VS"?

2. Odnośnie liczby plików/klas – nie chciałbym żebyś mnie źle zrozumiał. Doskonale wiem, że każdy projekt ma inne wymagania, które mogą prowadzić do różnych ciekawych rozwiązań – podobnie jak przy dyskutowanym wcześniej routingu.
Oczywiście nie jestem zwolennikiem jednego wielkiego modelu, wyczerpującego wszystkie przypadki – we wszystkim należy zachować umiar. Nadal uważam, że największym problemem jest utrzymanie spójności pomiędzy klasą biznesową a modelami.
Clue problemu jest "Czy masz na to jakiś patent". Ja na przykład zacząłem eksperymentować z generatorami kodu i ta technika wydaje się być bardzo obiecująca. Niestety przygotowanie dobrego generatora jest czasochłonne, a przygotowanie generatora który będzie obejmował 100% przypadków – praktycznie niemożliwe. Ale to dyskusja na inny artykuł :)

A jeszcze odnośnie kompilacji – nie wiem jak Ty, ale ja kompiluję projekt bardzo często – czasem nawet co minutę, bo taki mam styl pracy. Coś zmieniam i kompiluję żeby się upewnić że jest ok. Jeśli kompilacja wydłuża się, automatycznie spada mi produktywność :)

Oraz – last but not least – im więcej klas tym dotfuskator bardziej głupieje :)

procent
13 years ago

1) Taką serię kiedyś puściłem (w 3 odcinkach), co prawda było to dość dawno i tyczy wersji chyba 3.x, ale wszystko co tam jest pokazane nie straciło na aktualności, polecam http://www.maciejaniserowicz.com/?tag=/c%23+via+r%23

2) Patentu jako takiego nie mam, ale na pewno nie będę szedł w kierunku generacji kodu. Po prostu widzę szkic UI i dane jakie mają być na nim pokazane -> i tworzę dla niego model. Nie szukam czy taki lub podobny już gdzieś istnieje. Po prostu każdy ekran/widok ma swoją własną klasę.

A co do kompilacji… znów się R# kłania:). Nie muszę kompilować co chwilę projektu bo resharper robi to za mnie w tle i pokazuje błędy jakie popełniłem. Na bieżąco.

Na temat dotfuscatora sie nie wypowiem bo nie uzywam.

pawelek
pawelek
13 years ago

Fakt zmiana biznesowa, pociąga za soba zmiany w DTO oraz modelu… Ale nie widzę innej możliwości.
Fajny tip z tym ViewEngine, ale jak mówił WHUT (przed chwila rozmawialiśmy) to jak zaglądał do kodu to słówko Views widział zahardkodowane w wielu miejscach. Sam nie patrzyłem więc to tylko taki assume :)

Natomiast refactoring tak wielu klas pociąga za sobą masakryczna robotę i spodziewać się można że czasem drobna zmiana przebiegająca przez cały projekt (jak wczorajsza zmiana typu ze string na AccountNumber) to kilka godzin roboty.

Pozdrawiam
P.

Whut
13 years ago

Właśnie sprawdziłem drugi raz, nie wiem, gdzie ja widziałem to "Views" czy "Areas" zahardcodowane w wielu miejscach. Teraz oprócz ViewEngine widzę je teraz tylko raz i to dodatkowo w klasie, która zdaje się, że jest unsupported.

A do komentarza wyżej: jak jest wiele modeli to jest łatwiej, IMO, tak jak pisał wyżej procent. My w naszej aplikacji mamy "masakryczną robotę" od czasu do czasu, bo oprócz wielu modeli mamy też wiele DTOsów, (to wynika z specyfiki projektu).

Kurs Gita

Zaawansowany frontend

Szkolenie z Testów

Szkolenie z baz danych

Książka

Zobacz również