2014-09-15 14 views
5

preferisco questo stile di scrittura con rendimenti prime:dichiarazioni rientro anticipato e la complessità ciclomatica

public static Type classify(int a, int b, int c) { 
    if (!isTriangle(a, b, c)) { 
     return Type.INVALID; 
    } 
    if (a == b && b == c) { 
     return Type.EQUILATERAL; 
    } 
    if (b == c || a == b || c == a) { 
     return Type.ISOSCELES; 
    } 
    return Type.SCALENE; 
} 

Purtroppo, ogni return dichiarazione aumenta la metrica complessità ciclomatica calcolato da Sonar. Prendere in considerazione questa alternativa:

public static Type classify(int a, int b, int c) { 
    final Type result; 
    if (!isTriangle(a, b, c)) { 
     result = Type.INVALID; 
    } else if (a == b && b == c) { 
     result = Type.EQUILATERAL; 
    } else if (b == c || a == b || c == a) { 
     result = Type.ISOSCELES; 
    } else { 
     result = Type.SCALENE; 
    } 
    return result; 
} 

La complessità ciclomatica di questo secondo approccio riportato da Sonar è inferiore alla prima, per 3. Mi è stato detto che questo potrebbe essere il risultato di una errata applicazione delle metriche CC. O è corretto Sonar, e questo è davvero meglio? Queste domande relative sembrano essere d'accordo con quanto segue:

https://softwareengineering.stackexchange.com/questions/118703/where-did-the-notion-of-one-return-only-come-from

https://softwareengineering.stackexchange.com/questions/18454/should-i-return-from-a-function-early-or-use-an-if-statement

Se posso aggiungere il supporto per un paio di più tipi di triangolo, la return dichiarazioni si sommano a fare una differenza significativa nella metrica e la causa una violazione del sonar. Non voglio incollare un // NOSONAR al metodo, poiché questo potrebbe mascherare altri problemi con nuove funzionalità/bug aggiunti al metodo in futuro. Quindi uso la seconda versione, anche se non mi piace molto. C'è un modo migliore per gestire la situazione?

+0

Secondo http://en.wikipedia.org/wiki/Cyclomatic_complexity, CC è il numero di percorsi linearmente indipendenti attraverso la funzione, che è in entrambi i casi 4. Sonar ti dice qualcosa di diverso? –

+1

Yeap. Sonar aggiunge +1 per ogni istruzione return. È la regola "calam: MethodCyclomaticComplexity': https://dev.eclipse.org/sonar/rules/show/squid:MethodCyclomaticComplexity Una regola precedente (ma ora deprecata a favore di squid) non aveva questo vincolo: https: // dev.eclipse.org/sonar/rules/show/checkstyle:com.puppycrawl.tools.checkstyle.checks.metrics.CyclomaticComplexityCheck – janos

+0

quindi questa domanda significa davvero "come impedire a Sonar di calcolare il CC sbagliato" - che non è un buon adatto per questo sito. Tali domande sono meglio posizionate su StackOverflow. Segnalo questa domanda per la migrazione. –

risposta

2

Non proprio una risposta, ma troppo lungo per un commento.

Questa regola SONAR sembra essere completamente rotta. Si potrebbe riscrivere

b == c || a == b || c == a 

come

b == c | a == b | c == a 

e guadagna due punti in questo strano gioco (e forse anche un po 'di velocità ramificazione è costoso, ma questo è a discrezione del JITC, comunque).

Il old rule afferma che la complessità ciclomatica è correlata al numero di test. Il new one non lo fa, ed è una buona cosa dato che ovviamente il numero di test significativi per i tuoi due frammenti è esattamente lo stesso.

C'è un modo migliore per gestire la situazione?

In realtà, io ho una risposta: per utilizzare ogni rientro anticipato | invece di || una volta. : D

Ora sul serio: c'è un bug che richiede annotations che consente di disabilitare una singola regola, che è contrassegnata come fissa. Non guarderò oltre.

2

La tua domanda si riferisce a https://jira.codehaus.org/browse/SONAR-4857. Per il momento tutti gli analizzatori SonarQube mescolano la complessità ciclomatica e la complessità essenziale. Da un punto di vista teorico, la dichiarazione di ritorno non dovrebbe incrementare il cc e questo cambiamento avverrà nell'ecosistema SQ.

+0

Grazie! Qualche idea quando? – janos

+1

Di sicuro entro la fine dell'anno, ma per ora non può essere più preciso. –

0

Poiché la domanda riguarda anche le dichiarazioni di ritorno anticipato come stile di codifica, sarebbe utile considerare l'effetto della dimensione sullo stile di ritorno. Se il metodo o la funzione sono piccoli, meno di 30 righe, i ritorni anticipati non sono un problema, perché chiunque leggendo il codice può vedere l'intero metodo a colpo d'occhio, inclusi tutti i ritorni.In metodi o funzioni più ampi, un ritorno anticipato può essere una trappola involontariamente impostata per il lettore. Se il ritorno anticipato avviene sopra il codice che il lettore sta guardando, e il lettore non sa che il rendimento è superiore o dimentica che è sopra, il lettore non capirà il codice. Il codice di produzione può essere troppo grande per adattarsi a uno schermo.

Quindi chiunque stia gestendo una base di codice per la complessità dovrebbe consentire la dimensione del metodo nei casi in cui la complessità sembra essere un problema. Se il codice richiede più di uno schermo, uno stile di ritorno più pedante può essere giustificato. Se il metodo o la funzione è piccola, non ti preoccupare.

(uso sonar e sperimentato questo stesso problema.)

+1

Sono fortemente in disaccordo. Hai ragione con la parte che in un piccolo metodo, i ritorni anticipati vanno bene. In realtà, in un piccolo metodo, tutto va bene. In un grande metodo, tutto è un problema, e questo è il punto. Perché qualcuno scrive metodi oltre 30 righe ??? Guardando il codice che ho scritto ieri dormendo a metà vedo un pasticcio lì e il casino sono i grandi metodi (circa 30 righe). ** Elimina i grandi metodi ** e starai bene. ** Se il codice richiede più di uno schermo, refactoring. ** – maaartinus