Dlaczego złożoność cykliczna jest tak ważna dla jednej metody?


10

Od niedawna używam SonarLint do Eclipse , co bardzo mi pomogło. Podniosło mnie jednak pytanie o złożoność cykliczną.

SonarLint uważa za akceptowalny współczynnik CC wynoszący 10, a w niektórych przypadkach przekraczam ten limit, około 5 lub 6 jednostek. Części te są powiązane z elementami odwzorowującymi, w których wartości zależą od różnych zmiennych, na przykład:

  • Pole A opiera się na String sA;
  • Pole B opiera się na String sB;
  • Pole C opiera się na String sC;
  • itp ...

Nie mam innego wyboru niż postawienie ifdla każdego pola. To nie jest mój wybór (na szczęście), ale już istniejący i złożony system, którego sam nie mogę zmienić.


Rdzeń mojego pytania brzmi: dlaczego tak ważne jest, aby nie mieć zbyt wysokiego CC w jednej metodzie ? Jeśli przeniesiesz niektóre z twoich warunków w jednej lub więcej pod-metodach w celu zmniejszenia złożoności, nie obniży to kosztów ogólnej funkcji, po prostu przenosi problem gdzie indziej, tak myślę?

(Przepraszam za małe błędy, jeśli występują).


EDYTOWAĆ

Moje pytanie nie odnosi się do globalnej złożoności cyklomatycznej, ale tylko do złożoności pojedynczej metody i podziału metod (mam trudność z wyjaśnieniem, co dokładnie mam na myśli, przepraszam). Pytam, dlaczego dopuszczalne jest podzielenie waszych warunków na mniejsze metody, jeśli nadal należą one do „super metody”, która po prostu wykona każdą pod-metodę, zwiększając w ten sposób złożoność algorytmu.

Drugi link ( dotyczący anty-wzoru ) jest jednak bardzo pomocny.




^^^ Pytanie „strzałka w głowę” jest prawdopodobnie lepszym duplikatem w tym sensie, że wyjaśnia, jak poprawić kod, ale wybrałem pierwsze z powodu szczegółowych wyjaśnień odpowiadających części twojego pytania na temat złożoności cyklicznej
gnat

Podział metody na mniejsze części nie zmniejsza całkowitej ilości wykonanego kodu, ale uwidacznia poszczególne wykonywane zadania; każdy z nich można zrozumieć znacznie łatwiej indywidualnie, niż gdy wszystkie są splątane w większą całość. Przynajmniej usuwa wiele jednorazowych zmiennych pośrednich z większego zakresu.
Doval,

1
W konkretnym opisanym przypadku zrobiłbym coś w podstawowej metodzie, na przykład „A = extractAFrom (sA);” dla każdego pola. Prawdopodobnie możesz wymyślić lepsze nazwy, ponieważ znasz rzeczywiste pola i ich zastosowania.
Tin Man,

Odpowiedzi:


32

Najważniejsze tutaj: „pojemność mózgu”.

Widzisz, jedną z głównych funkcji kodu jest ... do odczytania . Kod może być łatwy do odczytania i zrozumienia; lub trudne.

A wysokie CC oznacza po prostu wiele „poziomów” w ramach jednej metody. A to oznacza: ty, jako ludzki czytelnik, będziesz miał trudności ze zrozumieniem tej metody.

Kiedy czytasz kod źródłowy, twój mózg automatycznie próbuje spojrzeć z innej perspektywy: innymi słowy - próbuje stworzyć jakąś formę „kontekstu”.

A kiedy masz małą metodę (o dobrej nazwie), która składa się tylko z kilku linii i bardzo niskiego CC; wtedy twój mózg może łatwo zaakceptować ten „blok”. Czytasz to, rozumiesz; GOTOWY.

Z drugiej strony, jeśli twój kod ma wysokie CC, twój mózg wyda wiele „cykli” więcej, aby odjąć to, co się dzieje.

