Kiedy funkcja jest za długa? [Zamknięte]

132

35 linii, 55 linii, 100 linii, 300 linii? Kiedy powinieneś zacząć go rozbijać? Pytam, ponieważ mam funkcję z 60 liniami (łącznie z komentarzami) i myślałem o jej rozbiciu.

long_function(){ ... }

w:

small_function_1(){...}
small_function_2(){...}
small_function_3(){...}

Funkcje nie będą używane poza long_function, tworzenie mniejszych funkcji oznacza więcej wywołań funkcji itp.

Kiedy podzieliłbyś funkcję na mniejsze? Czemu?

  1. Metody powinny robić tylko jedną logiczną rzecz (pomyśl o funkcjonalności)
  2. Powinieneś być w stanie wyjaśnić metodę w jednym zdaniu
  3. Powinien pasować do wysokości twojego wyświetlacza
  4. Unikaj niepotrzebnych kosztów (komentarzy, które wskazują na oczywiste ...)
  5. Testowanie jednostkowe jest łatwiejsze w przypadku małych funkcji logicznych
  6. Sprawdź, czy część funkcji może być ponownie wykorzystana przez inne klasy lub metody
  7. Unikaj nadmiernego sprzężenia międzyklasowego
  8. Unikaj głęboko zagnieżdżonych struktur kontrolnych

Dziękuję wszystkim za odpowiedzi , edytuj listę i zagłosuj na poprawną odpowiedź, wybiorę tę;)

Robię teraz refaktoryzację, mając na uwadze te pomysły :)

user58163
źródło
Twoje pytanie zawiera literówkę. Myślę, że chodziło Ci o „Kiedy funkcja jest za długa?”.
Tom
1
Źle interpretujesz pytanie, stawiając je w kategoriach linii kodu. Czynniki determinujące nie są mierzone w wierszach kodu.
dkretz
to pytanie może się skomplikować w zależności od kodu i języka. może możesz to opublikować.
Ray Tayek,
Jeśli jest to zgodne z zasadą pojedynczej odpowiedzialności - po prostu zrób to. Zwykle czuję potrzebę tworzenia nagłówka lub dla każdych 20 linii kodu, co oznacza, że ​​muszę go wyodrębnić i nazwać ten fragment funkcją o znaczącej nazwie zamiast tworzyć nagłówek rozdziału.
Yevgeniy Afanasjew

Odpowiedzi:

76

Nie ma na to naprawdę sztywnych i szybkich zasad. Generalnie podoba mi się moje metody polegające na „robieniu jednej rzeczy”. Więc jeśli chodzi o pobieranie danych, a następnie robienie czegoś z tymi danymi, a następnie zapisywanie ich na dysku, to podzieliłbym pobieranie i zapis na osobne metody, więc moja metoda „główna” zawierała po prostu „robienie czegoś”.

To „robienie czegoś” może jednak składać się z kilku wierszy, więc nie jestem pewien, czy liczba wierszy jest właściwa :)

Edycja: To jest pojedynczy wiersz kodu, który wysłałem pocztą w zeszłym tygodniu w pracy (aby udowodnić, że to nie jest coś, do czego mam nawyk :)) - z pewnością nie chciałbym 50-60 tych złych chłopców w mojej metodzie :RE

