Cyclomatic Complexity: il colesterolo del codice sorgente

In questo articolo parleremo del colesterolo del codice sorgente, ovvero ciò che viene definito come Cyclomatic Complexity.

Ebbene sì, hai letto bene: anche il codice sorgente potrebbe avere problemi di trigliceridi. 🙂

Se anche tu sviluppi software come me, ti sarà senz’altro capitato di avere a che fare con il cosiddetto Spaghetti Code: è un termine usato per indicare quel tipo di codice che diviene incomprensibile poiché pieno zeppo di condizioni, cicli, salti e rimandi, a tal punto da sembrare una palla appiccicosa di spaghetti stracotti come quelli delle peggiori mense aziendali.

La programmazione a oggetti (OOP) ci viene in aiuto consentendoci di strutturare meglio il codice, magari suddividendolo in layer, ovvero strati impermeabili ciascuno dedicato a una funzionalità specifica. Con diligenza, si creano livelli su livelli, ciascuno con singola responsabilità, fino a quando il numero di strati non diventa tale per cui gli spaghetti si trasformano e assumono la forma di una gigantesca lasagna, ed ecco a voi il Lasagna Code.

Spaghetti CodeSe cerchiamo un compromesso tra i due, possiamo scrivere famiglie di classi finalizzate a un particolare scopo e cercare di farle dialogare tra loro: è il Ravioli Code, ma non è un compito facile stabilire in seguito le relazioni tra queste famiglie. Se poi si adottano anche tecnologie e linguaggi di programmazione diversi, ecco che ci troviamo allora con un Maccaroni Code.

Tutto questo parlare di pasta mi ha fatto venire una gran fame, ma anche sorgere una domanda: non c’è uno strumento rapido ed efficace per poter misurare quanto “fa male” alla nostra salute il codice che siamo scrivendo?

Cyclomatic Complexity

Quando ho letto questo termine la prima volta, ho pensato «che diamine è questa roba?». Se vi capiterà di leggere qualcosa sul Clean Code oppure sui principi SOLID, troverete un sacco di termini simpaticamente complicati che, in realtà, nella maggior parte dei casi si riferiscono a concetti semplici e alla portata di chiunque. La Complessità Ciclomatica non fa eccezione, sebbene sembri il titolo di una puntata di The Big Bang Theory.

Ma quindi di cosa si tratta? Niente paura, non ci metteremo di sicuro a enunciare e analizzare formule complesse, anche perché ai tempi delle superiori io avevo 4 in matematica: immaginatela come un indice, un punteggio che viene dato al vostro codice, e tante più sono le strade che il vostro codice può percorrere durante l’esecuzione, maggiore è il valore attribuito a questo indice.

Ad esempio, se abbiamo un codice fatto solamente di istruzioni di assegnazione, o semplici chiamate ad altri metodi (o procedure, o funzioni che siano), il valore sarà quello più basso, ovvero 1 (uno). Se introduciamo una istruzione if, ecco che stiamo creando un “bivio”, ovvero due strade distinte che si possono intraprendere potenzialmente, e il valore aumenta quindi di due punti passando a un totale di tre. E se introduciamo uno switch? Ecco che l’indice della complessità incrementerà di una unità per ogni alternativa che introdurremo all’interno del costrutto. Lo stesso vale per cicli for. In conclusione, più sono i cammini indipendenti che il nostro software potrà percorrere, maggiore sarà il valore della complessità ciclomatica.

Possiamo quindi dire che la Cyclomatic Complexity è un po’ come il colesterolo nel codice: non si può azzerare, ma più il valore è basso meglio è, e bisogna sforzarsi di mantenerlo tale.

Quali sono i rischi?

In genere, i metodi con indice di complessità elevato tendono a essere eccessivamente lunghi, con molteplici righe che potrebbero essere isolate in metodi distinti, poi hanno una incidenza negativa sulla leggibilità e numerose variabili che sottraggono tante scelte dalla rosa dei nomi intelligibili da utilizzare. Insomma, se il software non può rischiare l’infarto, lo sviluppatore che dovrà manutenere quel codice sì.

Per coloro poi che praticano il salutare sport dello Unit Testing, la faccenda si complica: più sono le vie percorribili dal software, maggiore è la quantità di test da scrivere per coprirle tutte in modo da verificare tutte le possibili condizioni.

Misurare la complessità

Il primo passo per ridurre la complessità del codice è dotarsi degli strumenti appropriati per poterla “diagnosticare”. Non serve lo stetoscopio, né gli esami del sangue, ma è sufficiente controllare che l’ambiente di sviluppo in uso possa misurare la cyclomatic complexity del codice. Vediamone alcuni come esempio.

