Czy # regiony to zapach antypatternowy lub zapachowy?

264

C # pozwala na użycie słów kluczowych #region/ #endregiondo zwijania obszarów kodu w edytorze. Ilekroć to robię, robię to, aby ukryć duże fragmenty kodu, które prawdopodobnie mogłyby zostać przekształcone w inne klasy lub metody. Na przykład widziałem metody, które zawierają 500 wierszy kodu z 3 lub 4 regionami tylko po to, aby można było nim zarządzać.

Czy rozsądne wykorzystanie regionów jest oznaką kłopotów? Wydaje mi się, że tak jest.

Craig
źródło
9
FYI: CodeMap praktycznie eliminuje potrzeby regionów. visualstudiogallery.msdn.microsoft.com/… - Kliknij, aby przejść do metody / atrybutu / czegokolwiek. Używam go codziennie i to niesamowite, ile zyskujesz na produktywności, a także pod względem poznawczym. Otrzymujesz znacznie wyraźniejszy „widok z lotu ptaka” na klasę.
7
Czy ktoś może zrobić z tego wiki? Nie ma właściwej lub złej odpowiedzi na to pytanie (cóż, w granicach rozsądku), jest ono prawie całkowicie subiektywne.
Ed S.
6
Za to, co jest warte, Jeff Atwood ich nienawidzi . Twierdzi, że ukrywają zły kod.
Brian
3
Zapach kodowy to programista, który nie bierze prysznica i nie używa dezodorantu!
marko
5
Starannie wykonane regiony śmierdzącym kodem to to, co kilka wycisków Febreeze robi na chrupiącej kanapie. Sprawia, że ​​jest to do zniesienia, dopóki nie znajdziesz pieniędzy (czasu) na ich wymianę.
Newtopian,

Odpowiedzi:

284

Zapach kodu jest objawem wskazującym na problem w projekcie, który potencjalnie może zwiększyć liczbę błędów: nie dotyczy to regionów, ale regiony mogą przyczyniać się do tworzenia zapachów kodu, takich jak długie metody.

Od:

Anty-wzorzec (lub anty-wzór) to wzorzec stosowany w operacjach społecznych lub biznesowych lub inżynierii oprogramowania, który może być powszechnie stosowany, ale w praktyce jest nieskuteczny i / lub przynosi efekt przeciwny do zamierzonego

regiony anty-wzorami. Wymagają więcej pracy, która nie poprawia jakości ani czytelności kodu, co nie zmniejsza liczby błędów, a może tylko komplikować kod do refaktoryzacji.

Nie używaj regionów wewnątrz metod; zamiast tego refaktoryzuj

Metody muszą być krótkie . Jeśli w metodzie jest tylko dziesięć linii, prawdopodobnie nie użyłbyś regionów do ukrycia pięciu z nich podczas pracy z innymi pięcioma.

Ponadto każda metoda musi robić jedną i jedyną rzecz . Z drugiej strony regiony mają na celu oddzielenie różnych rzeczy . Jeśli twoja metoda wykonuje A, to B, logiczne jest utworzenie dwóch regionów, ale jest to złe podejście; zamiast tego powinieneś przeredagować metodę na dwie osobne metody.

Zastosowanie regionów w tym przypadku może również utrudnić refaktoryzację. Wyobraź sobie, że masz:

private void DoSomething()
{
    var data = LoadData();
    #region Work with database
    var verification = VerifySomething();
    if (!verification)
    {
        throw new DataCorruptedException();
    }

    Do(data);
    DoSomethingElse(data);
    #endregion

    #region Audit
    var auditEngine = InitializeAuditEngine();
    auditEngine.Submit(data);
    #endregion
}

Zwinięcie pierwszego regionu w celu skoncentrowania się na drugim jest nie tylko ryzykowne: możemy łatwo zapomnieć o wyjątku zatrzymującym przepływ ( returnzamiast tego mogłaby istnieć klauzula ochronna , co jest jeszcze trudniejsze do zauważenia), ale również miałoby problem jeśli kod powinien być refaktoryzowany w ten sposób:

private void DoSomething()
{
    var data = LoadData();
    #region Work with database
    var verification = VerifySomething();
    var info = DoSomethingElse(data);

    if (verification)
    {
        Do(data);
    }

    #endregion

    #region Audit
    var auditEngine = InitializeAuditEngine(info);
    auditEngine.Submit(
        verification ? new AcceptedDataAudit(data) : new CorruptedDataAudit(data));
    #endregion
}

Teraz regiony nie mają sensu i nie można odczytać i zrozumieć kodu w drugim regionie bez spojrzenia na kod w pierwszym.

Innym przypadkiem, który czasem widzę, jest ten:

public void DoSomething(string a, int b)
{
    #region Validation of arguments
    if (a == null)
    {
        throw new ArgumentNullException("a");
    }

    if (b <= 0)
    {
        throw new ArgumentOutOfScopeException("b", ...);
    }
    #endregion

    #region Do real work
    ...
    #endregion
}

Kuszące jest używanie regionów, gdy sprawdzanie poprawności argumentów zaczyna się od dziesiątek LOC, ale istnieje lepszy sposób na rozwiązanie tego problemu: ten używany przez kod źródłowy .NET Framework:

public void DoSomething(string a, int b)
{
    if (a == null)
    {
        throw new ArgumentNullException("a");
    }

    if (b <= 0)
    {
        throw new ArgumentOutOfScopeException("b", ...);
    }

    InternalDoSomething(a, b);
}