return level4 != null ? GetResources().Where(r => (r.Level2 == (int)level2) && (r.Level3 == (int)level3) && (r.Level4 == (int)level4)).ToList() : level3 != null ? GetResources().Where(r => (r.Level2 == (int)level2) && (r.Level3 == (int)level3)).ToList() : level2 != null ? GetResources().Where(r => (r.Level2 == (int)level2)).ToList() : GetAllResourceList();
Stevena Robbinsa
źródło
1
LOL Cóż, mógłbym usunąć wszystkie białe znaki w mojej metodzie i byłaby to tylko jedna bardzo długa linia, a nie długa funkcja. Robiąc jedną rzecz, prawdopodobnie jest to odpowiedź niż, dzięki
@Movaxes Ten fragment kodu, który opublikowałem, jest jednak pojedynczą instrukcją, a nie tylko wieloma wierszami w jednym wierszu .. nie ma tam średników :) Mógłbym za każdym razem rozszerzyć GetResources (), aby było jeszcze bardziej złe: P
Steven Robbins
Tak, to ma sens. Dlaczego nie wziąć całego pliku źródłowego i umieścić go w jednej linii. Chodzi mi o to, że naprawdę zostaniesz „ninja” Web 2.0 :)
BobbyShaftoe,
Pamiętam, że w starych magazynach (mówię o BBC Micro old) mieli "programy 10-liniowe", które miały po kilka wypowiedzi w każdej linijce, aż do maksymalnej długości, z jaką BBC mogła sobie poradzić ... zawsze były właściwym bólem wpisać: D
Steven Robbins,
6
Podoba mi się koncepcja funkcji wykonującej tylko jedną rzecz ... ale. Jeśli masz funkcję, która robi 10 rzeczy i przenosisz 9 z tych rzeczy do oddzielnych funkcji, które są nadal wywoływane przez pozostałą funkcję, czyż nie ta pozostała funkcja nadal w istocie robi 10 rzeczy! Myślę, że takie rozbicie funkcji znacznie ułatwia testowanie.
mtnpaul
216