Cyclomatic Complexity in DelphiRAD Studio, l’IDE prodotto da Embarcadero per lo sviluppo con Delphi e C++Builder, include strumenti per l’analisi del codice e la visualizzazione di diversi parametri, incluso un coefficiente di tossicità dei metodi. Una volta aperto il progetto su cui lavorare, basta selezionare il menu [Project|Method Toxicity Metrics] per richiamare una finestra che mostra istantaneamente gli indici calcolati in base alle metriche disponibili.

Cyclomatic Complexity in Visual StudioPer gli sviluppatori .NET che utilizzano Visual Studio con i linguaggi C# o Visual Basic.NET, suggerisco una estensione di terze parti – CodeMaid – che offre diverse funzionalità interessanti (tutte descritte nel sito ufficiale), inclusa una finestra denominata Spade che mostra i tipi definiti nel file sorgente aperto nell’editor, la loro struttura (campi, metodi, proprietà, ecc.) indicando per ciascun metodo l’indice della Cyclomatic Complexity aggiornato a ogni salvataggio. In alternativa, se siete felici possessori di ReSharper, un tool che non dovrebbe assolutamente mancare in qualsiasi installazione di Visual Studio, potete scaricare una estensione gratuita che calcola la complessità dei metodi e visualizza un warning quando questa supera le soglie di tolleranza prestabilite.

Qualunque sia il tool di sviluppo che state utilizzando, verificate quanto prima l’esistenza di un prodotto o di una estensione (gratuita o a pagamento che sia) in grado di fornirvi questa misura, ancora meglio se in tempo reale e con la possibilità di tenere d’occhio costantemente i valori.

Come “curare” il codice?

Quando il dottore ci diagnostica una complessità elevata nel codice, come possiamo intervenire per ridurla?

Lo slogan sarà pure molto inflazionato, ma anche in questo caso prevenire è meglio che curare: quando si scrive il codice, è necessario monitorare l’indice di complessità e accertarsi che non oltrepassi il limite della dignità. Se ci si accorge che il valore inizia a diventare troppo alto, questo è un chiaro segnale che il codice implementato sta divenendo troppo complesso e intricato ed è necessario quindi eseguire un refactoring per ottimizzarlo o suddividerlo in metodi più piccoli, molto più gestibili e ricollocabili anche in altre strutture, se necessario. Molti tool di refactoring incluso il già citato ReSharper sono dotati di una funzione “Extract Method” per isolare un pezzo di codice all’interno di un metodo lasciando al suo posto la chiamata a quest’ultimo.

E ancora, quando la presenza di uno switch (o di un case del Pascal) fa esplodere il valore dell’indice, è necessario sostituire il costrutto con una implementazione che potrebbe apparire più complessa da realizzare, ad esempio creando un dizionario di associazione tra i valori dello switch e l’implementazione da eseguire, usando funzioni lambda o delegati, oppure sfruttando la programmazione a oggetti e in modo particolare il polimorfismo per delegare a ciascuna sottoclasse derivata la specifica implementazione dei singoli rami logici dello switch.

Conclusioni

Una delle domande che mi viene rivolta più frequentemente è questa: «Come faccio a scrivere codice manutenibile e soprattutto testabile. Ecco, non esiste specificatamente una qualità che attribuisce in automatico, a qualsiasi porzione di codice, la caratteristica di “testabilità” a prescindere: occorre impegnarsi ed esercitarsi nel tenere innanzitutto sotto controllo le metriche di tossicità del codice e applicare le metodologie adeguate, primi fra tutti i principi SOLID, per ridurla drasticamente equilibrando i fattori di modularità e separazione degli ambiti tra i vari moduli software, e a quel punto il codice apparirà manutenibile e testabile come per magia. 🧙

Sebbene esistano tantissimi prodotti, anche complessi e costosi, in grado di compiere analisi molto approfondite del codice, generando indici e report dettagliati rivolti ai soli esperti, l’obiettivo di questo articolo è quello di sottolineare che esistono anche strumenti e tecniche semplici da usare, globalmente diffusi e immediati nella comprensione che permettono allo sviluppatore di tenere sotto controllo la complessità del codice scritto con poco sforzo, indipendentemente dal proprio livello di esperienza.

E voi, quali sono le strategie e gli accessori che utilizzate per mantenere sano il vostro codice? 😉

Got Something To Say:

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *

*

Questo sito usa Akismet per ridurre lo spam. Scopri come i tuoi dati vengono elaborati.

Copyright © 2018. Powered by WordPress & Romangie Theme.