Dlaczego ludzie tak zdecydowanie sprzeciwiają się metodom #region w metodach?

27

Słyszę dużo o skróceniu metod i słyszałem, jak wielu programistów twierdzi, że użycie tagów #region w metodzie jest pewnym znakiem, że jest ona zbyt długa i powinna zostać przekształcona w wiele metod. Wydaje mi się jednak, że istnieje wiele przypadków, w których oddzielenie kodu za pomocą znaczników #region w metodzie jest najlepszym rozwiązaniem do refaktoryzacji na wiele metod.

Załóżmy, że mamy metodę, której obliczenia można podzielić na trzy dość odrębne fazy. Co więcej, każdy z tych etapów jest istotny tylko dla obliczeń tej metody, więc wyodrębnienie ich w nowe metody nie powoduje ponownego użycia kodu. Jakie są zatem zalety wyodrębnienia każdej fazy z jej własnej metody? O ile mogę stwierdzić, zyskujemy tylko pewną czytelność i osobny zmienny zakres dla każdej fazy (co pomoże zapobiec przypadkowemu przerwaniu modyfikacji przez konkretną fazę).

Jednak oba z nich można osiągnąć bez wyodrębniania każdej fazy we własnej metodzie. Tagi regionalne pozwalają nam zwinąć kod do postaci, która jest równie czytelna (z dodatkową korzyścią, że nie musimy już zostawiać swojego miejsca w tym pliku, jeśli zdecydujemy się rozwinąć i zbadać kod), i po prostu zawijamy każdą fazę w {}tworzy własny zakres do pracy.

Zaletą robienia tego w ten sposób jest to, że nie zanieczyszczamy zakresu na poziomie klasy za pomocą trzech metod, które w rzeczywistości są istotne tylko dla wewnętrznych mechanizmów czwartej metody. Natychmiastowe przekształcenie długiej metody w szereg krótkich metod wydaje mi się być ponownym użyciem kodu równoważnym z przedwczesną optymalizacją; wprowadzasz dodatkową złożoność, aby rozwiązać problem, który w wielu przypadkach nigdy nie powstaje. Zawsze możesz później wyodrębnić jedną z faz we własnej metodzie, jeśli pojawi się możliwość ponownego użycia kodu.

Myśli?

jjoelson
źródło
4
Obecnie pracuję z klasą, która jest dość duża. Jest zgodny z zasadą jednolitej odpowiedzialności; wszystko w tej klasie wymaga funkcjonalności. Ma wiele prywatnych metod, głównie z powodu refaktoryzacji. Używam #region do dzielenia tych metod na kategorie funkcjonalne, co dla nas bardzo dobrze się sprawdziło. W tym projekcie istnieje wiele innych klas, które nie wymagały takiego leczenia. Mówię, że właściwe narzędzie do właściwej pracy.
Robert Harvey,
4
@RobertHarvey, używanie ich w klasie różni się od używania ich wewnątrz metody.
CaffGeek
18
@Chad: Ach, nie zauważyłem tego. Używanie ich w metodzie wydaje się nieco ekstremalne. Jeśli metoda jest tak długa, że ​​wymaga #regionów, refaktoryzuję ją do osobnych metod.
Robert Harvey,
8
Naprawdę nie jest to odpowiedź, ale nie tylko nienawidzę wszystkich #regiontagów, ale całkowicie wyłączam zwijanie kodu w Visual Studio. Nie lubię kodu, który próbuje się przede mną ukryć.
Daniel Pryden, 10.11.11
2
„Ponadto każdy z tych etapów jest istotny tylko dla obliczeń tej metody, a więc wyodrębnienie ich w nowe metody nie powoduje ponownego użycia kodu”. OTOH, stwierdzam, że jeśli podzielę funkcję na 3, często stwierdzam później, że poszczególne części <i> są </i> przydatne później, np. jeśli niektóre dane wejściowe zmieniają tylko jedną fazę, można to przetestować osobno itp.
Jack V.

Odpowiedzi:

65

Jedyne, o co powinieneś się troszczyć, to to, aby kod był użyteczny, a nie wielokrotnego użytku. Małpa może przekształcić użyteczny kod w kod wielokrotnego użytku, jeśli w ogóle trzeba wykonać jakieś transformacje.