Oto lista sygnałów ostrzegawczych (w dowolnej kolejności), które mogą wskazywać, że funkcja jest zbyt długa:

  1. Głęboko zagnieżdżone struktury kontrolne : np. Pętle for 3 poziomy lub nawet 2 poziomy z zagnieżdżonymi instrukcjami if, które mają złożone warunki.

  2. Zbyt wiele parametrów definiujących stan : przez parametr definiujący stan rozumiem parametr funkcji, który gwarantuje określoną ścieżkę wykonania przez funkcję. Jeśli uzyskasz zbyt wiele tego typu parametrów, otrzymasz kombinatoryczną eksplozję ścieżek wykonania (zwykle dzieje się to w połączeniu z # 1).

  3. Logika, która jest powielana w innych metodach : złe ponowne wykorzystanie kodu jest ogromnym czynnikiem przyczyniającym się do monolitycznego kodu proceduralnego. Wiele z takich powielania logiki może być bardzo subtelnych, ale po ponownym uwzględnieniu końcowym rezultatem może być znacznie bardziej elegancki projekt.

  4. Nadmierne sprzężenie międzyklasowe : ten brak właściwej hermetyzacji powoduje, że funkcje dotyczą intymnych cech innych klas, a tym samym je wydłużają.

  5. Niepotrzebny narzut : Komentarze wskazujące na oczywiste, głęboko zagnieżdżone klasy, zbędne metody pobierające i ustawiające dla prywatnych zagnieżdżonych zmiennych klas oraz niezwykle długie nazwy funkcji / zmiennych mogą powodować szum składniowy w powiązanych funkcjach, który ostatecznie zwiększy ich długość.

  6. Twój ogromny wyświetlacz klasy deweloperskiej nie jest wystarczająco duży, aby go wyświetlić : w rzeczywistości dzisiejsze wyświetlacze są na tyle duże, że funkcja, która jest bliska jej wysokości, jest prawdopodobnie zbyt długa. Ale jeśli jest większy , to dymiący pistolet, że coś jest nie tak.

  7. Nie można od razu określić cel z funkcji : Ponadto, gdy faktycznie zrobić określić swój cel, jeśli nie można podsumować ten cel w jednym zdaniu lub zdarzy się mieć ogromny ból głowy, to powinno być wskazówką.

Podsumowując, funkcje monolityczne mogą mieć daleko idące konsekwencje i często są objawem poważnych niedociągnięć projektowych. Ilekroć napotykam kod, którego czytanie daje absolutną radość , jego elegancja jest od razu widoczna. I zgadnij co: funkcje są często bardzo krótkie.

Ryan Delucchi
źródło
1
Niezły post! Bardzo deterministyczny
Chuck Conway
2
@PedroMorteRolo Dokładnie. Standardowe API nie zawsze jest modelem elegancji. Co więcej, znaczna część interfejsu API języka Java została opracowana przy gruntownej znajomości kompilatora języka Java i maszyny JVM, dlatego należy wziąć pod uwagę kwestie wydajności, które mogą to wyjaśnić. Przyznaję, że krytyczne fragmenty kodu, które nie mogą zmarnować ani jednej milisekundy, mogą wymagać złamania niektórych z tych zasad, ale zawsze należy to traktować jako przypadek specjalny. Poświęcenie dodatkowego czasu na rozwój z góry jest początkową inwestycją, która może uniknąć przyszłego (potencjalnie paraliżującego) długu technologicznego.
Ryan Delucchi,
2
Swoją drogą… jestem zdania, że ​​heurystyka długich metod jest zła dotyczy również klas. IMHO, długie zajęcia są złe, ponieważ mają tendencję do naruszania zasady pojedynczej odpowiedzialności. Byłoby fajnie, gdyby kompilatory emitowały ostrzeżenia zarówno dla długich klas, jak i metod ...
Pedro Rolo
3
@PedroMorteRolo Zdecydowanie się z tym zgadzam. Co więcej, duże klasy prawdopodobnie będą miały bardziej zmienny stan, co prowadzi do kodu, który jest bardzo trudny do utrzymania.
Ryan Delucchi
1
Najlepsza odpowiedź. Kolejna dobra wskazówka to: jak wyglądają komentarze w kodzie? Ile razy mam natknął czyjegoś kodu z linii takich jak: // fetch Foo's credentials where Bar is "uncomplete". To prawie na pewno nazwa funkcji, którą należy oddzielić. Prawdopodobnie chce być refaktoryzowany na coś takiego: Foo.fetchCredentialWhereBarUncomplete()
Jay Edwards
29

Myślę, że jest ogromne zastrzeżenie do mantry „rób tylko jedną rzecz” na tej stronie. Czasami robienie jednej rzeczy powoduje żonglowanie wieloma zmiennymi. Nie dziel długiej funkcji na kilka mniejszych funkcji, jeśli mniejsze funkcje mają długie listy parametrów. W ten sposób pojedynczą funkcję przekształca się w zestaw wysoce powiązanych funkcji bez rzeczywistej wartości indywidualnej.

jmucchiello
źródło
18

Funkcja powinna robić tylko jedną rzecz. Jeśli robisz wiele małych rzeczy w funkcji, zrób każdą małą rzecz funkcją i wywołaj te funkcje z długiej funkcji.

To, czego naprawdę nie chcesz robić, to kopiować i wklejać co 10 wierszy swojej długiej funkcji do funkcji krótkich (jak sugeruje przykład).

Jeremy Ruten
źródło
Tak, tworzenie wielu małych funkcji za pomocą wzorca kopiuj i wklej nie jest
„Zrób jedną rzecz” może być poprawne lub nie, w zależności od stopnia szczegółowości. Jeśli funkcja mnoży macierz, nie ma sprawy. Jeśli funkcja buduje wirtualny samochód - to jest „jedna rzecz”, ale jest to również bardzo ważna rzecz. Aby zbudować samochód, można użyć wielu funkcji, komponent po komponencie.
void.pointer
17

Zgadzam się, że funkcja powinna robić tylko jedną rzecz, ale na jakim poziomie jest to jedna rzecz.

Jeśli twoje 60 linii spełnia jedną rzecz (z punktu widzenia twoich programów), a elementy, które składają się na te 60 linii, nie będą używane przez nic innego, to 60 linii jest w porządku.

Nie ma żadnej realnej korzyści z rozbijania go, chyba że można go rozbić na konkretne kawałki, które stoją samodzielnie. Metryka, której należy użyć, to funkcjonalność, a nie wiersze kodu.

Pracowałem nad wieloma programami, w których autorzy podnieśli jedyną rzecz na ekstremalny poziom, a skończyło się na tym, że wyglądało to tak, jakby ktoś wziął granat do funkcji / metody i wysadził go na dziesiątki niepołączonych elementów, które są trudne do naśladowania.

Wyciągając fragmenty tej funkcji, musisz również rozważyć, czy będziesz dodawać niepotrzebne narzuty i unikać przekazywania dużych ilości danych.

Uważam, że kluczową kwestią jest poszukiwanie możliwości ponownego użycia w tej długiej funkcji i wyciągnięcie tych części. Pozostaje ci funkcja, bez względu na to, czy ma długość 10, 20 czy 60 linii.

bruceatk
źródło
2
+1 „Metryka, której należy użyć, to funkcjonalność, a nie wiersze kodu”
Cody Piersall
Inną ważną miarą jest liczba poziomów zagnieżdżenia bloków. Ogranicz do minimum. Często pomaga rozbicie funkcji na mniejsze części. Inne rzeczy też mogą pomóc, na przykład wielokrotne zwroty.
user2367418
10

60 linii jest długich, ale niezbyt długich jak na funkcję. Jeśli zmieści się na jednym ekranie w edytorze, możesz zobaczyć to wszystko naraz. To naprawdę zależy od tego, co robią funkcje.

Dlaczego mogę rozbić funkcję:

  • To jest za długie
  • Sprawia, że ​​kod jest łatwiejszy w utrzymaniu, dzieląc go i używając znaczących nazw dla nowej funkcji
  • Funkcja nie jest spójna
  • Części funkcji są przydatne same w sobie.
  • Gdy trudno jest wymyślić sensowną nazwę funkcji (prawdopodobnie robi za dużo)
dajorad
źródło
3
Słuszne uwagi, zgadzam się, również jeśli musisz nazwać funkcję DoThisAndThisAndAlsoThis prawdopodobnie robi za dużo. dzięki :)
2
Jesteś po prostu nie w porządku z tym kumplem. 60 linii to zawsze za dużo. Powiedziałbym, że jeśli zbliżasz się do 10 linii, prawdopodobnie zbliżasz się do limitu.
willcodejavaforfood
Ale inna funkcja wciąż wywołuje te funkcje i jest zasadniczo tą samą DoThisAndThisAndAlsoThisfunkcją, ale z dużą ilością abstrakcji, którą nadal musisz jakoś nazwać
Timo Huovinen
6

