I metodi iterativi riducono la complessità ciclomatica e migliorano la supportabilità?

11

I metodi iterativi come quelli che si trovano comunemente in linguaggi moderni come C #, JavaScript e (si spera) in Java 8 riducono l'impatto della complessità ciclomatica sulla comprensibilità e supportabilità del codice?

Ad esempio in C # potremmo avere il seguente codice:

List<String> filteredList = new List<String>();

foreach (String s in originalList){
   if (matches(s)){
      filteredList.add(s);
   }
}

Questo ha una semplice complessità ciclomatica di 2.

Potremmo facilmente riscriverlo come:

List<String> filteredList = originalList.where(s => matches(s));

Che ha una semplice complessità ciclomatica di 0.

Questo in realtà comporta più codice supportabile? C'è qualche ricerca su questo argomento?

    
posta C. Ross 25.02.2013 - 16:17
fonte

6 risposte

14

La mia ipotesi è che hai appena diviso / spostato la complessità. È diminuito perché non si conta l'implementazione di .where() nel CC.

Il CC globale non è stato realmente spostato, il tuo CC own code è diminuito, solo perché ora è stato spostato nel codice del framework.

Direi che è più gestibile. Quando è una caratteristica della lingua, usala. Non è un "oh, capisco, è un trucco intelligente" che stai utilizzando, solo una semplice funzione di riduzione in linea.

    
risposta data 25.02.2013 - 17:33
fonte
11

Tutto quello che stai facendo è evidenziare un difetto nella complessità ciclomatica come una metrica, la complessità del codice in realtà non è cambiata. Hai un ramo esplicito nel primo esempio e devi capire che c'è un ramo implicito nel secondo. Il secondo è più chiaro e più facile da capire, purché comprendiate la sintassi e poiché utilizza una sintassi di base che potrebbe costituire un problema.

    
risposta data 25.02.2013 - 17:17
fonte
6

Per rispondere alla domanda in modo obiettivo, avremmo bisogno di una sorta di metrica per la manutenibilità. La complessità ciclomatica di per sé non è una misura di manutenibilità, ma è un componente di alcune metriche che pretendono di misurare la manutenibilità. Ad esempio, la formula per l' indice di manutenibilità è:

MI = 171 - 5.2 * ln(V) - 0.23 * (G) - 16.2 * ln(LOC)

dove G è la complessità ciclomatica del codice in questione. Pertanto, riducendo la complessità ciclomatica di un pezzo di codice, per definizione, migliora l'Indice di Manutenibilità del codice e altre metriche che utilizzano analogamente la complessità ciclomatica .

È difficile dire se il tipo di modifica che si propone renda il programma sembrare più gestibile ai programmatori; questo probabilmente dipende da quanto sono familiari con (nel tuo caso) il metodo where .

    
risposta data 25.02.2013 - 18:03
fonte
3

Poiché è stato dimostrato che la complessità ciclomatica (CC) è strongmente correlata al codice dimensione ", tanto che si può dire che CC non abbia assolutamente alcun potere esplicativo". quello che stai veramente chiedendo è se "metodi iterativi come quelli che si trovano comunemente in linguaggi moderni come C #, JavaScript e (si spera) in Java 8 riducano l'impatto della dimensione del codice sulla comprensibilità e supportabilità del codice."

A quel punto, si spera che la risposta sia ovvia. È noto da decenni che il codice più breve è generalmente più facile da capire, mantenere e supportare.

    
risposta data 25.02.2013 - 20:17
fonte
2

Se stai parlando della statistica grezza della complessità ciclomatica, certo. Hai appena messo a fuoco da 2 a 0. Se stai passando per numeri, puro guadagno, fino in fondo.

Da una prospettiva pratica (leggi: umana) però, direi che in realtà hai aumentato la complessità di 2. Un punto di questo deriva dal fatto che ora qualche altro programmatore deve portare o acquisire la conoscenza della LINQ fluente-sintassi per comprendere questo codice.

Un altro punto di maggiore difficoltà deriva dalla comprensione delle espressioni Lambda; anche se un Lambda è abbastanza semplice in questo caso , ci sono alcuni cambiamenti di paradigma che devono essere fatti per apprezzarli appieno.

Questo caso, usando a.where(x => matches(x, arg)) non è terribile, e in tutta onestà è un ottimo modo per convincere un collega a vedere e lavorare con le espressioni LINQ e Lambda per la prima volta (ho effettivamente presentato un tutorial su LINQ / Lambdas ad alcuni ex colleghi che usano questo e altri insiemi di codice, con grande efficacia). Tuttavia, l'uso di questi richiede una certa conoscenza.

Raccomando cautela, perché ho visto casi in cui il refactore LINQ è in realtà significativamente peggio da leggere rispetto a quello che diventa quel foreach loop.

    
risposta data 25.02.2013 - 23:57
fonte
1

Soggettivamente, dipende dal pubblico degli sviluppatori, se capiscono le espressioni lambda, quindi;

List<String> filteredList = originalList.where(s => matches(s));

è più veloce da capire e forse leggermente più semplice. Sarei più preoccupato dell'uso di s e match (). Né è auto-descrittivo, qualcosa del tipo;

List<String> filteredList = 
    originalList.where(stringToBeTested => matchesNameTest(stringToBeTested));

o

List<String> filteredList = 
        originalList.where(originalListString => matchesNameTest(originalListString));

fornisce allo sviluppatore informazioni più significative ed è più facile da analizzare, senza dover immergersi nella funzione matches () per determinare quale corrispondenza viene eseguita.

La manutenibilità non riguarda solo la capacità di comprendere il codice, ma principalmente la velocità e la precisione con cui è possibile comprendere il codice.

    
risposta data 25.02.2013 - 19:13
fonte

Leggi altre domande sui tag