Argument „potrzebuję tego tylko tutaj” jest słaby, mówiąc grzecznie. Technikę, którą opisujesz, często określa się mianem techniki nagłówków i na ogół nie ma do niej pretensji.

  1. Nie można testować regionów, ale można przetestować prawdziwe metody w izolacji.
  2. Regiony to komentarze, a nie elementy składniowe. W najgorszym przypadku zagnieżdżanie się regionów i bloków jest ze sobą sprzeczne. Zawsze powinieneś starać się reprezentować semantykę swojej struktury za pomocą elementów składniowych używanego języka.
  3. Po refaktoryzacji do metod nie trzeba już składać, aby przeczytać tekst. Ktoś może patrzeć na kod źródłowy w dowolnym narzędziu, które nie ma funkcji składania, na przykład w terminalu, kliencie poczty, widoku sieci dla VCS lub przeglądarce różnic.
  4. Po refaktoryzacji do metod uzyskana metoda jest co najmniej tak dobra, jak w przypadku regionów, a ponadto łatwiej jest przenosić poszczególne części.
  5. Zasada pojedynczej odpowiedzialności sugeruje, że każda jednostka powinna mieć jedno zadanie i tylko jedno zadanie. Zadaniem metody „głównej” jest skomponowanie metod „pomocniczych” w celu uzyskania pożądanego rezultatu. Metody „pomocnika” rozwiązują dyskretny, prosty problem w izolacji. Klasa zawierająca wszystkie te metody powinna również wypełniać tylko jedno zadanie i zawierać tylko metody powiązane z tym zadaniem. Tak więc metody pomocnicze albo należą do zakresu klasy, albo kod nie powinien być w klasie w pierwszej kolejności, ale przynajmniej w jakiejś globalnej metodzie lub, co jeszcze lepsze, powinien zostać wstrzyknięty .

Również istotny: przemyślenia Jeffa Atwoodsa na temat zwijania kodu

back2dos
źródło
9
1. Większość programistów nie testuje wszystkich metod prywatnych. 2. Nazwa metody nie może przekazać wszystkiego, co można wiedzieć o tej metodzie; jakie wyjątki mogą zostać rzucone? Czy wartość null jest prawidłowym wejściem? Czasami dobrze jest używać nie syntaktycznych konstrukcji, aby kod był bardziej zrozumiały. W wielu językach pliki są przykładem nieskompaktowego elementu, który jest dość powszechnie akceptowany jako sposób organizacji kodu. 3. Najlepiej jest zanurzyć się w wewnętrznym działaniu metody w IDE z różnych powodów; sytuacje, w których regiony mogą ugryźć Cię w VCS lub w kliencie pocztowym, są raczej rzadkie.
jjoelson
3
4. Ale właśnie wyeksportowałeś poważną złożoność do reszty klasy. Czy to jest tego warte? Ponadto regiony można przenosić tak łatwo, jak wywołanie metody. 5. Teraz mówisz o zanieczyszczeniu przestrzeni nazw większą liczbą klas, które będą używane tylko w jednym miejscu. Dlaczego klasy i metody są jedynymi jednostkami enkapsulacji, które zaakceptujesz? Zawsze możesz utworzyć tę nową klasę później, kiedy (lub jeśli) konieczne będzie oddzielenie tej klasy.
jjoelson
7
@jjoelson: 1. Co z tego? 2. Dokładnie o to mi chodzi: można stosować konstrukty nie syntaktyczne, jeśli sama składnia (i tylko wtedy) nie wystarczy. 3. „Rzadko?” - Przypuszczam, że masz na to liczby. Mogę powiedzieć z całą pewnością, że narzędzie diff (lub wina lub cokolwiek innego w tym zakresie) dołączone do TortoiseSVN nie ma funkcji składania. 4. Jak to się ma do przedstawionego przeze mnie punktu. 5. Dlatego większość współczesnych języków ma zagnieżdżone przestrzenie nazw. Używasz sztuki ASCII zamiast strukturyzować kod za pomocą szerokiej palety dostępnych elementów językowych.
back2dos,
4
@jjoelson: 1. To jest twoja opinia i nie wchodzi w zakres tego pytania. 2. Przez rozszerzenie mojego argumentu funkcje zagnieżdżone są lepsze niż regiony, tak. 3. Ponieważ czasami muszę przeglądać wiele wersji, aby wyśledzić problem. Tak czy inaczej, kod źródłowy jest pisany dla ludzi, a nie IDE. 4. Z jednej strony argument ten nie ma związku z moją kwestią, po drugie, to znowu tylko twoja opinia, po trzecie, jest poza zakresem tego pytania. 5. C # ma inne sposoby strukturyzacji kodu niż funkcja zagnieżdżania. Powinieneś użyć tych lub języka, który pozwala na zagnieżdżanie funkcji.
back2dos
13
Powinieneś wziąć to na czacie, jeśli nadal chcesz dyskutować ... Nie mam nic do powiedzenia OP, jest typowym, opiniotwórczym młodym programistą, którego poglądy są zgodne z jego przekonaniami. Nic nie zmieni jego zdania, ale więcej doświadczenia IMO.
wałek klonowy
15