Moja osobista heurystyka jest taka, że ​​jeśli nie widzę całości bez przewijania, jest za długo.

Ferruccio
źródło
4
... podczas gdy rozmiar czcionki został ustawiony na 5?
EricSchaefer
5

Rozmiar przybliżony do rozmiaru ekranu (więc weź duży panoramiczny ekran i obróć go) ... :-)

Żart na bok, jedna logiczna rzecz na funkcję.

A pozytywną rzeczą jest to, że testowanie jednostkowe jest znacznie łatwiejsze w przypadku małych funkcji logicznych, które wykonują jedną rzecz. Duże funkcje, które robią wiele rzeczy, są trudniejsze do zweryfikowania!

/ Johan

Johan
źródło
Dobra uwaga na temat testów jednostkowych :)
5

Zasada ogólna: jeśli funkcja zawiera bloki kodu, które coś robią, co jest nieco oddzielone od reszty kodu, należy umieścić ją w osobnej funkcji. Przykład:

function build_address_list_for_zip($zip) {

    $query = "SELECT * FROM ADDRESS WHERE zip = $zip";
    $results = perform_query($query);
    $addresses = array();
    while ($address = fetch_query_result($results)) {
        $addresses[] = $address;
    }

    // now create a nice looking list of
    // addresses for the user
    return $html_content;
}

dużo ładniejszy:

function fetch_addresses_for_zip($zip) {
    $query = "SELECT * FROM ADDRESS WHERE zip = $zip";
    $results = perform_query($query);
    $addresses = array();
    while ($address = fetch_query_result($results)) {
        $addresses[] = $address;
    }
    return $addresses;
}

function build_address_list_for_zip($zip) {

    $addresses = fetch_addresses_for_zip($zip);

    // now create a nice looking list of
    // addresses for the user
    return $html_content;
}

Takie podejście ma dwie zalety:

  1. Zawsze, gdy potrzebujesz pobrać adresy dla określonego kodu pocztowego, możesz skorzystać z łatwo dostępnej funkcji.

  2. Kiedy kiedykolwiek będziesz musiał ponownie odczytać funkcję build_address_list_for_zip(), wiesz, co zrobi pierwszy blok kodu (pobiera adresy dla określonego kodu pocztowego, przynajmniej to można uzyskać z nazwy funkcji). Jeśli zostawisz kod zapytania w tekście, musisz najpierw przeanalizować ten kod.

