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


11

I metodi iterativi che si trovano comunemente nei 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);
   }
}

Ciò ha una complessità ciclomatica semplice di 2.

Potremmo facilmente riscriverlo come:

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

Che ha una complessità ciclomatica semplice di 0.

Ciò comporta effettivamente un codice più sopportabile? C'è qualche ricerca reale su questo argomento?


2
Il tuo titolo chiede la riduzione della complessità ciclomatica, ma il tuo testo presuppone una riduzione del CC e chiede la manutenibilità. Questo ha il potenziale per essere una domanda preziosa, puoi modificare il titolo per essere più accurato?
Kilian Foth,

@KilianFoth È meglio?
C. Ross,

Vorrei associare metodi iterativi a metodologie di sviluppo iterativo. Penso che un termine migliore sarebbe funzioni di ordine superiore. (E a parte questo, i metodi non hanno tipo / vuoto di ritorno mentre le funzioni restituiscono qualcosa).
Johannes Rudolph,

@JohannesRudolph "i metodi non hanno tipo / vuoto di ritorno mentre le funzioni restituiscono qualcosa" - in quale lingua è vero? Non l'ho mai sentito; in effetti, l'unica vera distinzione che io abbia mai sentito era che i metodi sono associati a una classe, le funzioni no.
tre

Risposte:


14

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

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

Direi che è più mantenibile. Quando è una caratteristica della lingua, usala. Non è un "ohh, vedo, è un trucco intelligente" che stai usando, solo una semplice funzione di riduzione in linea.


11

Tutto quello che stai facendo è evidenziare un difetto nella complessità ciclomatica come metrica, la complessità del codice non è davvero 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 comprendere, a condizione che tu comprenda la sintassi e poiché utilizza una sintassi di base meno grave che potrebbe rappresentare un problema.


1
Si potrebbe sostenere che la complessità ciclomatica del proprio codice è ridotta qui, poiché wherequi è probabilmente da un quadro. Penso che la complessità ciclomatica come metrica sia utile anche qui perché, mentre spezzare una funzione in più non diminuisce la complessità complessiva del sistema (anzi, spesso la aumenta, anche se solo leggermente), ti aiuta a determinare quando parte del sistema diventa eccessivamente complessa e deve essere scomposta.
tre

6

Per rispondere obiettivamente alla domanda, avremmo bisogno di una sorta di metrica per la manutenibilità. La complessità ciclomatica in sé non è una misura della manutenibilità, ma è una 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)

dov'è Gla complessità ciclomatica del codice in questione. Pertanto, ridurre la complessità ciclomatica di un pezzo di codice migliora per definizione l'indice di manutenibilità del codice e altre metriche che usano allo stesso modo la complessità ciclomatica .

E 'difficile dire se il tipo di cambiamento che proponete rende il programma sembra più gestibile per i programmatori; ciò dipende probabilmente da quanto hanno familiarità con (nel tuo caso) il wheremetodo.


Attenzione: numeri magici! (>_<)
Izkata,

C'è solo questo piccolo problema con l'indice di manutenibilità. I tre componenti di esso sono il volume di Halstead, la complessità ciclomatica e le linee di codice. Sia il volume di Halstead che la complessità ciclomatica hanno dimostrato di essere fortemente correlati alle linee di codice. Ciò significa che potrebbe essere derivata un'equazione approssimativa alternativa per l'indice di manutenibilità che dipendeva SOLO da linee di codice che sarebbe quasi accurata come l'originale, con una difficoltà di calcolo considerevolmente inferiore.
John R. Strohm,

@ JohnR.Strohm Penso che otterrai un risultato simile anche se usi LOC come metrica di manutenibilità. La modifica del PO riduce LOC a 1 da 4, e anche altre modifiche che riducono la complessità ciclomatica riducono altrettanto LOC. Ad ogni modo, dipende davvero da come si definisce e si misura la manutenibilità.
Caleb,

1
@Caleb: concordato. Il punto che cerco di sottolineare è che le persone troppo spesso scelgono queste metriche e combinazioni di metriche davvero complicate, senza rendersi conto che quasi tutte hanno dimostrato di essere fortemente correlate al codice reale con semplici vecchie righe di codice (LOC) e quindi non hanno più valore predittivo o descrittivo di LOC.
John R. Strohm,

3

Poiché è stato dimostrato che la complessità ciclomatica (CC) è fortemente correlata alla dimensione del codice, "al punto che si può dire che CC non ha assolutamente alcun potere esplicativo proprio". quello che stai veramente chiedendo è se "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 dimensione del codice sulla comprensibilità e il supporto del codice".

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


2

Se stai parlando dello stat grezzo della complessità ciclomatica, certo. L'hai appena passato da 2 a 0. Se stai andando per numeri, guadagno puro, fino in fondo.

Da una prospettiva pratica (leggi: umana), direi che hai effettivamente aumentato la complessità di 2. Un punto di ciò deriva dal fatto che ora un altro programmatore deve portare o conoscere la sintassi fluida LINQ per capire questo codice.

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

Questo caso, l'utilizzo 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 (in realtà ho presentato un tutorial su LINQ / Lambdas ad alcuni ex colleghi che usano questo e altri insiemi di codice, con grande efficacia.) Tuttavia, l'utilizzo di questi richiede alcune conoscenze.

Raccomando cautela, perché ho visto casi in cui il refattore LINQ è in realtà significativamente peggiore da leggere rispetto a quello che foreachdiventa quel ciclo.


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ù facile. Sarei più preoccupato di usare s, e partite (). Né è auto-descrittivo, qualcosa di simile;

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 match () per determinare quale partita viene eseguita.

La manutenibilità non riguarda solo la capacità di comprendere il codice, ma soprattutto la velocità e l'accuratezza con cui è possibile comprendere il codice.


2
Ciao asso È un esempio, intenzionalmente privo di contenuto semantico per evidenziare la struttura.
C. Ross,
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.