private void InternalDoSomething(string a, int b)
{
    ...
}

Nie używaj regionów poza metodami do grupowania

  • Niektóre osoby używają ich do grupowania pól, właściwości itp. Takie podejście jest błędne: jeśli kod jest zgodny z StyleCop, to pola, właściwości, metody prywatne, konstruktory itp. Są już zgrupowane i łatwe do znalezienia. Jeśli nie, nadszedł czas, aby zacząć myśleć o stosowaniu reguł, które zapewnią jednolitość w całej bazie kodu.

  • Inne osoby używają regionów, aby ukryć wiele podobnych podmiotów . Na przykład, jeśli masz klasę zawierającą sto pól (co daje co najmniej 500 linii kodu, jeśli policzysz komentarze i białe znaki), możesz ulec pokusie, aby umieścić te pola w regionie, zwinąć je i zapomnieć o nich. Ponownie robisz to źle: mając tak wiele pól w klasie, powinieneś lepiej pomyśleć o zastosowaniu dziedziczenia lub pokroić obiekt na kilka obiektów.

  • Wreszcie, niektórzy ludzie mają pokusę, aby użyć regionów do grupowania powiązanych ze sobą rzeczy : zdarzenia z jego delegatem lub metody związanej z IO z innymi metodami związanymi z IO itp. W pierwszym przypadku staje się bałaganem, który jest trudny do utrzymania , Przeczytaj i zrozum. W drugim przypadku lepszym rozwiązaniem byłoby prawdopodobnie utworzenie kilku klas.

Czy regiony mają dobre zastosowanie?

Nie. Nie było użycie starszego typu: kod wygenerowany. Mimo to narzędzia do generowania kodu muszą po prostu używać klas częściowych. Jeśli C # ma obsługę regionów, to głównie dlatego, że używa tego starszego typu, a ponieważ zbyt wiele osób używa regionów w swoim kodzie, nie będzie możliwe ich usunięcie bez zerwania istniejących baz kodów.

Pomyśl o tym jak o goto. Fakt, że język lub IDE obsługuje funkcję, nie oznacza, że ​​należy jej używać codziennie. Reguła StyleCop SA1124 jest jasna: nie należy używać regionów. Nigdy.

Przykłady

Obecnie dokonuję przeglądu kodu mojego współpracownika. Baza kodów zawiera wiele regionów i jest właściwie doskonałym przykładem zarówno tego, jak nie używać regionów, jak i dlaczego regiony prowadzą do złego kodu. Oto kilka przykładów:

4000 potworów LOC:

Niedawno przeczytałem gdzieś na Programmers.SE, że gdy plik zawiera zbyt wiele usings (po wykonaniu polecenia „Usuń nieużywane zastosowania”), to dobry znak, że klasa wewnątrz tego pliku robi zbyt wiele. To samo dotyczy rozmiaru samego pliku.

Podczas przeglądania kodu natrafiłem na plik LOC o wielkości 4000. Okazało się, że autor tego kodu po prostu skopiował i wkleił tę samą 15-liniową metodę setki razy, nieznacznie zmieniając nazwy zmiennych i wywoływaną metodę. Prosty regex pozwolił przyciąć plik z 4 000 LOC do 500 LOC, po prostu dodając kilka ogólnych; Jestem całkiem pewien, że dzięki bardziej sprytnemu refaktoryzacji ta klasa może zostać zredukowana do kilkudziesięciu wierszy.

Korzystając z regionów, autor zachęcił się do zignorowania faktu, że kod jest niemożliwy do utrzymania i źle napisany, a także do znacznego skopiowania kodu zamiast go przefiltrować.

Region „Do A”, Region „Do B”:

Innym doskonałym przykładem była metoda inicjalizacji potwora, która po prostu wykonała zadanie 1, następnie zadanie 2, następnie zadanie 3 itd. Było pięć lub sześć zadań, które były całkowicie niezależne, każde inicjując coś w klasie kontenera. Wszystkie te zadania zostały zgrupowane w jedną metodę i zgrupowane w regiony.

Miało to jedną zaletę:

  • Metoda była dość jasna do zrozumienia, patrząc na nazwy regionów. To powiedziawszy, ta sama metoda raz zrefaktoryzowana byłaby tak samo jasna jak oryginał.

Z drugiej strony problemy były liczne:

  • Nie było oczywiste, czy istnieją zależności między regionami. Mamy nadzieję, że nie było ponownego użycia zmiennych; w przeciwnym razie utrzymanie może być koszmarem jeszcze bardziej.

  • Metoda była prawie niemożliwa do przetestowania. Skąd miałbyś łatwo wiedzieć, czy metoda, która wykonuje dwadzieścia rzeczy na raz, robi to poprawnie?

Region pól, region właściwości, region konstruktora:

Sprawdzony kod zawierał także wiele regionów grupujących wszystkie pola razem, wszystkie właściwości razem itp. To miał oczywisty problem: wzrost kodu źródłowego.

Kiedy otworzysz plik i zobaczysz ogromną listę pól, będziesz bardziej skłonny do refaktoryzacji klasy, a następnie pracy z kodem. W regionach masz nawyk załamywania się i zapominania o tym.

Innym problemem jest to, że jeśli robisz to wszędzie, tworzysz regiony jednobryłowe, co nie ma żadnego sensu. Tak było w przypadku kodu, który sprawdziłem, gdzie było wiele #region Constructorzawierających jednego konstruktora.

