Franz w “Psach” powiedział: “nie lubię Ruskich”. Ja teraz mówię: “nie lubię regionów”. Regiony to te małe śmierdziuchy rozpoczynane dyrektywą #region i kończone dyrektywą #endregion. To te potworki co pozwalają klasę z kilkoma tysiącami linii zwinąć do kilku linii, grupując kod choćby w bezsensowny sposób, i spełnić tym samym całkiem sensowną zasadę “klasa powinna mieścić się na jednym ekranie”.
Moje podejrzenie jest takie, że regiony dorzucono do specyfikacji C# oraz VS po to, by chować w nich kod wygenerowany przez przeróżne designery. Zanim okazało się, że lepiej je w ogóle wyrzucić do innego pliku przy pomocy partial classes.
Jeśli klasa ma tak dużo kodu, że trzeba go grupować/zwijać, to najprawdopodobniej jest za duża. Pamiętacie Single responsibility principle, podstawę SOLID? Ano więc właśnie… Nie wydaje mi się, aby w tej regule chodziło o “każdy region powinien zawierać kod implementujący jedną rzecz”.
Ale skoro już przy tym jesteśmy, to jeśli nawet wrzucasz regiony do wielkich klas i co czyni cię szczęśliwym: faktycznie zrób to w ten sposób. To znaczy nie “regionalizuj” składowych klasy po ich typach, nie twórz regionów “public methods”, “fields”, “protected methods”, “event handlers” itd. Co to daje? Ułatwia nawigację? Do skakania po metodach/polach/właściwościach i tak nie powinno się używać klikacza. Jeżeli regiony i ogromne klasy ci naprawdę nie przeszkadzają to chociaż pogrupuj kod według jego odpowiedzialności. Na przykład wszystkie metody, pola, handlery itd umożliwiające użytkownikowi zmianę hasła w ogromnym kolosie UserService. A nuż kolejnym krokiem będzie rozbicie tego na mniejsze klasy, dzięki czemu nasz wszechświat stanie się lepszym miejscem do życia?
Dodatkowo dość mocno “konfunduje” mnie wrzucanie regionów nawet do najmniejszych klas. Taka “konwencja”. Klasa ze zwiniętymi regionami: 14 linii. Klasa ze SKASOWANYMI regionami: 16 linii. Po co? Nie wiem, a spotkałem się z tym ostatnio w dwóch zupełnie osobnych projektach, z zupełnie niezależnych firm. Wrzucone są chyba tylko po to, żeby programista zapoznający się z kodem nie mógł od razu zobaczyć kodu, tylko musiał się przeklikać przez krzyżyki.
Dla takich programistów zmęczonych ciągłym rozwijaniem regionów mam dwa tipy. Po pierwsze: skrót “ctrl+m+l” rozwinie wszystko w aktualnie edytowanym pliku. Po drugie: opcja tools -> options -> text editor -> c# -> advanced -> uncheck “enter outlining mode..” powoduje automatyczne rozwinięcie regionów we wszystkich plikach po ich otwarciu w VS. Wtedy klikać nie trzeba i pozostaje pogodzić się z tym, że kodu jest więcej niż mogłoby być.
Osobiście zamiast regionów wolałbym już nawet podzielenie klasy na kilka plików (partial classes). Może nie zamykać implementacji jakiegoś interfejsu w region “ISomeNterface implementation” – a wywalić to do pliku obok? Który to plik można sobie nawet “shierarchizować” w solution explorerze, o czym pisałem dawno, dawno temu, za górami i lasami, w poście ““Zwijanie” plików w Visual Studio“. Sprawdziłem to podejście – jest całkiem okej przy konieczności implementowania kilku sporych interfejsów w jednym miejscu.
Niedawno na twitterze wywołałem krótką dyskusję odnośnie regionów właśnie. Rob Ashton fajnie ją podsumował:
@rafek @fzawada @maniserowicz cough, the only valid reason pic.twitter.com/J37hEw3aph
— Mr 'Rob' Ashton (@RobAshton) March 8, 2013
Heh, i śmieszna sprawa: Gutek później podesłał mi link do mojego własne posta, z roku 2008: Pimp my code – 11 miniporad. Pierwsza porada, jakiej wówczas udzieliłem, to: “Chwała pomysłodawcy regionów. A tym, którzy mogą ich używać, a nie używają – na pohybel!“. AAAAHHHAAAdżdżdż!!! To dźwięk siarczystego liścia podróżującego w czasoprzestrzeni ku mej ówczesnej cielesnej powłoce. Pokazuje to, że nie tylko politycy zmieniają poglądy jak popadnie. Widocznie też jestem jak kogucik na wietrze: tam zapieje, gdzie wiatr zawieje. Może to i dobrze?
Trochę to szukanie dziury w całym. Ktoś lubi to używa a ktoś nie lubi to nie używa. Ja osobiście lubię podpisać sobie fragment kodu regionem w mvc. Łatwiej mi się później odnaleźć. Tym bardziej że w kontrolerze (np Home) mam wiele widoków, które właśnie sobie oddzielam regionami. Np. #region Index – i wewnątrz mam wszystkie akcje powiązane z view Index, tak więc insert,update, delete dla np. grida, jak i partialowe elementy (wyskakujące okna), podstrony.
P.S. Co do wypowiedzi Pana Rafała ‘cennych bajtów’ bez przesady :D
Sebastian,
No właśnie to jest problem – ktoś lubi to używa, a potem ktoś inny musi z tym walczyć. Akurat organizacji kontrolerów w MVC pisałem już kiedyś, nie znoszę takich rozdętych plików z kontrolerami bo jak to potem wygląda i jak się w tym odnaleźć? http://www.maciejaniserowicz.com/2011/06/30/troche-inna-organizacja-kodu-w-asp-net-mvc/ .
Właściwie to w ogóle nie znoszę kontrolerów bo są zbędne, temu tak mi się podoba Nancy czy Fubu i Simple.Web – wyrzucają ten durny koncept z frameworka… ale to chyba osobny temat:)
Mialem ta sposobnosc, ze C# uczylem sie na zywym projekcie, ktorego budowe oparto na zapozyczonych wzorcach i technikach z zachodnich firm. To bylo niemal dekade temu.
Dzisiaj kiedy patrze w ten kod widze mase regionow, ktorymi wtedy probowalem zapanowac nad cala ta zlozonoscia.
Przy refaktoryzacji tego projektu (dla “sportu”) mam podobne spostrzezenia.
Tez uzywalem chetnie regionow, wtedy moje obiektowe kung-fu polegalo na uzywaniu obiektowego jezyka.
Popelniamy bledy, a kiedy po latach budza usmieszek z “cielęcia”, znaczy to tyle, ze sie rozwinelismy.
Ja również należę do osób, które lubują się w regionowaniu kodu. Uważam, że wprowadza to swego rodzaju porządek w plikach cs, a tym samym poniekąd stoi na straży czytelnego kodu.
Nie lubię i zupełnie nie rozumiem natomiast, kiedy każda metoda owinięta jest w region – come on! To już gruba przesada.
Swoją drogą widziałem tego tweet’a Roba – rewelacja! xD
Powiem ci że np. w XNA jak robisz od podstaw obsługe eventów to powstaja takie ogromne klasy że się w pale nie mieści ;( i regony wtedy jestem zmuszony urzywać. Ale raczej w normalnych projektach nie używam.
Myślę, że balansujemy po cienkiej granicy pomiędzy obiektywnie dobrymi praktykami programowania a indywidualnymi preferencjami konkretnego człowieka. Piszesz żeby chociaż grupować kod pod względem odpowiedzialności. A jeśli regiony stanowią rozwinięcie tego podejścia? Jeżeli w danej chwili pracujesz nad implementacją jednej tylko odpowiedzialności, to czemu niezawracanie sobie głowy pozostałymi i tymczasowe ich ukrycie ma być szkodliwe?
pjsen,
Wiele niezależnych odpowiedzialności nie powinno znajdować się w jednym pliku ani w jednej klasie – o czym wspomniałem przytaczając SRP. Wtedy regiony stają się zbędne.
procent,
wiele niezależnych odpowiedzialności nie powinno się znajdować w tym samym pliku — zgoda. A zależnych, przynajmniej w pewnym stopniu? W mojej ocenie regiony mogą być użyteczne w niektórych sytuacjach “pośrednich”, gdy wyodrębnianie kolejnych plików niekoniecznie będzie zasadne. Np. w code-behind niewielkiego okna WPF trudno mi sobie wyobrazić rozdzielenie go na kilka plików, w końcu zawarte w nim funkcjonalności dotyczą wspólnego elementu — okna. Regiony mogą w takich sytuacjach wprowadzić uporządkowanie, które — nie rozumiem dlaczego — ma zawsze być złe.
pjsen,
VS sam rozbija przecież to na kilka plików. Poza tym akurat do wszelakich code-behind nie stosuję żadnych reguł, to śmietnik którego jedynym zadaniem jest walczenie z frameworkiem i przekazanie sterowania dalej. Tutaj do regionów się nie przyczepię o ile nie ma w takim kodzie żadnej logiki, a jedyne wywołania do presentera.
Grupowanie metod po akcesorach, typach… idąc dalej zróbmy regiony:
#region metody rozpoczynające się na A
…
#endregion
#region metody rozpoczynające się na B
…
#endregion
regiony – fuj!
Pozwolę sobie na mały offtop. Niedawno została przypomniana stronka z wyświetlaniem chmury w przeglądarce. Tutaj można pobawić się autami:
http://carvisualizer.plus360degrees.com/threejs/
Najlepiej w przeglądarce chrome, w ff i ie nie wszystko sie wyświetla prawidłowo.
A jeśli idzie o regiony to czasami stosowałem jak klasa miała większą ilość fieldów, albo kilka konstruktorów. Nie uważałem żeby to było złe. Natomiast zamykanie w regiony grup metod czy (omg!) kodu wewnątrz metody powinno skłonić do zastanowienia czy na pewno wszystko jest ok.
W wielu kwestiach masz rację, ale kojarzę przynajmniej jeden przypadek, gdy regiony znacznie ułatwiają życie – w ViewModelach (MVVM) przy implementacji komend. Jako że na każdą komendę składają się zwykle 3 elementy (property oraz metody can execute i execute) regiony znacząco usprawniają pracę z takimi plikami – które niestety muszą być czasem przydługawe. OK, można je rozbić na kilka plików – ale zwykle utrudniło by to tylko ogarnięcie takiego VMa.
Generalizując – wszystko jest dla ludzi, tylko trzeba wiedzieć kiedy przestać ;)
Jestem w 100% za – na pohybel regionom! W tysiącach linijek które spotkałem, zawsze były one po prostu metodą stosowaną do chowania paskudnego kodu za nagłówkiem. “Regionalizować” to trzeba powiązania pomiędzy obiektami w systemie, a nie linijki w plikach.
Regionalna opinia o #regionach | Maciej Aniserowicz o programowaniu…
Dziękujemy za dodanie artykułu – Trackback z dotnetomaniak.pl…
No dobra, a popatrzmy na regiony od innej strony – jako narzedzie do ujednolicania kodu. W projekcie w ktorym dwie lub wiecej osob zajmuje sie jedna warstwa mamy ryzyko iz klasy poszczegolnych osob beda sie znaczaca od siebie roznily (czasem jest to prawdziwe dla jednej osoby). Wydaje sie, ze to nie jest zaden problem, iz propertisy/implementacje interfacue itp moga byc na poczatku pliku, koncu lub w srodku – dopoki to nie my musimy sie zajmowac takimi klasami. Otwierajac plik z “nieznana” mi klasa chce aby wygladal tak samo jak inna klasa z tej samej warstwy, ktora zajmowalem sie wczoraj – oszczedza to czas. Tutaj z pomoca przychodza regiony – oczywiscie przelozony musi wymoc na pracownikach stosowanie sie do stworzonego wczesniej szablonu klasy z regionami, ale nie jest to tak ciezkie jak w przypadku gdy zakladamy iz przykladowe propertisy maja byc pierwszymi elementami w klasie (tego wg mnie juz wymoc sie nie da :)). Implementacje klas z tej samej warstwy powinna byc do siebie podobne, wiec dlaczego nie ulatwic sobie zycia jeszcze bardziej i zalozyc iz wyglad klas powinien byc podobny (znam jedna klase – znam wszystkie).
Maciek stwierdzil, iz szukajac czegos w klasie nie powinno sie klikac – ma racje – problem kiedy ktos klasy nie zna i wogole nie wie czego szuka (oczywiscie mozna do tego wykorzystac rozne dodatki do vs ktore ulatwiaja nawigacje po pliku, tylko ze czasem pracuje sie na express edition/mamy swiezego programiste itp) – regiony wtedy moga znacznie pomoc (oczywiscie sensownie stosowane).
Co do partial class – dla mnie sluza one tylko do oddzielania kodu generowanego przez vs od mojego kodu i dzielenie klasy na kilka jest czyms zlym (pozytywny wplyw javowcow :) )
Na koniec co tego podobienstwa klas – tak wiem ze nie zawsze jest to mozliwe :)
Marek,
Dla mnie to że “widziałeś jedną klasę to znasz je wszystkie” oznacza, że projekt jest nudny.
Co z tego że properties są na początku, i są zamknięte w region, i w każdej inne klasie też tak jest? Nie potrafię zrozumieć co mi taka informacja upraszcza, jak skraca pracę.
Też uważam że regiony są be, a że muszę żyć z ludzmi którzy ich niestety używają mam takie rozszerzenie.
http://visualstudiogallery.msdn.microsoft.com/0ca60d35-1e02-43b7-bf59-ac7deb9afbca
Robi tyle że regiony są domyślnie rozwinięte a ich font zmniejszony.
Co do tych properties-ow – regiony nie dadza mi nic ponadto ze wszystkie pliki/klasy beda mialy ta sama strukture – tylko tyle lub az tyle. Wchodzac do pliku nie chce nic szukac (nie wazne po co) – chce machinalnie wiedziec gdzie dany element powinien sie znajdowac. Zgodze sie ze sa do tego lepsze narzedzia lecz nie zawsze mozna z nich korzystac. Jesli ktos potrafi zmusic kilka osob aby wszyscy trzymali taki sam schemat podczas tworzenia klas to regiony nie sa mu potrzebne – tylko ja w cos takiego nie wierze (mozna mnie nazwac czlowiekiem malej wiary ;)).
Co do podejscia “widziałeś jedną klasę to znasz je wszystkie” – zgodze sie, ze taki projekt jest nudny (nie mylic z zacofanym), mniej wydajny itp. Tylko ze taki nudny projekt jest latwiej utrzymac, a to jest zbyt duzy plus aby go ignorowac. Zreszta mnie przykladowo kazdy projekt nudzi po stworzeniu glownych bazowych mechanizmow.
Tak na koniec jak czytalem negatywne opinie dotyczace regionow – wiekszosc (a moze nawet wszystkie) mowia ze regiony sa zle i jako przyklad podaja ich bledne zastosowanie (przykladowo regiony wewnatrz metody o_0). W ten sam sposob mozna powiedziec ze interface’y za zle (interface’y z metodami na dana litere), unit testy, orm-y, podzial na wartstwy itp. Regiony nie sa jakims cudem, nie gwarantuja ze projekt padnie/odniesie sukces. Moga zwiekszyc wg mnie czytelnosc pliku gdy sa sensownie stosowane i tylko tyle (one nie maja nam pomoc tylko osobom ktore przyjda po nas).
Ps
Co do rozszerzenia wskazanego przez Janka – fajne rozwiazanie dla kogos dla kogo ctrl+m+l to za duzo klawiszy :).
A co z ukrywaniem właśnie implementacji poszczególnych interfejsów, jeśli klasa musi zaimplementować kilka interfejsów, to ukrycie tych implementacji pod poszczególnymi regionami nie będzie dobrym rozwiązaniem ?