# Complessità Ciclomatica: Quando Refactorizzare il Tuo Codice

URL: https://whatshouldibuildnext.com/it/journal/complessita-ciclomatica-quando-refactorizzare-il-tuo-codice
Type: blog
Locale: it
Published: 2026-08-01
Updated: 2026-08-27

---

> La metrica che conta i percorsi eseguibili nel tuo codice. Alta complessità ciclomatica: più bug, più test, più fatica a modificare il codice esistente.

## Complessità Ciclomatica: Quando Refactorizzare il Tuo Codice

La **complessità ciclomatica** misura il numero di percorsi eseguibili indipendenti in una funzione. Se questa metrica supera 10, ogni modifica diventa una scommessa. Se supera 20, il codice è praticamente impossibile da testare in modo completo. Il numero non mente: è il primo indicatore da guardare quando devi decidere cosa refactorizzare prima di aggiungere una nuova funzionalità al tuo progetto. È una metrica che esiste dal 1976 e continua a essere rilevante perché descrive qualcosa di concreto: quante teste devi tenere in memoria mentre modifichi una funzione. Ignorarla significa scoprire il problema durante il debugging, non prima.

## Come si calcola (e perché è più semplice di quanto sembri)

Thomas J. McCabe definì la complessità ciclomatica nel 1976 partendo dalla teoria dei grafi. La formula originale è:

`CC = E - N + 2P`Dove E = archi del grafo di flusso, N = nodi, P = componenti connessi. Per una funzione singola senza casi particolari, P = 1, quindi CC = E - N + 2.

Nella pratica quotidiana, puoi dimenticartela. Il modo più rapido per calcolarlo manualmente: parti da 1 e aggiungi 1 per ogni punto di decisione. Ogni `if`, `else if`, `elif`, `for`, `while`, `case`, `&&`, `||`, `?` (ternario) e `catch` aggiunge 1 al conteggio. Ogni ramo logico aggiunge un percorso eseguibile che dovrà essere testato.

Esempio concreto in Python:

`def processa_ordine(ordine, utente, sconto=None):  # CC = 1
    if ordine.importo > 100:                        # +1 = 2
        if utente.premium:                          # +1 = 3
            sconto = 0.20
        else:
            sconto = 0.10
    if sconto:                                      # +1 = 4
        ordine.importo *= (1 - sconto)
    if ordine.pagamento == "carta":                 # +1 = 5
        if utente.carta_verificata:                 # +1 = 6
            return esegui_pagamento(ordine)
        else:
            raise PagamentoErrore("carta non verificata")
    return esegui_pagamento(ordine)
# CC finale: 6`Un CC di 6 è gestibile e non preoccupante. Il problema è che raramente le funzioni restano così. Aggiungici validazione dell'input, gestione di casi di errore, compatibilità con configurazioni diverse, e arrivi a 15 senza che nessun singolo commit abbia alzato un campanello d'allarme. Il debito si accumula inosservato, un `if` alla volta.

## Le soglie che contano davvero

La scala di McCabe è ancora quella usata dal settore come riferimento principale:

- 
**CC 1-10**: semplice, testabile senza sforzo particolare.

- 
**CC 11-20**: moderato, ogni percorso deve avere il suo test dedicato.

- 
**CC 21-50**: complesso, alto rischio di bug in produzione.

- 
**CC > 50**: non testabile completamente in modo pratico.

Queste soglie non sono dogmi. Un parser lessicale o un codice generato automaticamente può avere CC > 50 senza che sia un problema reale. Il contesto conta sempre. La categoria del codice, la sua frequenza di modifica e la copertura dei test sono variabili che modificano il rischio effettivo.

La soglia pratica per un codebase applicativo standard: **> 10 è un segnale**, **> 15 è un candidato prioritario per il refactoring**.

Molti team usano 10 come hard limit nel Quality Gate delle PR: nessuna funzione con CC > 10 entra nel codice principale senza revisione esplicita. È un approccio pratico che previene l'accumulo silenzioso di complessità nel codebase.