Problemem nie są regiony w metodach, ale przypadek, gdy istnieje potrzeba (a nawet zastosowanie) regionów w metodach.

Po tym, jak musiałem debugować wiele 200-300 metod liniowych, mogę powiedzieć, że nie chciałbym tego na nikim. Jeśli piszesz i dbasz o swój własny kod, to w porządku - rób co chcesz. Ale gdy ktoś na to spojrzy, natychmiast powinno być jasne, co robi metoda.

„Najpierw dostaje rzeczy, a potem je kręci, a jeśli potrzebują szumu, robi to, w przeciwnym razie sprawdza, czy są niebieskie i odwraca ich wartość Kopernika. Następnie, jeśli druga rzecz jest większa niż pierwsza rzecz, my muszę wziąć pudełko na sok i włożyć go ... ”

Nie, to nie wystarczy. Podziel to na regiony, jak chcesz, ale wciąż kręcę głową, myśląc o tym.

Jeśli włamiesz się na metody, uzyskasz wiele korzyści:

  • Lepsze zrozumienie tego, co się dzieje, nawet jeśli tylko poprzez nazwę metody. A ty jesteś zły , że metoda ta nie może być w pełni udokumentowane - dodać blok dokumentacja (hit ///) i wprowadź opis, parametry, typ zwracany, a także exception, example, remarkswęzły na szczegóły tych scenariuszy. Tam właśnie idzie, po to jest!
  • Nie ma żadnych skutków ubocznych ani problemów z zasięgiem. Możesz powiedzieć, że deklarujesz wszystkie zmienne w podzakresie {}, ale czy muszę sprawdzać każdą metodę, aby upewnić się, że nie „oszukujesz”? Czy dodgyObjectużywam tego tylko dlatego, że był używany w tym regionie, czy też pochodzi z innego miejsca? Gdybym był według własnej metody, z łatwością mógłbym zobaczyć, czy został on przekazany mi, czy też sam go stworzyłem (a raczej czy to Ty go stworzyłeś).
  • Mój dziennik zdarzeń mówi mi, w której metodzie wystąpił wyjątek. Tak, może uda mi się znaleźć kod naruszający numer linii, ale znajomość nazwy metody (zwłaszcza jeśli poprawnie ją nazwałam) daje mi bardzo dobre wskazanie co się stało i co poszło nie tak. „Och, TurnThingsUpsideDownmetoda zawiodła - prawdopodobnie zawodzi podczas obracania złej rzeczy” jest o wiele lepsza niż „Och, DoEverythingmetoda zawiodła - mogło być 50 różnych rzeczy i będę musiał kopać przez godzinę, aby ją znaleźć” .

To wszystko zanim pojawią się jakiekolwiek wątpliwości dotyczące możliwości ponownego użycia lub poprawy. Właściwie wyodrębnione metody oczywiście ułatwiają ponowne użycie, a także pozwalają łatwo zastąpić metodę, która nie działa (zbyt wolno, zbyt błędnie, zmieniona zależność itp.). Czy kiedykolwiek próbowałeś refaktoryzować którąś z tych wielkich metod? Nie ma sposobu, aby wiedzieć, że to, co zmienisz, nie wpłynie na nic innego.

Proszę poprawnie zawrzeć logikę w rozsądnych metodach. Wiem, że łatwo im wymknąć się spod kontroli, a argumentowanie, że w tym momencie nie warto przeprojektowywać, to kolejna kwestia. Ale musisz zaakceptować fakt, że nie ma szkody ani przynajmniej potencjalnej korzyści z posiadania odpowiednio zamkniętych, czysto napisanych i po prostu zaprojektowanych metod.

Kirk Broadhurst
źródło
Analiza komentarzy XML w Visual Studio, wraz ze znacznikami #region, należy do kategorii funkcji Visual Studio. Chodzi mi o to, że nie jest źle polegać na tych funkcjach, jeśli wszyscy w twoim projekcie korzystają z Visual Studio. Jeśli chodzi o skutki uboczne i problemy z zasięgiem, nadal możesz popsuć wszystko globalnym polom. W obu przypadkach musisz polegać na programistach, aby nie robili głupich rzeczy z efektami ubocznymi.
jjoelson
5
@jjoelson Nadal możesz czytać komentarze XML bez wizualnego studia, ale tagi regionu są prawie całkowicie bezużyteczne poza VS. Logiczne rozszerzenie twojego argumentu jest jedną wielką metodą, która uruchamia całą twoją aplikację jest w porządku, pod warunkiem, że masz ją podzieloną na regiony!
Kirk Broadhurst
2
@jjoelson, proszę, nie zaczynaj od tego, jak złe są globalne pola. Mówienie czegoś nie jest przydatne, ponieważ masz „obejście”, które i tak to spieprzyło, jest po prostu głupie. Po prostu trzymaj się metod krótkich, a zakres zmiennych.
OliverS,
@OliverS, Kirk był tym, który przywołał stan współdzielony jako problem z moim schematem regionów w metodzie. Zasadniczo mówiłem dokładnie to, co mówisz : fakt, że programista może nadużywać stanu, udostępniając zbyt wiele zmiennych między regionami, nie jest oskarżeniem całego schematu, podobnie jak zdolność do zepsucia stanu dzielonego między metodami za pomocą globałów nie jest • akt oskarżenia o systemie wielu metod.
jjoelson
7

Jeśli twoja metoda jest na tyle złożona, że ​​można ją podzielić na trzy odrębne fazy, to nie tylko powinny to być trzy osobne metody ... ale twoja metoda powinna być w rzeczywistości osobną klasą dedykowaną do tego obliczenia.

„Ale wtedy moja klasa będzie miała tylko jedną metodę publiczną!”

Masz rację i nie ma w tym nic złego. Zasada zasady pojedynczej odpowiedzialności polega na tym, że twoja klasa robi jedno .

Twoja klasa może wywoływać kolejno każdą z trzech metod i zwracać wynik. Jedna sprawa.

Jako bonus, teraz twoja metoda jest testowalna, ponieważ nie jest już metodą prywatną.

Ale nie wspominając o jednej klasie; w rzeczywistości powinieneś mieć cztery : po jednym dla każdego z elementów twojej metody, plus jeden, który bierze każdą z trzech jako zależność i wywołuje je we właściwej kolejności, zwracając wynik.

To sprawia, że ​​Twoje zajęcia są jeszcze bardziej testowalne. Ułatwia także zmianę jednego z tych trzech elementów. Wystarczy napisać nową klasę dziedziczącą po starej i zastąpić zmienione zachowanie. Lub stwórz interfejs dla zachowania każdego z twoich trzech elementów; a następnie, aby je zastąpić, po prostu napisz nową klasę implementującą ten interfejs i zastąp go starą w konfiguracji kontenera wstrzykiwania zależności.

Co? Nie używasz zastrzyku zależności? Cóż, prawdopodobnie nie widziałeś jeszcze takiej potrzeby, ponieważ nie przestrzegasz zasady pojedynczej odpowiedzialności. Kiedy zaczniesz, przekonasz się, że najłatwiejszym sposobem nadania zależności każdej klasie jest użycie kontenera DI.

EDYCJA :

OK, odłóżmy na bok pytanie o refaktoryzację. Celem #regionjest ukrycie kodu , co oznacza głównie kod, który nie musi być edytowany w żadnych normalnych okolicznościach. Wygenerowany kod jest najlepszym przykładem. Powinien być ukryty w regionach, ponieważ zwykle nie trzeba go edytować. W razie potrzeby rozszerzenie regionu daje ci trochę ostrzeżenia w stylu „Oto smoki”, aby upewnić się, że wiesz, co robisz.

Dlatego powiedziałbym, że nie#region powinien być stosowany w środku metody. Jeśli otworzę metodę, chcę zobaczyć kod. Użycie #region daje mi kolejny poziom ukrywania, którego nie potrzebuję, a to staje się irytujące: rozwijam metodę ... i wciąż nie widzę żadnego kodu.

Jeśli martwisz się, że ludzie widzą strukturę metody (i odmawiasz jej refaktoryzacji), dodaj komentarze banerowe w następujący sposób:

//
// ---------- COMPUTE SOMETHING OR OTHER ----------
//

Pomogą one komuś przeglądającemu kod zobaczyć poszczególne części twojej metody bez konieczności zajmowania się rozwijaniem i zwijaniem #regiontagów.

Kyralessa
źródło
2
Wszystko to w przypadku metody wywoływanej w jednym miejscu? Nawet najbardziej zapaleni Lisperowie nie wyodrębnią funkcji wyższego rzędu, dopóki nie zidentyfikują co najmniej dwóch miejsc, w których można jej łatwiej zdefiniować funkcję.
jjoelson,
1
@jjoelson Czy tak trudno jest stworzyć nową klasę? Co to jest, jedna linia, jedna klamra otwierająca i jedna klamra zamykająca. Och, i musisz nacisnąćctrl+n
Kirk Broadhurst,
2
To nie jest tak, że trudno jest stworzyć nową klasę, ale jest trochę dodatkowych kosztów posiadania dodatkowej klasy. To kolejna warstwa pośrednicząca, która utrudnia twórcy kodu znalezienie tego, czego szuka. Nie jest to wielka okazja, ale nie kupuje też niczego w przypadku, gdy ten fragment kodu jest mało prawdopodobny z innego miejsca. Jak już wspomniałeś, stworzenie nowej klasy i umieszczenie tam kodu jest dość łatwe, jeśli okaże się, że trzeba wywołać ten fragment kodu w wielu miejscach.
jjoelson
2
@jjoelson, jest to dość powszechna reakcja. To było moje, kiedy po raz pierwszy dowiedziałem się o takich rzeczach, jak SRP i DI, i była to reakcja moich współpracowników, kiedy zaczęliśmy wyłamywać zależności. Jeśli patrzysz na pojedynczy przypadek , nie wydaje się to warte. Korzyść jest sumowana. Gdy zaczniesz robić SRP ze wszystkimi swoimi klasami, przekonasz się, że o wiele łatwiej jest zmienić fragment kodu bez zmian w połowie aplikacji.
Kyralessa
@ Kyralessa, są to metody, które są używane tylko w jednym miejscu. Zmiana takiej metody nie spowoduje pomarszczenia połowy aplikacji. Jeśli taki kod jest zaimplementowany jako region w metodzie, która go używa, masz doskonałą enkapsulację; tylko metoda zawierająca używa kodu, więc możesz go dowolnie zmieniać, nie martwiąc się o efekt, z wyjątkiem tej metody.
jjoelson
4

Myślę, że przykład, który podajesz w swoim argumencie, dotyczy mniej YAGNI (nie będziesz go potrzebował), a więcej o pisaniu kodu jakości, który można łatwo utrzymać.

Na najwcześniejszych kursach programistycznych dowiadujemy się, że jeśli metoda ma 700 LOC, jest prawdopodobnie zbyt duża i na pewno byłoby ogromnym bólem, aby spróbować i debugować.

Po drugie, jeśli napiszę metody A, B i C, które są używane tylko w ramach metody D, to mogę łatwiej testować jednostki AB i C niezależnie od D, pozwalając na bardziej niezawodne testy jednostkowe we wszystkich 4 metodach.

wałek klonowy
źródło
Testowanie jednostkowe jest z pewnością słusznym punktem, ale nie jestem pewien, czy uzasadnia to zanieczyszczenie zakresu klasy w każdym przypadku. Mówiąc realistycznie, czy ktoś faktycznie testuje jednostkowo każdą małą prywatną metodę, którą piszą? Powiedziałbym, że ludzie często testują jednostkowo metody prywatne, które są często używane, to znaczy metody prywatne, które i tak byłyby kandydatami do ponownego użycia kodu.
jjoelson
@jjoelson Jeśli metoda ma sensowną logikę i nie zawiera innych funkcji, zawsze piszę na jej podstawie test jednostkowy. Metody testowania jednostkowego nie mają nic wspólnego z ponownym użyciem kodu. Powinieneś jednostkowo testować metody, aby sprawdzić, czy dla danych wejściowych otrzymujesz oczekiwane wyniki w spójny i powtarzalny sposób. Jeśli zauważysz, że zasięg klasy ulega zanieczyszczeniu, jak go nazywasz, być może Twoja klasa narusza zasadę pojedynczej odpowiedzialności.
wałek klonowy
2
Większość programistów, których spotkałem, nie zgadza się z pomysłem testowania jednostkowego każdej prywatnej metody. Po prostu nie warto poświęcać czasu na wdrożenie i utrzymanie testów wszystkich metod prywatnych.
jjoelson
3

Załóżmy, że mamy metodę, której obliczenia można podzielić na trzy dość odrębne fazy. Co więcej, każdy z tych etapów jest istotny tylko dla obliczeń tej metody, więc wyodrębnienie ich w nowe metody nie powoduje ponownego użycia kodu. Jakie są zatem zalety wyodrębnienia każdej fazy z jej własnej metody? O ile mogę stwierdzić, zyskujemy tylko pewną czytelność i osobny zmienny zakres dla każdej fazy (co pomoże zapobiec przypadkowemu przerwaniu modyfikacji przez konkretną fazę).

To dwie zalety. Ale dla mnie najważniejsza jest debuggowanie . Jeśli musisz prześledzić ten kod, o wiele łatwiej jest przejść przez dwie z trzech sekcji i prześledzić tylko tę, na której ci zależy. Umożliwia to refaktoryzacja na mniejsze metody; tagi regionu nie.

Mason Wheeler
źródło
1
ctrl-f10- biegnij do kursora
Steven Jeuris,
2

Moją osobistą zasadą jest to, że jeśli metoda jest dłuższa niż jeden ekran, powiedzmy 40 linii, to jest za długa. Jeśli klasa jest dłuższa niż 500 linii, jest za duża. Czasami łamię te zasady, czasami nawet dużą wielokrotność, ale generalnie żałuję tego w ciągu roku.

Nawet metoda składająca się z 20 do 30 linii w większości przypadków jest nieco długa. Powiedziałbym więc, że użycie regionów w metodzie jest zwykle złym pomysłem, po prostu dlatego, że prawie nigdy nie miałoby sensu zwinięcie regionu zawierającego od 20 do 30 linii w wiele podregionów.

Podział funkcji, które są długie według tej definicji, ma co najmniej dwie zalety:

  1. Możesz nazwać to, co robią te podfunkcje, co wyjaśnia twoje obecne myślenie i upraszcza zadanie późniejszych opiekunów.

  2. Rozkład na mniejsze funkcje zmusza do przekazania tylko tych parametrów, których potrzebują mniejsze funkcje, więc zakres wymaganych i modyfikowanych danych jest bardzo jasny. Zakłada się, że nie uzyskujesz dostępu i nie modyfikujesz stanu obiektu w stu różnych funkcjach liści, co również odradzam.

Z mojego doświadczenia wynika, że ​​reguły te tworzą kod, który jest łatwiejszy do napisania bez popełniania typowych błędów i może być później zrozumiany i zmodyfikowany bez przerywania subtelnych zachowań. Nie ma znaczenia, czy osobą, która musi zrozumieć / zmodyfikować kod, jest ktoś inny, czy ja po tym, jak spałem i zapomniałem o wszystkim.

Dlatego uważam regiony w metodach za „zapach kodu” wskazujący, że stosowane są niezrównoważone praktyki. Jak zawsze mogą istnieć wyjątki, ale zdarzają się tak rzadko, że prawie nie warto o nich dyskutować.

PeterAllenWebb
źródło
2

Znowu zaczynamy ... Jest wiele innych tematów na temat programistów, którzy zakończyli tę samą dyskusję.

Wskazujesz kilka bardzo interesujących argumentów związanych z krótkimi funkcjami. To nie jest popularne stwierdzenie, ale jestem z tobą w tej sprawie . Po wcześniejszym omówieniu mam wrażenie, że dyskusja sprowadza się zwykle do tego, czy skupiasz się przede wszystkim na właściwej enkapsulacji, czy też maksymalnie rozwijasz programowanie testowe. To są dwaj główni pretendenci do czegoś, co wydaje się zbliżać do kolejnej świętej wojny, i obawiam się, że jesteśmy po stronie słabej mocy.

Jednak ...

Moim zdaniem rozwiązaniem zdecydowanie nie jest owijanie „faz” w regiony. Składanie kodu służy do zamiatania kodu pod dywan. Zostaw kod tam, gdzie jest, może przypominać, że możesz to zmienić później. Odnosząc to do argumentu w pytaniu: jak będziesz w stanie zobaczyć możliwość ponownego użycia kodu, jeśli nie zobaczysz żadnego kodu? Długie segmenty kodu powinny być dokładnie tym, cierniem w oku, co sprawia, że ​​chcesz go zmienić.

Jako odpowiedni zamiennik dla regionów sugeruję stosowanie akapitów kodu, ponieważ Alex Papadimoulis nazywa je w komentarzu . Być może już używasz podobnego podejścia. Są to po prostu bloki kodu z nagłówkiem komentarza, wyjaśniające, co robi cały blok. Masz czytelność funkcji, ale możesz używać normalnie rozmieszczonych zdań w języku angielskim i nie tracisz żadnej enkapsulacji.

Steven Jeuris
źródło
Zasadniczo używam regionów, aby rozgraniczać akapity kodu (regiony mogą mieć komentarze, które są widoczne nawet po złożeniu kodu). Lubię używać do tego regionów, ponieważ daje to opiekunowi wybór, aby zobaczyć kod, jeśli chce zbadać implementację lub złożyć go, jeśli chce zobaczyć tylko „duży obraz”.
jjoelson
1

Chociaż zgadzam się, że zwykle lepiej jest refaktoryzować kod niż użyć #region, nie zawsze jest to możliwe.

Na poparcie tego stwierdzenia podam przykład.

class Foo : IComparable
{
  private String name;
  private int foo;
  private Bar bar;

  public int CompareTo(Foo other)
  {
#region Ascending on name
     if (this.name < other.name) return -1;
     if (this.name > other.name) return 1;
#endregion
#region Usual order on bar
     int compBar = bar.compareTo(other.bar);
     if (compBar != 0) return compBar;
#endregion
#region Descending on foo
     if (this.foo > other.foo) return -1;
     if (this.foo < other.foo) return 1;
#endregion
     return 0; // equal
  }

Łatwo jest dostosować regiony, aby zmienić kolejność lub rozszerzyć, gdy do klasy zostaną dodane pola dodatkowe. W każdym razie wymagane są komentarze, aby szybko zobaczyć, jak powinno wyglądać zamówienie. A przede wszystkim: nie rozumiem, w jaki sposób refaktoryzacja poprawi czytelność w tym przypadku.

Te wyjątki są jednak rzadkie. Zwykle można refaktoryzować, jak mówi wiele innych odpowiedzi.

Sjoerd
źródło
0

Nie sądzę, aby istniała jedna odpowiedź na pytanie, dlaczego niektóre osoby lub zespoły decydują się nie używać, #regionale gdybym musiał wymienić kilka, byłoby to najważniejsze powody, które widziałem.

  • Nazwy i porządek regionów w bardziej wyraźny sposób porządkują i organizują kod, który wymusza określony styl, który może stać się źródłem sporów i wyścigów rowerowych.
  • Większość koncepcji nie pasuje idealnie do niewielkiej liczby regionów. Zazwyczaj zaczynasz od regionów przez modyfikatory dostępu publiczne , prywatne, a następnie może według typu członka (np. Metoda, właściwość, pole), ale co z konstruktorami obejmującymi te modyfikatory, statyczne odmiany wszystkich z nich, chronione elementy, elementy wewnętrzne, chronione elementy wewnętrzne członkowie, niejawni członkowie interfejsu, zdarzenia itp. W końcu mielibyśmy najbardziej dobrze zaprojektowane klasy, w których każdy ma jedną metodę lub metodę ze względu na szczegółową kategoryzację.
  • Jeśli jesteś w stanie utrzymać pragmatyczne i tylko grupować rzeczy w powiedzmy trzy lub cztery stałe typy regionów, to może to zadziałać, ale jaką wartość naprawdę to dodaje? Jeśli dobrze projektujesz klasy, naprawdę nie powinieneś przeszukiwać stron kodu.
  • Jak wskazano powyżej, regiony mogą ukrywać brzydki kod, co może sprawiać, że wydaje się mniej problematyczny niż jest. Trzymanie go na ból oczu może pomóc w jego rozwiązaniu.
jpierson
źródło