Innym sposobem powiedzenia tego jest: zawsze powinieneś skłaniać się ku preferowaniu złożonej sieci prostych rzeczy zamiast prostej sieci złożonych rzeczy. Ponieważ twój mózg lepiej rozumie małe rzeczy.


9
Więc w zasadzie nie chodzi o kwestie techniczne , ale o człowieka ? To rzeczywiście brzmi trochę sprytnie, nie wiem, jak wcześniej o tym nie myślałem. Dzięki !
Yassine Badache

4
Jeśli tak, z całego serca polecam zakup „Czystego kodu” Roberta Martina (plik pdf można znaleźć bezpłatnie w sieci). Widzisz, tworzenie czytelnego kodu jest jedną z najważniejszych, ale bardzo często ignorowanych zalet dobrego programisty.
GhostCat pozdrawia Monikę C.

@YassineBadache CC utrudnia również testowanie każdego zakątka (pełne pokrycie).
Tulains Córdova,

To był także sedno gazety goto Dijkstry .
Seth Battin

Z mojego doświadczenia wynika, że ​​błędy prawie zawsze dotyczą metod o wysokim CC, a gdy błędy dotyczą metody o niskim CC, są one zwykle całkowicie oczywiste, nie ma sposobu, aby ukryć się przy pierwszym uruchomieniu kodu. Uważam też, że prawie nigdy nie muszę modyfikować metody o niskim CC - więcej obciążenia zostaje zdjęte z mózgu.
Loren Pechtel,

6

CC, podobnie jak wszystkie inne ogólne zasady dotyczące zapachów kodu, jest heurystyką . To nie jest bezpieczne kryterium, które mówi absolutną prawdę. Gdyby tak było, rozsądną rzeczą byłoby po prostu uczynienie takich metod nielegalnymi w języku i zmusić ludzi do osiągnięcia swoich celów w inny sposób.

Ale nie tak działają wskaźniki. Przez większość czasu ich funkcją jest ostrzeganie ludzi o rzeczach, o których nie byli świadomi. W twoim przypadku masz świadomość, że logika jest skomplikowana, a alternatywne rozwiązania sprawiłyby, że byłaby jeszcze bardziej skomplikowana. Dlatego nie ma sensu próbować spełniać prymitywnej reguły, kiedy jej głównym celem jest wydawanie ostrzeżeń osobom, które nie są świadome, że istnieje problem.


2
Jeśli „FieldA polega na String sA”, jak stwierdza OP, nie jestem przekonany, że przeniesienie go do CalculateFieldA (String sA) powoduje, że kod jest bardziej skomplikowany.
Taemyr

2

Krótko mówiąc: chodzi przede wszystkim o czytelność, a zatem i łatwość konserwacji twojego kodu.

Jeśli masz długą, złożoną metodę z dużą liczbą (zagnieżdżonych) if, trudno jest powiedzieć, co ona właściwie robi. Jeśli wyodrębnisz niektóre prywatne metody i nadasz im sensowne znaczenie, będzie to o wiele łatwiejsze.


Jest to dobra odpowiedź, ale jest trochę krótka. Byłoby miło, gdybyś mógł podać przykład tego, co mówisz i sprecyzować pytanie zadane przez OP: „dlaczego tak ważne jest, aby nie mieć zbyt wysokiego CC w jednej metodzie?”.
Machado,

2

Cyklomatyczna złożoność metody jest związana z liczbą przypadków testowych wymaganych dla metody. W szczególności cykliczna złożoność wynosząca 10 oznacza, że ​​10 jest górną granicą dla przypadków testowych, aby uzyskać całkowite pokrycie gałęzi dla Twojej metody. Jest to również związane z liczbą ścieżek, które należy przetestować, pomniejszoną o ścieżki niemożliwe.

Poza tym zgadzam się z innymi odpowiedziami na inne względy - zdolności umysłowe dewelopera lub wskaźnik potencjalnych problemów lub refaktoryzacji lub miarę czytelności i możliwości utrzymania kodu .


0

CC to tylko heurystyka, a to, jak „zły” jest konkretny wynik, zależy od wielu rzeczy.