Wreszcie pola, właściwości, konstruktory itp. Powinny już być w porządku . Jeśli są i są zgodne z konwencjami (stałe zaczynające się od dużej litery itp.), Jest już jasne, gdzie na typie elementów zatrzymuje się, a inne zaczynają, więc nie trzeba jawnie tworzyć dla tego regionów.

Arseni Mourzenko
źródło
13
Wydaje mi się, że istnieje co najmniej kilka możliwych do obrony zastosowań # regionów - np. Zwijanie klauzul ochronnych (sprawdzanie parametrów wejściowych), które, jeśli pozostaną niezakończone, odwrócą istotę lub „mięso” metody. Innym przykładem jest obsługa wyjątków na granicach API; często nie chcesz wpływać na ślad stosu, wywołując inne metody, aby zawinąć wyjątek, więc masz kilka linii kodu do zawijania i ponownego rzucania. Jest to również często nieistotny kod i można go bezpiecznie zwinąć.
Daniel B
9
Sprawdzenie autentyczności. Widziałem wiele # regionów między metodami, które były pomocne. Kiedy masz kilkaset metod liniowych z zagnieżdżoną logiką sterowania z dziesiątkami do setek linii w / w niektórych z nich - na szczęście idiota przynajmniej umieścił w regionach.
radarbob
37
@radarbob: krótko mówiąc, regiony są pomocne w kiepskim kodzie, który nie powinien istnieć w ogóle.
Arseni Mourzenko
41
-1 (gdybym miał reputację). Nawet jeśli członkowie twojego typu są dobrze zorganizowani i rozdzieleni, może być ich dużo. Regiony oszczędzają konieczności przewijania 10 lub 12 właściwości oraz powiązanych funkcji pobierających i ustawiających, aby przejść do metody, nad którą chcesz pracować. Jedyną alternatywą jest zawalenie wszystkich twoich nieruchomości indywidualnie, co nie jest moim fanem. Regiony pokazu / ukrywania na dużą skalę są niezwykle przydatne. Zgadzam się jednak co do regionów wewnątrz metody.
Asad Saeeduddin
14
Absolutnie nie zgadzam się z tą odpowiedzią: smród kodu i region nie mają ze sobą nic wspólnego. Jeśli twój kod śmierdzi, śmierdzi regionami lub bez nich. Używam regionów, aby podzielić moje klasy na regiony. Ogólnie jednak trzymam się tego samego wzorca: właściwości publiczne, metody publiczne, pola prywatne, metody prywatne. To jedyny użytek, dla którego miałbym regiony. Cokolwiek innego, prawdopodobnie łamiesz zasadę SRP w swoim kodzie.
Alexus
113

To dla mnie niewiarygodne, jak wielu ludzi tak nienawidzi regionów!

Zgadzam się całkowicie z tyloma ich zastrzeżeniami: wbicie kodu w #regioncelu ukrycia go przed widokiem jest złą rzeczą. Podział klasy na #regionsmoment, kiedy należy ją zrefaktoryzować na osobne klasy, jest oczywiście błędem. Używanie #regiondo osadzania zbędnych informacji semantycznych jest, no cóż, zbędne.

Ale żadna z tych rzeczy nie oznacza, że ​​jest coś nieodłącznie związanego z używaniem regionów w kodzie! Mogę tylko założyć, że sprzeciw większości ludzi wynika z pracy w zespołach, w których inni są skłonni do niewłaściwego korzystania z funkcji IDE takich jak ta. Mam luksus samodzielnej pracy i doceniam sposób, w jaki regiony pomogły w organizacji mojego przepływu pracy. Może to moje zaburzenie obsesyjno-kompulsywne, ale nie lubię na ekranie pękać kodu na raz, bez względu na to, jak starannie i elegancko jest napisane. Rozdzielenie rzeczy na logiczne regiony pozwala mi zwinąć kod, którego nie obchodzi mnie, do pracy nad kodem, który robiętroszczyć się o. Nie ignoruję źle napisanego kodu, nie ma sensu refaktoryzować go więcej niż jest w rzeczywistości, a dodatkowa organizacja „meta” ma charakter opisowy, a nie ma sensu.

Teraz, gdy spędziłem więcej czasu pracując w C ++, programując bardziej bezpośrednio do Windows API, żałuję, że wsparcie dla regionów nie było tak dobre, jak dla C #. Można argumentować, że użycie alternatywnej biblioteki GUI uczyniłoby mój kod prostszym lub bardziej przejrzystym, eliminując w ten sposób potrzebę usuwania zbędnych szumów z ekranu, ale mam inne powody, dla których nie chcę tego robić. Jestem wystarczająco biegły w posługiwaniu się klawiaturą i IDE, aby rozwinąć / zwinąć kod podzielony na regiony zajmuje mniej niż ułamek sekundy. Czas, który oszczędzam na sile mózgowej, próbując ograniczyć moją świadomą koncentrację tylko do kodu, nad którym obecnie pracuję, jest więcej niż wart. Wszystko należy do jednej klasy / pliku, ale nie wszystkie jednocześnie na moim ekranie.

