Perché la complessità ciclomatica è così importante per un singolo metodo?


10

Sto usando SonarLint per Eclipse da poco, e mi ha aiutato molto. Tuttavia, mi ha sollevato una domanda sulla complessità ciclomatica.

SonarLint considera accettabile un CC di 10, e ci sono alcuni casi in cui sono al di là di esso, circa 5 o 6 unità. Tali parti sono correlate ai mappatori in cui i valori si basano su variabili diverse, ad esempio:

  • Il campo A si basa su String sA;
  • Il campo B si basa su String sB;
  • Il campo C si basa su String sC;
  • eccetera ...

Non ho altra scelta che mettere un ifper ogni campo. Questa non è la mia scelta (per fortuna) ma un sistema già esistente e complesso che non posso cambiare da solo.


Il nocciolo della mia domanda è: perché è così importante non avere un CC troppo alto in un solo metodo ? Se spostate alcune delle vostre condizioni in uno o più sotto-metodi per ridurre la complessità, non riduce il costo della vostra funzione generale, ma sta spostando il problema altrove, immagino?

(Ci scusiamo per eventuali piccoli errori).


MODIFICARE

La mia domanda non si riferisce alla complessità ciclomatica globale, ma solo alla complessità del metodo singolo e alla suddivisione del metodo (ho un momento difficile spiegare cosa intendo esattamente, scusa). Mi chiedo perché sia ​​possibile dividere le condizioni in metodi più piccoli se appartiene ancora a un "super metodo", che eseguirà semplicemente ogni sotto-metodo, aggiungendo così complessità all'algoritmo.

