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.


Komentarze

dotnetomaniak.pl

30 czerwca 2011 10:03

Trochę inna organizacja kodu w ASP.NET MVC

Dziękujemy za publikację - Trackback z dotnetomaniak.pl

procent

30 czerwca 2011 11:26

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

30 czerwca 2011 12:16

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 lostechies.com/.../

ja

30 czerwca 2011 14:41

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

30 czerwca 2011 15:06

@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

30 czerwca 2011 15:26

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

30 czerwca 2011 17:24

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

30 czerwca 2011 17:31

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

1 lipca 2011 08:56

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

1 lipca 2011 13:03

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

2 lipca 2011 12:51

"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 haacked.com/.../areas-in-aspnetmvc.aspx na zrzucie struktura jest to nadal rozwleczona.

procent

2 lipca 2011 13:07

Ł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

3 lipca 2011 14:34

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: dotnet.uni.lodz.pl/.../...VC-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

3 lipca 2011 14:40

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

Whut

3 lipca 2011 14:52

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

4 lipca 2011 06:45

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

4 lipca 2011 20:04

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

5 lipca 2011 07:40

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

5 lipca 2011 08:16

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

whut

6 lipca 2011 08:35

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

Pomysł na podział jest z bloga Ayende:)

PrzypadkowyObserwator

7 lipca 2011 23:17


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

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 (github.com/.../AreaViewEngine.cs)
Pozdrawiam
H.

PrzypadkowyObserwator

7 lipca 2011 23:38

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

8 lipca 2011 08:34

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

8 lipca 2011 09:30

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

8 lipca 2011 10:47

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

8 lipca 2011 12:32

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

8 lipca 2011 12:42

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

8 lipca 2011 12:43

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

28 lipca 2011 21:00

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).

Komentarze zamknięte