[Z drugiej strony (zaprzeczę, że ci powiedziałem, nawet podczas tortur): Jeśli dużo czytasz o optymalizacji PHP, możesz wpaść na pomysł, aby liczba funkcji była jak najmniejsza, ponieważ wywołania funkcji są bardzo, bardzo drogie w PHP. Nie wiem o tym, ponieważ nigdy nie robiłem żadnych testów porównawczych. W takim przypadku prawdopodobnie lepiej nie podążać za żadną z odpowiedzi na swoje pytanie, jeśli aplikacja jest bardzo wrażliwa na wydajność ;-)]

EricSchaefer
źródło
dzięki niezły przykład :)
5

Rzuć okiem na cyklomatyczny McCabe, w którym dzieli swój kod na wykres, na którym: „Każdy węzeł na wykresie odpowiada blokowi kodu w programie, w którym przepływ jest sekwencyjny, a łuki odpowiadają gałęziom pobranym w programie. "

Teraz wyobraź sobie, że twój kod nie ma funkcji / metod; to tylko jeden ogromny fragment kodu w postaci wykresu.

Chcesz rozbić ten rozrost na metody. Weź pod uwagę, że kiedy to zrobisz, w każdej metodzie będzie pewna liczba bloków. Tylko jeden blok każdej metody będzie widoczny dla wszystkich innych metod: pierwszy blok (zakładamy, że będziesz mógł przejść do metody tylko w jednym punkcie: w pierwszym bloku). Wszystkie pozostałe bloki w każdej metodzie będą informacjami ukrytymi w tej metodzie, ale każdy blok w metodzie może potencjalnie przeskoczyć do dowolnego innego bloku w tej metodzie.

Aby określić, jaki rozmiar powinny mieć twoje metody pod względem liczby bloków na metodę, jedno pytanie, które możesz sobie zadać, brzmi: ile metod powinienem mieć, aby zminimalizować maksymalną potencjalną liczbę zależności (MPE) między wszystkimi blokami?

Ta odpowiedź jest podana za pomocą równania. Jeśli r to liczba metod, które minimalizują błąd graniczny dopuszczalny (MPE) systemu, a n to liczba bloków w systemie, to równanie wygląda następująco: r = sqrt (n)

Można też wykazać, że daje to również liczbę bloków na metodę, które mają być również sqrt (n).

Ed Kirwan
źródło
4

Pamiętaj, że możesz skończyć z ponownym faktoringiem tylko dla samego ponownego faktorowania, potencjalnie sprawiając, że kod będzie bardziej nieczytelny niż był na początku.

Mój były kolega miał dziwną regułę, że funkcja / metoda musi zawierać tylko 4 linie kodu! Próbował trzymać się tego tak sztywno, że nazwy jego metod często stawały się powtarzalne i bez znaczenia, a wywołania stały się głęboko zagnieżdżone i zagmatwane.

Stała się więc moja własna mantra: jeśli nie możesz wymyślić przyzwoitej nazwy funkcji / metody dla fragmentu kodu, który analizujesz, nie przejmuj się.

Saltmeister
źródło
3

Głównym powodem, dla którego zwykle rozbijam funkcję, jest to, że jej fragmenty są również składnikami innej pobliskiej funkcji, którą piszę, więc części wspólne są uwzględniane. Ponadto, jeśli używa wielu pól lub właściwości z innej klasy, istnieje duża szansa, że ​​odpowiedni fragment można pobrać hurtowo i, jeśli to możliwe, przenieść do innej klasy.

Jeśli masz blok kodu z komentarzem na górze, rozważ wyciągnięcie go do funkcji, z nazwami funkcji i argumentów ilustrującymi jej cel, i zarezerwuj komentarz dla uzasadnienia kodu.

Czy na pewno nie ma tam elementów, które przydałyby się gdzie indziej? Jaka to funkcja?

Jeffrey Hantin
źródło
Funkcja tworzy plik pamięci podręcznej z szablonu na podstawie adresu URL, na przykład post_2009_01_01.html z adresu url / post /
3