Il secondo link ( circa l'anti-pattern ) è di grande aiuto.




^^^ La domanda "testa di freccia" è probabilmente un duplicato migliore nel senso che spiega come migliorare il tuo codice ma ne ho scelto uno per la spiegazione dettagliata che risponde alla parte della tua domanda sulla complessità ciclomatica
moscerino

La suddivisione di un metodo in parti più piccole non riduce la quantità totale di codice eseguito ma chiarisce le singole attività che stanno accadendo; ognuno può essere compreso molto più facilmente individualmente rispetto a quando sono tutti aggrovigliati in un tutto più grande. Perlomeno rimuove molte variabili intermedie usa e getta dall'ambito più ampio.
Doval,

1
Per il tuo caso particolare descritto, farei qualcosa nel tuo metodo principale come "A = extractAFrom (sA);" per ogni campo. Probabilmente puoi trovare nomi migliori poiché conosci i campi effettivi e i loro usi.
Tin Man,

Risposte:


32

La cosa fondamentale qui: "capacità cerebrale".

Vedete, una delle principali funzioni del codice è ... da leggere . E il codice può essere facile da leggere e capire; o difficile.

E avere un CC alto implica semplicemente molti "livelli" all'interno di un metodo. E questo implica: tu, come lettore umano, avrai difficoltà a capire quel metodo.

Quando leggi il codice sorgente, il tuo cervello cerca automaticamente di mettere le cose in prospettiva: in altre parole, cerca di creare una qualche forma di "contesto".

E quando hai un metodo piccolo (con un buon nome) che consiste solo di poche righe e CC molto basso; allora il tuo cervello può facilmente accettare questo "blocco". Lo leggi, lo capisci; FATTO.

D'altra parte, se il tuo codice ha un alto CC, il tuo cervello impiegherà molti più "cicli" per dedurre ciò che sta succedendo.

Un altro modo per dirlo: dovresti sempre inclinarti a preferire una complessa rete di cose semplici rispetto a una semplice rete di cose complesse. Perché il tuo cervello è più bravo a capire le piccole cose.


9
Quindi fondamentalmente non si tratta di problemi tecnici , ma di umani ? Sembra davvero intelligente, non so come non ci abbia pensato prima. Grazie !
Yassine Badache,

4
In tal caso, ti consiglio vivamente di acquisire "Clean Code" di Robert Martin (potresti trovare il pdf gratuitamente sulle reti). Vedete, la creazione di codice leggibile è una delle virtù più importanti ma molto spesso ignorate di un buon programmatore.
GhostCat saluta Monica C. il

@YassineBadache CC rende anche difficile testare ogni angolo (copertura completa).
Tulains Córdova,

Questo è stato anche il nocciolo della carta goto di Dijkstra .
Seth Battin,

Nella mia esperienza, i bug sono quasi sempre nei metodi con un CC elevato e quando i bug sono in un metodo a CC basso, di solito sono totalmente ovvi, non c'è modo per loro di nascondersi oltre la prima esecuzione del codice. Inoltre, trovo che non devo quasi mai modificare un metodo a basso CC - più carico rimosso dal cervello.
Loren Pechtel,

6

CC, come tutte le altre regole empiriche per gli odori di codice, è euristico . Non è un criterio a prova di errore che ti dice una verità assoluta. Se lo fosse, la cosa ragionevole da fare sarebbe semplicemente rendere tali metodi illegali nella lingua e costringere le persone a raggiungere i loro scopi in un altro modo.

Ma non è così che funzionano gli indicatori. Il più delle volte la loro funzione è quella di avvisare le persone di cose di cui non erano a conoscenza. Nel tuo caso, sei consapevole che la logica è contorta e le soluzioni alternative la renderebbero ancora più contorta. Pertanto, non ha senso tentare di soddisfare la regola empirica primitiva, quando il suo scopo principale è quello di emettere avvisi per le persone che non sono consapevoli che esiste un problema.


2
Se "FieldA si basa su String sA" come afferma OP, non sono convinto che spostarlo in un CalculateFieldA (String sA) comporti un codice più contorto.
Taemyr,

2

In breve: si tratta della leggibilità e quindi della manutenibilità del codice.

Se hai un metodo lungo e complesso con molti (nidificati) if, diventa difficile dire cosa fa realmente. Se estrai alcuni metodi privati ​​e li assegni in modo significativo, è molto più semplice.


Mentre questa è una buona risposta, è un po 'breve. Sarebbe bello se potessi fornire un esempio di ciò che stai dicendo, ed essere più specifico riguardo alla domanda posta dall'OP: "perché è così importante non avere un CC troppo alto in un solo metodo?".
Machado,

2

La complessità ciclomatica di un metodo è correlata al numero di casi di test richiesti per un metodo. In particolare, una complessità ciclomatica di 10 significa che 10 è il limite superiore per i casi di test per avere una copertura totale del ramo per il tuo metodo. È anche correlato al numero di percorsi che devono essere testati, meno eventuali percorsi impossibili.

Oltre a ciò, concordo con le altre risposte per altre considerazioni: la capacità mentale di uno sviluppatore o un indicatore di potenziali problemi o refactoring o una misura di leggibilità e manutenibilità del codice .


0

CC è solo un'euristica e quanto "cattivo" sia un punteggio particolare dipende da molte cose.

Detto questo, dovresti sempre vedere un CC alto come qualcosa che evidenzia il codice che potrebbe / dovrebbe essere refactored. Dici che spostare l' ifistruzione in un altro metodo sta nascondendo il problema - ma c'è un modello lì che puoi astrarre invece di copiare e incollare n volte? Se è una if-elsecatena lunga , puoi trasformarla in un'istruzione switch o forse usare il polimorfismo o qualcos'altro? Se esiste un annidamento profondo, è possibile unire alcune delle clausole condizionali o indicare responsabilità separate che dovrebbero essere suddivise in classi diverse?


0

Vedo la complessità ciclomatica come un avvertimento. Se riesci a leggere il codice e non è troppo complesso da capire, non mi preoccuperei molto di esso, probabilmente ci sono cose più importanti di cui preoccuparsi, ci sono sempre.

Un modo per ridurre il tipo di CC che menzioni è usare il polimorfismo, poiché hai taggato la tua domanda con il tag Java. Quindi, invece di digitare stringentemente i percorsi del codice, puoi usare classi ben denominate. Questo può aiutare, ma a volte è eccessivo e può rendere il tuo codice ancora più difficile da capire.

Tuttavia, può essere un segno di codice che sarà difficile da mantenere. Durante la lettura del metodo, è facile vedere quale percorso di codice verrà visualizzato per ciascun caso? Saresti in grado di saltare questo metodo se non conosci bene la base di codici e stavi cercando qualcosa di correlato ma più avanti nel codice? So che alcune persone sostengono la suddivisione dei metodi in molti metodi di 1/2 linea con nomi descrittivi, ma a volte penso che sia ancora più difficile da leggere rispetto al codice che doveva sostituire.

In definitiva la manutenibilità è un problema difficile e sta a te decidere quale pensi che sarà più facile da leggere. Il fatto che tu stia pensando a questo significa che sei sulla strada giusta. Ricorda, il manutentore che deve provare a decifrare questo codice tra un anno potresti essere tu. Quindi rendilo il più semplice possibile per loro.


0

Dipende da quanto tempo passa a guardare (cicli cerebrali) il codice e capire cosa sta facendo il codice.

  • Prendi in considerazione un metodo a 10 righe - Probabilmente impiegherai qualche minuto per capire cosa sta facendo.
  • Prendi in considerazione un metodo a 100 righe - Probabilmente impiega un'ora o più per capire cosa sta facendo.
  • Prendi in considerazione un metodo a 1000 righe - Probabilmente impiega un giorno o più per capire cosa sta facendo.

Anche metodi più grandi sono più difficili da testare e più difficili da prevedere che tipo di comportamento potrebbe verificarsi.

La complessità ciclomatica è una misura. In questo caso, valori più alti sono indicatori di potenziali problemi. Il codice complesso richiede più tempo per comprendere e probabilmente non viene testato in modo approfondito come i metodi meno complessi. Pertanto, è importante notare quali aree del codice sono complesse con questa misura ai fini del refactoring e della manutenzione.

Un'altra cosa da considerare è l'aggiornamento di codice complesso. Durante l'analisi, uno sviluppatore potrebbe segnalare che la modifica del codice è più o meno rischiosa osservando la sua complessità.

Quindi, c'è molto valore nella misurazione della complessità che può essere sfruttata e utilizzata per scopi decisionali.


1
Mi dispiace Ghost Cat risposta molto simile, dovrebbe avere aggiornato la pagina.
Jon Raynor,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.