To powiedziawszy, zawsze powinieneś widzieć wysokie CC jako coś, co podkreśla kod, który można / powinien zostać zrefaktoryzowany. Mówisz, że przeniesienie ifinstrukcji na inną metodę ukrywa problem - ale czy istnieje tam wzorzec, który można streścić zamiast kopiować wklejanie n razy? Jeśli jest to długi if-elsełańcuch, czy możesz zamienić go w instrukcję switch, a może użyć polimorfizmu lub czegoś innego? Jeśli istnieje głębokie zagnieżdżanie, czy niektóre z waszych klauzul warunkowych można połączyć, czy też oznacza to oddzielne obowiązki, które należy podzielić na różne klasy?


0

Widzę złożoność cykliczną jako ostrzeżenie. Jeśli umiesz czytać kod i nie jest to zbyt skomplikowane do zrozumienia, nie martwiłbym się tym zbytnio, prawdopodobnie są ważniejsze rzeczy, o które należy się martwić, zawsze takie są.

Jednym ze sposobów zmniejszenia wspomnianego CC jest użycie polimorfizmu, ponieważ otagowałeś swoje pytanie tagiem Java. Dlatego zamiast ciągów wpisywanych ścieżek kodu można używać dobrze nazwanych klas. Może to pomóc, ale czasami jest przesadne i może sprawić, że kod będzie jeszcze trudniejszy do zrozumienia.

Może to być jednak znak kodu, który będzie trudny do utrzymania. Czy czytając tę ​​metodę, łatwo jest zobaczyć, którą ścieżkę kodu pójdziesz w dół dla każdego przypadku? Czy byłbyś w stanie pominąć tę metodę, jeśli nie znasz dobrze podstawy kodu i szukałeś czegoś związanego, ale dalej w kodzie? Wiem, że niektórzy opowiadają się za dzieleniem metod na wiele metod 1/2 liniowych z opisowymi nazwami, ale czasami myślę, że jest to trudniejsze do odczytania niż kod, który miał zastąpić.

Ostatecznie łatwość konserwacji jest trudnym problemem i to Ty decydujesz, który z nich będzie łatwiejszy do odczytania. Fakt, że w ogóle o tym myślisz, oznacza, że ​​jesteś na dobrej drodze. Pamiętaj tylko, że opiekun, który za kilka lat będzie musiał odszyfrować ten kod, może być tobą. Ułatw im to, jak to możliwe.


0

Wszystko sprowadza się do tego, ile czasu spędza się na przeglądaniu kodu (cykli mózgowych) i zrozumieniu tego, co robi kod.

  • Rozważ metodę 10-liniową - Prawdopodobnie zajmie kilka minut, aby zrozumieć, co robi.
  • Rozważ metodę 100-liniową - Prawdopodobnie zajmie to godzinę lub dłużej, aby zrozumieć, co się dzieje.
  • Zastanów się nad metodą 1000 linii - prawdopodobnie zrozumienie tego, co się dzieje, zajmuje prawdopodobnie dzień lub dłużej.

Również większe metody są trudniejsze do przetestowania i trudniejsze do przewidzenia, jakie zachowanie może wystąpić.

Cyklomatyczna złożoność jest miarą. W takim przypadku wyższe wartości są wskaźnikami potencjalnych problemów. Złożony kod wymaga więcej czasu na zrozumienie i prawdopodobnie nie jest tak dokładnie testowany jak mniej złożone metody. Dlatego ważne jest, aby pamiętać, które obszary kodu są złożone z tym środkiem do celów refaktoryzacji i konserwacji.

Inną rzeczą do rozważenia jest aktualizacja złożonego kodu. Wykonując analizę, deweloper może zgłosić, że zmiana kodu jest mniej lub bardziej ryzykowna, patrząc na jego złożoność.

Mierzenie złożoności ma więc dużą wartość, którą można wykorzystać i wykorzystać do celów decyzyjnych.


1
Niestety, Ghost Cat odpowiada bardzo podobnie, powinien był odświeżyć stronę.
Jon Raynor,
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.