![Grafico che mostra la relazione tra complessità ciclomatica e densità di bug nel codice sorgente](https://fdzlnqpwsaniezitwiuw.supabase.co/storage/v1/object/public/cms-media/whatshouldibuildnext/2026-08/aec123-inline1.webp)

## Perché alta complessità si traduce in bug reali

Ogni percorso logico è un percorso che deve essere coperto dai test. Con CC = 15, hai almeno 15 test distinti da scrivere per coprire tutti i rami in modo completo. In pratica, le suite di test raramente raggiungono quella copertura su funzioni complesse: i test vengono scritti per i casi ovvi, non per le combinazioni di stato più improbabili.

Lo studio originale di [McCabe sul controllo del flusso nel software](https://ieeexplore.ieee.org/document/1702388) mostra una correlazione diretta tra CC alto e densità di difetti. Analisi successive su codebase open source confermano che le funzioni con CC > 15 mostrano una frequenza di bug 2-3 volte superiore rispetto a quelle con CC < 10.

Il meccanismo è matematicamente preciso: le combinazioni di stato crescono in modo esponenziale, non lineare. Con 10 condizioni booleane indipendenti, non sei a 10 percorsi possibili, sei potenzialmente a 1024 combinazioni di stato. Ogni combinazione è una possibilità di comportamento inatteso in produzione.

In un codebase con alta complessità media, i bug tendono a concentrarsi in specifici hotspot. Identificarli e refactorizzarli prima di aggiungere nuove funzionalità riduce il rischio di regressioni e accorcia i cicli di debugging. Un team che riduce la complessità media dei suoi moduli da 18 a 9 spesso osserva una riduzione proporzionale del tempo dedicato al debugging nelle settimane successive.

## Quando refactorizzare e quando accettare il debito tecnico consapevolmente

Non tutto il codice ad alta complessità va refactorizzato subito. Le risorse sono limitate e ogni refactoring ha un costo reale: tempo di sviluppo, rischio di regressioni, costo del testing successivo. Le domande che aiutano a prioritizzare:

**1. Il modulo viene modificato spesso?**
Un modulo con CC = 20 che non tocchi da 18 mesi ha un rischio reale quasi nullo. Un modulo con CC = 12 che modifichi ogni sprint è il candidato prioritario per il refactoring. La frequenza di modifica trasforma la complessità statica in rischio dinamico concreto.

**2. Il codice è coperto da test?**
Alta complessità senza copertura di test è la combinazione più pericolosa. Alta complessità con test completi è un rischio gestito, anche se con fatica. Prima di refactorizzare, scrivi i test che mancano: ti serviranno come rete di sicurezza durante la riscrittura.

**3. Quanti dev ci lavorano in parallelo?**
Se è il codice su cui lavorano più persone in parallelo, il refactoring ha un ROI chiaro e immediato: riduce i conflitti di merge e i bug di integrazione. Se lo tocchi solo tu ogni sei mesi, il costo del refactoring potrebbe superare il beneficio a breve termine.

**4. La funzione fa parte del percorso critico?**
Le funzioni nel percorso critico dell'applicazione o nel flusso di pagamento meritano attenzione particolare, indipendentemente dal CC. Un bug lì ha conseguenze proporzionalmente maggiori rispetto a una funzione di utilità usata raramente.

La regola del pollice che si rivela utile nella pratica: **refactorizza quando il costo di capire la funzione supera il costo di riscriverla**. Quando devi rileggere una funzione tre volte prima di capire dove intervenire, il refactoring ha già ripagato il suo costo in termini di tempo di debugging futuro evitato.

## Come CodeScene usa la complessità per prevedere i rischi del codebase

CodeScene aggiunge una dimensione che SonarQube da solo non ha: l'asse temporale. Non guarda solo quanto è complessa una funzione oggi, ma con quale frequenza viene modificata nel repository git nel tempo.

Il concetto chiave è l'**hotspot**: un file o una funzione con alta complessità E alta frequenza di modifica. Questi sono i punti del codebase dove si concentra la maggior parte dei bug e dove il dev perde più tempo per ogni modifica aggiunta.

In un progetto tipico, il 5-10% dei file contiene il 60-80% dei difetti. La mappa degli hotspot mostra esattamente quali sono, senza doverti fidare dell'intuizione del membro più anziano del team. Questo è utile soprattutto nei codebase grandi, dove l'esperienza personale copre solo una frazione del codice effettivo.

CodeScene fornisce anche la metrica di "health" per team: identifica i file dove più dev lavorano in parallelo su codice complesso, un segnale di coordinamento difficile. Questi sono i punti dove i bug di integrazione sono statisticamente più probabili. La combinazione di alta complessità e alto accoppiamento tra contributi è il pattern più predittivo di incidenti in produzione su codebase maturi.

![Mappa degli hotspot del codice sorgente che evidenzia le aree a rischio nel repository](https://fdzlnqpwsaniezitwiuw.supabase.co/storage/v1/object/public/cms-media/whatshouldibuildnext/2026-08/cf7628-inline2.webp)

## Refactoring pratico: le tecniche per ridurre la complessità ciclomatica

Le tecniche più efficaci, in ordine di impatto e facilità di applicazione sicura:

**Estrazione di funzioni**
Il modo più diretto e sicuro. Prendi un blocco con logica autonoma e spostalo in una funzione separata con un nome descrittivo. La funzione padre diventa più leggibile, quella estratta ha il suo CC isolato e testabile separatamente. Ogni estrazione riduce il CC della funzione originale del numero di rami estratti.

`# Prima: CC = 8
def calcola_sconto(ordine, utente):
    if utente.premium and ordine.importo > 200:
        if ordine.categoria == "tech":
            return 0.25
        return 0.20
    elif utente.gold and ordine.importo > 100:
        return 0.15
    elif ordine.primo_ordine:
        return 0.10
    return 0

# Dopo: due funzioni con CC <= 4 ciascuna
def sconto_premium(ordine):
    return 0.25 if ordine.categoria == "tech" else 0.20

def calcola_sconto(ordine, utente):
    if utente.premium and ordine.importo > 200:
        return sconto_premium(ordine)
    if utente.gold and ordine.importo > 100:
        return 0.15
    if ordine.primo_ordine:
        return 0.10
    return 0`**Tabelle di decisione al posto di catene if/elif**
Quando hai molti rami su una variabile con valori enumerabili, sostituiscili con un dizionario. Il CC scende a 1, la logica diventa dichiarativa e il testo si legge come una specifica.

**Guard clauses per l'early return**
Invece di annidare gli `if`, ritorna presto quando la condizione non è soddisfatta. Ogni early return elimina un livello di nidificazione.

`# Invece di annidare:
def valida_utente(utente):
    if utente:
        if utente.attivo:
            if utente.email_verificata:
                return True
    return False

# Early return:
def valida_utente(utente):
    if not utente:
        return False
    if not utente.attivo:
        return False
    return utente.email_verificata`La stessa logica, stesso CC finale, ma la versione con guard clauses si legge linearmente dall'alto verso il basso senza dover tracciare mentalmente i livelli di nidificazione.

## Gli strumenti che integrano la complessità ciclomatica nel workflow di sviluppo

Tre soluzioni usate in produzione con caratteristiche distinte per contesti diversi:

**SonarQube** è lo standard per i team aziendali e per i progetti open source. Offre analisi statica su ogni PR, soglie configurabili nel Quality Gate, dashboard centralizzata e storico delle metriche nel tempo. La versione Community è gratuita per i repository pubblici e locali. Supporta oltre 25 linguaggi inclusi Java, Python, JavaScript, TypeScript, Go, C#, Ruby e Kotlin.

**CodeScene** combina la complessità con la storia git per identificare gli hotspot reali nel codebase. È la scelta per i team che vogliono prioritizzare il debito tecnico in modo oggettivo invece di basarsi sull'intuizione del singolo sviluppatore. La visualizzazione degli hotspot rende immediato dove concentrare il refactoring nelle prossime settimane.

**CodeClimate Quality** si integra direttamente nei workflow GitHub e GitLab senza infrastruttura aggiuntiva da gestire. Ogni PR riceve un punteggio di maintainability, con il CC come uno dei fattori principali. È la scelta per i team che vogliono feedback automatico su ogni contributo al codice senza dover mantenere un server SonarQube dedicato. Il piano gratuito copre i repository open source.

## Come usare questa metrica per decidere cosa buildare o refactorizzare prima

Se stai valutando se aggiungere una nuova funzionalità o dedicare uno sprint al refactoring, la complessità ciclomatica ti offre un criterio misurabile invece di un'opinione soggettiva.

La regola pratica che si rivela utile: se i moduli dove devi lavorare hanno CC medio > 12, il tempo di sviluppo della nuova funzionalità aumenta di un fattore 1.5-2 rispetto a un codebase con complessità bassa. Non è un'intuizione, è misurabile confrontando la velocity del team su moduli ad alta e bassa complessità nel tempo. Tieni un registro, i dati ti convincono più dell'intuizione.

Il check prima di ogni sprint: apri SonarQube o CodeClimate sulla sezione che stai per toccare. Se vedi punteggi alti, la conversazione diventa esplicita: "refactorizziamo questo sprint o accettiamo consciamente il debito?" Accettare il debito tecnico è legittimo quando hai dati per giustificarlo. Non vederlo non è un'opzione che ti conviene.

Anche su un side project da soli, la metrica vale. Un CC > 15 su un modulo che devi estendere è un segnale concreto da considerare prima di aggiungere la prossima feature. Il codebase lavora per te o contro di te: questa metrica ti dice la risposta prima che lo scopri in modo più costoso durante un debugging alle 23 di un martedì.

## FAQ

### La complessità ciclomatica si applica a tutti i linguaggi di programmazione?

Sì. Il concetto è indipendente dal linguaggio. SonarQube, CodeScene e CodeClimate la calcolano per Java, Python, JavaScript, TypeScript, Go, C#, Ruby, Kotlin e altri. La formula varia leggermente in base a come il linguaggio gestisce le eccezioni, ma la scala di interpretazione è la stessa in tutti i contesti.

### Qual è la differenza tra complessità ciclomatica e complessità cognitiva?

La complessità ciclomatica misura i percorsi eseguibili indipendenti: è una metrica strutturale oggettiva. La complessità cognitiva, introdotta da SonarSource, misura quanto è difficile capire il codice leggendolo, penalizzando l'annidamento profondo più della struttura lineare. Si completano: usa la prima per valutare la testabilità, la seconda per la leggibilità e la manutenibilità percepita.

### Un punteggio CC di 1 è sempre l'obiettivo ideale?

Non necessariamente. Una funzione con CC = 1 che fa troppe cose è comunque problematica: viola il principio di responsabilità singola e diventa difficile da modificare. Il CC misura la complessità interna della funzione, non se la funzione è ben progettata rispetto al sistema. Una funzione con CC = 6 ben strutturata è spesso più sana di una con CC = 1 che contiene logica mista e accoppiamenti nascosti.

### Come si configura SonarQube per bloccare PR con complessità ciclomatica troppo alta?

Nel Quality Gate, aggiungi la condizione 'Cyclomatic Complexity on New Code > [soglia]'. La soglia raccomandata come punto di partenza è 10. Le PR che introducono codice sopra quella soglia falliscono automaticamente il gate e richiedono revisione o refactoring prima del merge nel ramo principale.

### Quanto tempo serve per abbassare la complessità ciclomatica di un codebase legacy?

Dipende dalla profondità del debito accumulato e dalla dimensione del codebase. Un approccio realistico: dedica il 20-30% di ogni sprint al refactoring, concentrandoti sugli hotspot, cioè i moduli con CC alto e frequenza di modifica alta. Con questo ritmo, risultati visibili in 2-3 mesi su un codebase di dimensioni medie. Non cercare di abbassare tutto in un solo sprint: il rischio di regressioni è alto.

### La complessità ciclomatica influisce sulle performance dell'applicazione?

Direttamente quasi mai. Influisce sul numero di test necessari, sulla velocità di sviluppo futuro e sulla frequenza di bug. Le performance dipendono da altri fattori come la complessità algoritmica (notazione O) e gli accessi I/O. Una funzione con CC = 20 può essere velocissima in esecuzione, ma sarà difficile da testare, da modificare e da debuggare quando qualcosa va storto.

### Ha senso misurare la complessità ciclomatica su un progetto personale o un side project?

Sì. Anche da soli, il CC ti aiuta a identificare le parti del codice che ti rallenteranno nelle prossime sessioni di build. Un CC > 15 su un modulo che devi estendere è un segnale concreto: considera se è più conveniente refactorizzare prima di aggiungere la prossima feature. Non serve un team grande per beneficiare di questa metrica, serve solo la volontà di prendere decisioni consapevoli sul debito tecnico.