Chodzi o to, że używanie #regionsdo oddzielania i logicznego dzielenia kodu nie jest złą rzeczą, której należy unikać za wszelką cenę. Jak podkreśla Ed, nie jest to „zapach kodu”. Jeśli Twój kod pachnie, możesz być pewien, że nie pochodzi on z regionów, ale z dowolnego kodu, który próbowałeś zakopać w tych regionach. Jeśli funkcja pomaga ci lepiej zorganizować się lub napisać lepszy kod, to mówię, aby go użyć . Jeśli stanie się to przeszkodą lub okaże się, że używasz go nieprawidłowo, przestań go używać. Jeśli najgorsze stanie się najgorsze, a ty będziesz zmuszony pracować w zespole z ludźmi, którzy go używają, zapamiętaj skrót klawiaturowy, aby wyłączyć opisywanie kodu: Ctrl+ M, Ctrl+P. I przestań narzekać. Czasami mam wrażenie, że jest to kolejny sposób, w jaki ci, którzy chcą być postrzegani jako „prawdziwi”, „hardkorowi” programiści, lubią próbować i sprawdzić się. Nie ma nic lepszego niż unikanie regionów niż unikanie kolorowania składni. Nie czyni cię bardziej twórcą macho.

Biorąc to wszystko pod uwagę, regiony w metodzie są po prostu nonsensem. Za każdym razem, gdy zechcesz to zrobić, powinieneś refaktoryzować się do osobnej metody. Bez wymówek.

Cody Gray
źródło
9
Dobrze powiedziane. Użycie regionów do organizacji nie jest bardziej szkodliwe niż przełączanie opcji IDE „zobacz białe znaki”. To osobiste preferencje.
Josh
24
Pracując na WPF z ViewModels, które mają 10 lub 20 właściwości, które po prostu zawijają właściwości na moim modelu, uwielbiam regiony - mogę po prostu schować te właściwości w regionie (nigdy nie trzeba ich dotykać) i pilnować odpowiedniego kodu.
Kirk Broadhurst
4
Kompletnie się zgadzam. W .NET 2.0 właściwości mają około 8-10 linii. Kiedy masz ponad 20 właściwości w klasie, zajmują dużo miejsca. Regiony są idealne do ich zwijania.
Kristof Claes
6
@Kristof: Podobnie jak właściwości w .NET 4.0, które wykonują proste sprawdzanie poprawności danych wejściowych. Automatyczne właściwości po prostu nie były tak magiczne dla moich celów.
Cody Gray
8
Jestem skłonny postawić lewą piłkę, że osoby, które nienawidzą regionów, albo nigdy nie opracowały aplikacji WPF, ani nigdy tak naprawdę nie korzystały z funkcji definiujących WPF, takich jak wiązanie danych i wiązanie poleceń. Skonfigurowanie kodu w taki sposób, aby praca ta zajmowała dużo miejsca i generalnie nie trzeba na nie patrzeć ponownie.
l46kok
70

Po pierwsze, nie mogę już znieść terminu „zapach kodu”. Jest używany zbyt często i spędzają dużo czasu ludzie, którzy nie potrafili rozpoznać dobrego kodu, jeśli go ugryzł. W każdym razie ...

Osobiście nie lubię korzystać z wielu regionów. Utrudnia to dostanie się do kodu, a kod jest tym, co mnie interesuje. Lubię regiony, gdy mam dużą część kodu, którego nie trzeba często dotykać. Poza tym wydają się mi przeszkadzać, a regiony takie jak „prywatne metody”, „publiczne metody” itp. Doprowadzają mnie do szału. Przypominają komentarze odmiany i++ //increment i.

Dodałbym również, że użycie regionów nie może tak naprawdę być „anty-wzorcem”, ponieważ termin ten jest powszechnie używany do opisania logiki / wzorców programowych programu, a nie układu edytora tekstu. To jest subiektywne; użyj tego, co działa dla Ciebie. Nigdy nie skończysz z niemożliwym do utrzymania programem z powodu nadużywania regionów, na tym właśnie polegają anty-wzorce. :)

Ed S.
źródło
2
Normalnie oddam ci głos za komentarzem zapachowym kodu, ale w tym przypadku jest dokładnie dokładny. Brak kodu nie może być zapachem kodu. +2!
7
Haha, cóż, nie chcę powiedzieć, że terminu „zapach kodu” nie można używać dokładnie. Może, ale widzę, że rzuca się tak bardzo w tych dniach, że moja natychmiastowa reakcja jest po prostu irytacją, szczególnie gdy pochodzą od ludzi, którzy tak naprawdę powtarzają to, co słyszą, nie rozumiejąc ich ani nie myśląc krytycznie. Stwierdzenia takie jak „więcej niż 5 zmiennych lokalnych w funkcji to zapach kodu” pokazują tylko, jak mało doświadczenia ta osoba faktycznie ma.
Ed S.
13
Nie jestem pewien, czy rozumiem twój komentarz na temat zapachów kodu. Zapachy kodu nie wskazują na problem, tylko może być problem.
Craig
7
+1 za przeciwstawienie się zapachowi kodu zapachowego. Miałem dość, gdy zobaczyłem post twierdzący, że prywatne metody były zapachem kodu. Ale ogólnie nie zgadzam się z waszą niechęcią do regionów. Łatwo się rozpraszam. Tak naprawdę chciałbym, gdyby VS miał tryb VB4, w którym można wyświetlać tylko jedną metodę na raz.
Josh
7
Chciałem tylko wejść i powiedzieć, że niewłaściwe użycie idealnie dobrej metafory nie powinno dewaluować tej metafory. „Zapach kodowy” to świetna metafora, która jest natychmiast zrozumiała, łatwa do zapamiętania i łatwa w użyciu. Wciąż istnieje wiele miejsc, w których stosowanie metafory „zapachowego zapachu” jest nadal najlepszym sposobem na uzyskanie punktu.
Eric King,
23