Zwykle przerywam funkcje potrzebą umieszczenia komentarzy opisujących następny blok kodu. To, co wcześniej znajdowało się w komentarzach, teraz trafia do nowej nazwy funkcji. To nie jest twarda zasada, ale (dla mnie) miła praktyczna zasada. Lubię kod, który mówi sam za siebie, niż taki, który wymaga komentarzy (ponieważ nauczyłem się, że komentarze zwykle kłamią)

Olaf Kock
źródło
Lubię komentować mój kod, głównie nie dla siebie, ale dla innych, co eliminuje wiele pytań o to, gdzie zdefiniowano zmienną $, ale lubię też, aby kod był zrozumiały. Czy komentarze kłamią?
tak, ponieważ częściej niż nie są one utrzymywane. W chwili pisania tego tekstu mogą być poprawne, ale po wprowadzeniu poprawki lub nowej funkcji nikt nie wymusza zmiany komentarzy zgodnie z nową sytuacją. Nazwy metod mają tendencję do kłamstwa znacznie rzadziej niż komentarze IMHO
Olaf Kock
Właśnie trafiłem na tę odpowiedź: stackoverflow.com/questions/406760/ ... stwierdzając, że „Większość komentarzy w kodzie jest w rzeczywistości zgubną formą powielania kodu”. Również - długa linia komentarzy.
Olaf Kock
2

Moim zdaniem odpowiedź brzmi: kiedy robi za dużo rzeczy. Twoja funkcja powinna wykonywać tylko czynności, których oczekujesz od jej nazwy. Inną kwestią do rozważenia jest to, czy chcesz ponownie wykorzystać niektóre części swoich funkcji w innych; w tym przypadku może być przydatne podzielenie go.

Pierpaolo
źródło
1

Jest to po części kwestia gustu, ale jak to określam, staram się zachować moje funkcje tylko tak długo, jak zmieszczą się na moim ekranie w jednym czasie (maksymalnie). Powodem jest to, że łatwiej jest zrozumieć, co się dzieje, jeśli widzisz wszystko na raz.

Kiedy koduję, jest to mieszanka pisania długich funkcji, a następnie refaktoryzacji w celu wyciągnięcia bitów, które mogłyby zostać ponownie wykorzystane przez inne funkcje - oraz - pisania małych funkcji, które wykonują dyskretne zadania na bieżąco.

Nie wiem, czy jest jakaś dobra lub zła odpowiedź na to pytanie (np. Możesz wybrać 67 linii jako maksimum, ale może się zdarzyć, że warto dodać kilka więcej).

Andrew Hedges
źródło
Cóż, lubię też widzieć moją pełną funkcję na ekranie :) czasami oznacza to czcionkę Monospace 9 i dużą rozdzielczość na czarnym tle, zgadzam się, że łatwiej to zrozumieć w ten sposób.
1

Przeprowadzono szczegółowe badania na ten temat, jeśli chcesz najmniej błędów, twój kod nie powinien być zbyt długi. Ale też nie powinno być za krótkie.

Nie zgadzam się, że metoda powinna zmieścić się na ekranie w jednym, ale jeśli przewijasz w dół o więcej niż jedną stronę, metoda jest za długa.

Zobacz rozmiarowi Optymalne klasy dla obiektowego Oprogramowania do dalszej dyskusji.

Ian Hickman
źródło
dzięki za link, czytanie :)
1

Napisałem wcześniej 500 funkcji liniowych, ale były to tylko duże instrukcje przełączające do dekodowania i odpowiadania na wiadomości. Kiedy kod pojedynczej wiadomości stał się bardziej złożony niż pojedyncza instrukcja if-then-else, wyodrębniłem go.

W istocie, chociaż funkcja miała 500 linii, niezależnie utrzymywane regiony miały średnio 5 linii.

Joshua
źródło
1

Zwykle do pisania kodu używam podejścia opartego na testach. W tym podejściu rozmiar funkcji jest często powiązany z szczegółowością testów.

Jeśli twój test jest wystarczająco ukierunkowany, poprowadzi cię to do napisania małej, skoncentrowanej funkcji, która sprawi, że test zostanie zaliczony.

Działa to również w drugą stronę. Funkcje muszą być wystarczająco małe, aby skutecznie testować. Dlatego podczas pracy ze starszym kodem często okazuje się, że rozkładam większe funkcje, aby przetestować różne ich części.