Tak, regiony to zapach kodu!

Byłbym szczęśliwy widząc regiony całkowicie usunięte z kompilatora. Każdy programista wymyśla własny bezcelowy program pielęgnacji, który nigdy nie będzie cenny dla innego programisty. Mam wszystko do czynienia z programistami, którzy chcą ozdobić i upiększyć swoje dziecko, nie ma to nic wspólnego z prawdziwą wartością.

Czy możesz pomyśleć o jednym przykładzie, w którym pomyślałeś „kurcze, chciałbym, żeby mój kolega wykorzystał tu niektóre regiony!”?

Mimo że mogę skonfigurować moje IDE, aby automatycznie rozszerzyć wszystkie regiony, nadal są one obolałe i utrudniają czytanie prawdziwego kodu.

Naprawdę mniej by mnie to obchodziło, gdyby wszystkie moje publiczne metody były powiązane, czy nie. Gratulacje, znasz różnicę między deklaracją zmiennej a inicjalizacją, nie musisz wyświetlać jej w kodzie!

Bezwartościowa pielęgnacja!

Dodatkowo, jeśli Twój plik potrzebuje i „architektury informacji” poprzez wykorzystanie regionów, możesz chcieć zwalczyć podstawowy problem: Twoja klasa jest zbyt duża! Podział na mniejsze części jest o wiele bardziej korzystny, a przy prawidłowym wykonaniu dodaje prawdziwą semantykę / czytelność.

Joppe
źródło
Czy #regions jest częścią kompilatora? Myślałem, że to tylko dyrektywa dla IDE, którą można zignorować.
Steve Rukuts,
2
Kompilator musiałby je zignorować podczas analizowania kodu C #. Jeśli ich nie zignoruje, zwymiotuje na nich. Mam na myśli to w ten sposób.
Joppe
1
„Czy możesz pomyśleć o jednym przykładzie, w którym pomyślałeś:„ rany, chciałbym, aby mój kolega wykorzystał tu niektóre regiony! ” Tak bardzo. Kiedy mam klasę z metodami prywatnymi i publicznymi, dzielę je na regiony, ponieważ podczas refaktoryzacji metod publicznych niekoniecznie musisz dotykać prywatnego kodu i odwrotnie.
Anshul
Oczywiście nigdy nie widziałeś kodu zleconego na zewnątrz. Tak wiele razy regiony świetnie byłoby zobaczyć w kodzie zewnętrznym. Mimo że kod jest do bani, przynajmniej łatwiej byłoby go zrozumieć, gdyby był zgrupowany w logiczny sposób. Chociaż jeśli ich kod nie jest logiczny, regiony też nie byłyby, więc prawdopodobnie pogorszyłoby to sytuację. Regiony są świetne, jeśli są właściwie używane.
Nickmccomb
15

Osobiście używam regionów jako sposobu grupowania różnych rodzajów metod lub części kodu razem.

Plik kodu może więc wyglądać tak po otwarciu:

  • Właściwości publiczne
  • Konstruktory
  • Zapisz metody
  • Edytuj metody
  • Metody prywatnego pomocnika

Nie umieszczam regionów w metodach. IMHO, który jest oznaką zapachu kodu. Kiedyś natknąłem się na metodę o długości ponad 1200 linii i obejmującą 5 różnych regionów. To był straszny widok!

Jeśli używasz go jako sposobu na uporządkowanie kodu w sposób, który przyspieszy znajdowanie rzeczy dla innych deweloperów, nie sądzę, że to oznaka kłopotów. Jeśli używasz go do ukrywania linii kodu w metodzie, powiedziałbym, że nadszedł czas, aby przemyśleć tę metodę.

Tyanna
źródło
14
Ugh. Wiem, że to subiektywny temat, ale stary, naprawdę nie mogę znieść tego schematu. Z mojego doświadczenia wynika, że ​​dodana „organizacja” wcale nie pomaga i sprawia, że ​​przeglądanie kodu jest uciążliwe. Wolę też metody grupowania nie tylko według modyfikatora dostępu, ale także logicznej odpowiedzialności. W przypadku interfejsu publicznego zazwyczaj grupuję każdą metodę / właściwość razem, ale często metoda chroniona może wywoływać funkcję pomocnika prywatnego, aw takim przypadku zdecydowanie wolę, aby funkcja pomocnika (która może być tam zastosowana) była powyżej lub poniżej wartości metoda, która to wywołuje.
Ed S.
3
@Ed S. - dlatego powiedziałem „może wyglądać”. To jest bardzo subiektywne. Nie twierdzę, że każdy plik powinien tak wyglądać. Byłbym zaskoczony, gdyby tak zrobili. Tylko przykład na złożony temat. :)
Tyanna
Och, wiem, jak powiedziałem; to subiektywne. Cokolwiek działa dla Ciebie / Twojego zespołu. Po prostu mam go w tym schemacie, ponieważ nie działa (dla mnie), ale musiałem utrzymać projekt, który właśnie to zrobił. Doprowadzało mnie to do szału.
Ed S.
3
@EdS. Więc idź do swoich opcji w vs i wyłącz regiony. Problem rozwiązany.
Andy
Dlaczego twoje obiekty mają metody zapisywania? :(
TheCatWhisperer
10

Używanie #regionbloków w celu uczynienia bardzo dużej klasy czytelną jest zwykle oznaką naruszenia zasady pojedynczej odpowiedzialności. Jeśli są przyzwyczajeni do grupowania zachowań, prawdopodobne jest również , że klasa robi za dużo (ponownie narusza SRP).

Trzymając się linii myślenia „zapachowy kod”, #regionbloki nie są samymi zapachami kodowymi, ale są bardziej „Febreze dla kodu”, ponieważ starają się ukryć zapachy. Podczas gdy korzystałem z nich tonę w przeszłości, kiedy zaczynasz refaktoryzować, zaczynasz widzieć mniej, ponieważ w końcu nie ukrywają się zbytnio.

Austin Salonen
źródło
5

Kluczowym słowem jest tutaj „rozsądny”. Trudno wyobrazić sobie przypadek, w którym umieszczenie regionu w metodzie jest rozsądne; zbyt prawdopodobne jest, że będzie to ukrywanie kodu i lenistwo. Jednak mogą istnieć dobre powody, aby mieć kilka regionów tu i tam w swoim kodzie.

Jeśli jest wiele regionów, myślę, że to zapach kodu. Regiony są często wskazówką w możliwym miejscu do przyszłego refaktoryzacji. Wiele regionów oznacza, że ​​ktoś tak naprawdę nigdy nie bierze podpowiedzi.

Rozsądnie stosowane dają dobry środek między strukturą jednej klasy z wieloma metodami a strukturą wielu klas z kilkoma metodami w każdej z nich. Są najbardziej przydatne, gdy klasa zaczyna zbliżać się do punktu, w którym powinna zostać przekształcona w wiele klas, ale jeszcze jej nie ma. Grupując powiązane ze sobą metody, ułatwiam później wyodrębnienie zestawu powiązanych metod do ich własnej klasy, jeśli będzie ich coraz więcej. Na przykład, jeśli mam klasę, która zbliża się do 500 wierszy kodu, ten zestaw metod wykorzystujących łącznie 200 wierszy kodu zebranych razem w regionie jest prawdopodobnie dobrym sposobem na jego refaktoryzację - i ten inny region ze 100 liniami kodu w swoim metody mogą być również dobrym celem.

Innym sposobem, w jaki lubię używać regionów, jest zmniejszenie jednego z negatywnych skutków refaktoryzacji dużej metody: wiele małych, zwięzłych, łatwych do ponownego wykorzystania metod, które czytelnik musi przewinąć, aby przejść do innej, w większości niezwiązanej z tym metody. Region może być dobrym sposobem na enkapsulację metody i jej pomocników dla czytelników, więc ktoś, kto pracuje z innym aspektem klasy, może po prostu je zwinąć i szybko odrzucić tę część kodu. Oczywiście działa to tylko wtedy, gdy twoje regiony są naprawdę dobrze zorganizowane i zasadniczo są używane jako inny sposób dokumentowania twojego kodu.

Ogólnie rzecz biorąc, uważam, że regiony pomagają mi się zorganizować, pomagają w „udokumentowaniu” mojego kodu i pomagają w wyszukiwaniu miejsc do refaktoryzacji znacznie wcześniej niż w przypadku, gdy nie używam regionów.

Ethel Evans
źródło
4

Używam głównie regionów dla klas serwerów CRUD do organizowania różnych rodzajów operacji. Nawet wtedy chętnie bym bez nich poszedł.

Przy intensywnym użyciu spowodowałoby to czerwoną flagę. Szukałem klas, które mają zbyt dużą odpowiedzialność.

Z mojego doświadczenia wynika, że ​​metoda z setkami linii kodu jest zdecydowanie zapachem.

TaylorOtwell
źródło
4

Moja ogólna zasada brzmi: jeśli masz więcej niż 5 regionów w pliku, to jest to zapach kodu

To znaczy, może być wskazanie pola, metod, właściwości i konstruktorów, ale jeśli zaczynasz owijać każdą inną metodę w jej własny region, coś jest naprawdę nie tak

... i tak, brałem udział w wielu projektach, często z powodu złych standardów kodowania, generowania kodu lub obu. Szybko jest już przełączać wszystkie kontury w studio wizualnym, aby uzyskać dobry przegląd kodu.

Homde
źródło
4

REGIONY MAJĄ UŻYTKOWANIE

Użyłem ich osobiście do zdarzeń interfejsu „kodowanie ręczne” wcześniej dla aplikacji formularzy Windows.

Jednak w mojej pracy korzystamy z generatora kodu do obsługi SQL, który automatycznie wykorzystuje regiony do sortowania metod wyboru, aktualizacji, usuwania itp.

Chociaż nie używam ich często, doskonale nadają się do usuwania dużych fragmentów kodu.

Rozpoznać
źródło
1
Użyłem podobnych generatorów kodu i wolę używać klas częściowych do usuwania generowanego kodu.
Craig
Robimy to, regiony znajdują się w generowanym kodzie, aby ułatwić czytanie lub debugowanie (w razie potrzeby).
Ken
4

Jeśli masz kod IN regionu , z pewnością masz problem (z wyjątkiem przypadku wygenerowanego kodu). Wstawianie regionów w kodzie to po prostu powiedzenie „refaktoryzuj to”.

Istnieją jednak inne przypadki. Jeden, który przychodzi mi na myśl, że cofnąłem się kiedyś: stół z kilkoma tysiącami wstępnie obliczonych przedmiotów. Jest to opis geometrii, bez błędu w tabeli, nigdy nie będzie okazji, aby na nią spojrzeć. Jasne, mogłem uzyskać dane z zasobu lub podobnego, ale to wykluczałoby użycie kompilatora, aby ułatwić czytanie.

Loren Pechtel
źródło
1
Jest to lepszy przypadek użycia dla klasy częściowej z klasą przechowywaną w osobnym pliku lub być może zastrzykiem IMyDataSource z implementacją HardcodedDataSource.
Bryan Boettcher
3

W ostatnim projekcie istniała metoda linii 1700 z osadzonymi w niej kilkoma regionami. Interesujące jest to, że regiony podjęły wyraźne działania, które zostały wykonane w ramach tej metody. Udało mi się zrobić metodę refaktoryzacji -> wyodrębnić dla każdego regionu bez wpływu na funkcjonalność kodu.

Ogólnie rzecz biorąc, przydatne są regiony używane do ukrywania kodu płyty kotła. Odradzałbym używanie regionów do ukrywania właściwości, pól i tym podobnych, ponieważ jeśli są one zbyt nieporęczne, aby na nie patrzeć podczas pracy w klasie, prawdopodobnie jest to znak, że klasa powinna zostać dalej podzielona. Ale z reguły, jeśli umieszczasz region w metodzie, prawdopodobnie lepiej byłoby wyodrębnić inną metodę, która wyjaśnia, co się dzieje, niż zawijanie tego bloku w regionie.

Michael Brown
źródło
3

Czy regiony mogą być używane w kodzie dobrej jakości? Prawdopodobnie. Założę się, że w wielu przypadkach. Jednak moje osobiste doświadczenia pozostawiają mnie bardzo podejrzliwym - widziałem regiony prawie wyłącznie niewłaściwie wykorzystywane. Powiedziałbym, że jestem zmęczony, ale nadal jestem optymistą.

Z grubsza mogę podzielić kod wykorzystujący region, który do tej pory widziałem, na trzy kategorie:

  • Słabo rozłożony kod: większość kodu, który widziałem, wykorzystuje regiony jako narzędzie faktoringu biedaka. Na przykład klasa, która urosła do tego stopnia, że ​​sensowne jest jej specjalizowanie do różnych celów, można zamiast tego podzielić na osobne regiony, po jednym dla każdego celu.

  • Kod napisany przy użyciu niewłaściwych bibliotek, a czasem niewłaściwego języka, dla domeny problemowej Często, gdy programista nie używa odpowiedniego zestawu bibliotek dla domeny problemowej, zobaczysz, że kod staje się niewiarygodnie szczegółowy - z dużą ilością małych funkcji pomocniczych które tak naprawdę nie należą (prawdopodobnie należą do ich własnej biblioteki).

  • Kod napisany przez studentów lub absolwentów. Wydaje się, że niektóre programy i kursy próbują wpajać studentom wykorzystanie regionów do różnego rodzaju dziwnych celów. Zobaczysz regiony zaśmiecające kod źródłowy do punktu, w którym stosunek znaczników regionu do linii kodu mieści się w zakresie 1: 5 lub mniej.

Blueberryfields
źródło
3

Powiedziałbym, że to „zapach kodu”.

Anty-wzorce są zasadniczo podstawowymi problemami strukturalnymi w oprogramowaniu, podczas gdy regiony same w sobie powodują obrzydliwe zachowanie w edytorze. Korzystanie z regionów wcale nie jest z natury złe, ale używanie ich często, zwłaszcza w celu ukrycia fragmentów kodu, może wskazywać na istnienie innych, niezależnych i większych problemów gdzie indziej.

Jaka jest nazwa?
źródło
@Andrew Grimm: yeah
whatsisname
3

Używam regionów tylko do jednej rzeczy (przynajmniej nie mogę myśleć o innych miejscach, w których ich używam): do grupowania testów jednostkowych dla metody.

Zwykle mam jedną klasę testów na klasę, a następnie grupuję testy jednostkowe dla każdej metody, używając regionów, które mają nazwę metody. Nie jestem pewien, czy to jest zapach kodu, czy coś, ale ponieważ podstawową ideą jest to, że testy jednostkowe nie muszą się zmieniać, chyba że ulegną awarii, ponieważ coś w kodzie uległo zmianie, ułatwia mi to znalezienie wszystkich testów dla określonej metody dość szybko.

Mogłem używać regionów do organizowania kodu w przeszłości, ale nie pamiętam, kiedy to zrobiłem ostatni raz. Jednak trzymam się swoich regionów w klasach testów jednostkowych.

Anne Schuessler
źródło
1
Czy kiedykolwiek miałeś testy, które testują więcej niż jedną metodę?
Marcie
Naprawdę nie rozumiem pytania ani tego, do czego zmierzasz. Odpowiedź brzmi: nie, test jednostkowy zawsze jest ukierunkowany tylko na jedną metodę, a raczej na pewien aspekt jednej metody.
Anne Schuessler
2

Uważam, że są anty-wzorcem i szczerze mówiąc, należy je wyeliminować. Ale jeśli znajdujesz się w niefortunnej sytuacji, gdy pracujesz w miejscu, w którym są standardem, Visual Studio oferuje niesamowite narzędzie do zminimalizowania kwoty, którą chciałbyś zwymiotować za każdym razem, gdy zobaczysz region, którego nienawidzę #Regiony

Ta wtyczka zwiększy rozmiar czcionki w regionach naprawdę małych. Zostaną również rozszerzone, abyś nie musiał wciskać Ctr + M + L, aby otworzyć wszystkie regiony. Nie naprawia tej formy raka kodu, ale czyni ją znośną.

DeadlyChambers
źródło
0

Używam regionów, aby zawierać każdą kombinację widoczności i typu członka. Więc wszystkie funkcje prywatne przechodzą do regionu itp.

Powód, dla którego to robię, nie jest taki, że mogę złożyć kod. Dzieje się tak, ponieważ mam napisany skrypt do edytora, dzięki czemu mogę wstawić, powiedzmy, odwołanie do serwera proxy:

#region "private_static_members"
 /// <summary>
 /// cache for LauncherProxy
 /// </summary>
private static LauncherProxy _launcherProxy;
#endregion

#region "protected_const_properties"
protected LauncherProxy LauncherProxy{
  get{
    if(_launcherProxy==null) {
      if (!God.Iam.HasProxy(LauncherProxy.NAME)) {
        God.Iam.RegisterProxy(new LauncherProxy());
      }
      _launcherProxy=God.Iam.Proxy(LauncherProxy.NAME) as LauncherProxy;
    }
    return _launcherProxy;
  }
}
#endregion

do kodu i starannie umieść każdą część w odpowiednim regionie.

W tym przypadku makro przeanalizuje mój projekt, da mi listę serwerów proxy i wstrzyknie kod dla tego, którego chcę. Mój kursor nawet się nie rusza.

Na początku nauki języka C # rozważałem wykorzystanie regionów do utrzymywania wspólnoty razem, ale jest to propozycja typu hit and miss, ponieważ nie jest to relacja jeden do jednego przez cały czas. Kto chce się martwić członkiem używanym przez dwa regiony, a nawet zacząć rozpadać się na tych warunkach.

Jedynym innym rodzajem segregacji są metody - podzielę metody na polecenia, funkcje i programy obsługi, więc będę mieć region dla poleceń publicznych, prywatnych itp.

Daje mi to szczegółowość, ale jest to spójna, jednoznaczna ziarnistość, na której mogę polegać.

znak
źródło
-1, jak tylko dostanę 125 punktów do głosowania. Dodajesz niepotrzebne wiersze kodu. DLACZEGO DLACZEGO DLACZEGO miałbyś ustawić region wokół nieruchomości ... jeśli (God.Iam.AbusingRegions () == true) myName = "Mark"
DeadlyChambers
1
@DeadlyChambers Powód jest podany w drugim akapicie - używam makr edytora do wstrzykiwania wspólnych wzorów kodów do pliku, regiony pomagają utrzymać strukturę pliku, dzięki czemu podobne elementy są grupowane. Nie umieszczam regionu wokół pojedynczej właściwości, ale wszystkie właściwości mieszczą się w wyznaczonym regionie w zależności od ich atrybutów „protected_const_properties”. Czy przeczytałeś post?
Mark
1
Prawdopodobnie możesz zmienić to na: chronione LauncherProxy LauncherProxy => God.Iam.GetOrAddProxy <LauncherProxy> (ref _launcherProxy); i dlatego nie potrzebujesz teraz regionu. Nazwę _launcherProxy można również zmienić na _launcherProxyCache, więc nie potrzebujesz regionu ani komentowania.
aeroson
0

Regiony są wyrażeniami preprocesora - innymi słowy są traktowane jak komentarze i po prostu ignorowane przez kompilator. Są czysto wizualnym narzędziem używanym w Visual Studio. Dlatego #region nie jest tak naprawdę zapachem kodu, ponieważ po prostu nie jest kodem. Zapach kodu jest raczej metodą 800-liniową, która zawiera wiele różnych obowiązków itp. Więc jeśli widzisz 10 regionów w jednej metodzie - prawdopodobnie jest on używany do ukrywania zapachu kodu. Powiedziawszy, że widziałem, jak były one używane bardzo skutecznie, aby uczynić klasę przyjemniejszą dla oka i łatwiejszą w nawigacji - w bardzo dobrze napisanej i zorganizowanej klasie!

BKSpurgeon
źródło
0

Regiony były sprytnym pomysłem organizacyjnym, ale nie wzięły pod uwagę niektórych tendencji deweloperów, by chcieć przecenić wszystko, i generalnie są niepotrzebne według większości współczesnych praktyk OOP ... są „zapachem”, w tym sensie, że ich używanie często oznacza że twoja klasa / metoda jest zdecydowanie za duża i powinna zostać zmieniona, ponieważ prawdopodobnie naruszasz „S” zasad SOLID ... ale jak każdy zapach, niekoniecznie oznacza to, że coś idzie nie tak.

Regiony służą bardziej celowi w kodzie funkcjonalnym niż w kodzie obiektowym, IMO, gdzie masz długie funkcje sekwencyjnych danych, które warto rozdzielić, ale były chwile, kiedy osobiście ich używałem w c #, i prawie zawsze skup się na kodzie, którego nie potrzebujesz / nie chcesz oglądać. Dla mnie były to zwykle nieprzetworzone stałe ciągów SQL w bazie kodu używanej dla NPoco lub jego wariantów. O ile nie obchodzi cię, w jaki sposób dane wypełniają obiekt POCO za pośrednictwem Twojej ORM, nie było sensu na nie patrzeć ... a jeśli cię to obchodziło, hej, po prostu rozszerz region i BAM! Ponad 150 wierszy skomplikowanego zapytania SQL dla przyjemności oglądania.

Jeremy Holovacs
źródło