Zwykle zadaję sobie pytanie „za co odpowiada ta funkcja” i jeśli nie potrafię określić tej odpowiedzialności w jasnym, zwięzłym zdaniu, a następnie przełożyć to na mały, ukierunkowany test, zastanawiam się, czy funkcja nie jest zbyt duża.

zakres leksykalny
źródło
1

Jeśli ma więcej niż trzy gałęzie, ogólnie oznacza to, że funkcja lub metoda powinna zostać rozdzielona, ​​aby hermetyzować logikę rozgałęzień w różnych metodach.

Każda pętla for, instrukcja if itp. Nie jest wtedy postrzegana jako gałąź w metodzie wywołującej.

Cobertura dla kodu Java (i jestem pewien, że istnieją inne narzędzia dla innych języków) oblicza liczbę if itp. W funkcji dla każdej funkcji i sumuje ją dla „średniej złożoności cyklicznej”.

Jeśli funkcja / metoda ma tylko trzy gałęzie, otrzyma trójkę na tej metryki, co jest bardzo dobre.

Czasami trudno jest postępować zgodnie z tą wytyczną, a mianowicie przy sprawdzaniu poprawności danych wejściowych użytkownika. Niemniej jednak umieszczanie gałęzi w różnych metodach pomaga nie tylko w rozwoju i utrzymaniu, ale także w testowaniu, ponieważ dane wejściowe do metod wykonujących rozgałęzienia można łatwo przeanalizować, aby zobaczyć, jakie dane wejściowe należy dodać do przypadków testowych, aby objąć gałęzie, które nie zostały objęte.

Gdyby wszystkie gałęzie znajdowały się w jednej metodzie, dane wejściowe musiałyby być śledzone od początku metody, co utrudnia testowalność.

Martin54
źródło
0

Podejrzewam, że znajdziesz na ten temat wiele odpowiedzi.

Prawdopodobnie rozbiję to na podstawie logicznych zadań wykonywanych w ramach funkcji. Jeśli wydaje ci się, że twoje opowiadanie zamienia się w powieść, proponuję znaleźć i wyodrębnić różne kroki.

Na przykład, jeśli masz funkcję, która obsługuje dane wejściowe w postaci ciągu i zwraca wynik w postaci ciągu, możesz podzielić tę funkcję na podstawie logiki dzielenia ciągu na części, logiki dodawania dodatkowych znaków i logiki wstawiania go wszystkie razem jako sformatowany wynik.

Krótko mówiąc, najlepszym podejściem jest wszystko, co sprawia, że ​​kod jest czysty i łatwy do odczytania (czy to po prostu zapewniając, że funkcja ma dobry komentarz, czy też ją rozbija).

Phil Wheeler
źródło
0

zakładając, że robisz jedną rzecz, długość będzie zależeć od:

  • co robisz
  • jakiego języka używasz
  • z iloma poziomami abstrakcji musisz się zmierzyć w kodzie

60 linii może być zbyt długich lub w sam raz. podejrzewam jednak, że może to być za długie.

Ray Tayek
źródło
Robię trochę cache'owania w PHP, tak pewnie 60 linii to za dużo, refaktoryzuję ...
0

Jedna rzecz (i ta rzecz powinna być oczywista z nazwy funkcji), ale nie więcej niż ekran pełen kodu, niezależnie od tego. Możesz też zwiększyć rozmiar czcionki. A jeśli masz wątpliwości, przerób to na dwie lub więcej funkcji.

gkrogers
źródło
0

Rozszerzając ducha tweeta od wujka Boba jakiś czas temu, wiesz, że funkcja staje się zbyt długa, gdy czujesz potrzebę wstawienia pustej linii między dwoma wierszami kodu. Chodzi o to, że jeśli potrzebujesz pustego wiersza do oddzielenia kodu, jego odpowiedzialność i zakres są oddzielane w tym momencie.

Mark Bostleman
źródło
0

Mój pomysł jest taki, że jeśli muszę zadać sobie pytanie, czy to jest za długie, to prawdopodobnie za długie. Pomaga w tworzeniu mniejszych funkcji w tym obszarze, ponieważ może pomóc w późniejszym cyklu życia aplikacji.

sokket
źródło