Esistono molte metriche che possono indicare un tipo di qualità del codice o aspetti di leggibilità, ma alla fine non contano. Ciò che importa è che il pubblico previsto del codice (ad esempio gli altri umani) può capire facilmente il codice. Un pubblico diverso ha diversi livelli di abilità, background diversi e aspettative diverse, quindi non esiste uno stile che possa soddisfarli tutti.
Questo non significa che le metriche siano inutili, solo che dovremmo essere consapevoli di come sono solo proxy per la leggibilità reale. Un classico esempio è la complessità ciclomatica (CC), che conta i rami in una funzione. Quali sono i vari problemi con CC?
- In caso di un'istruzione switch / case, CC è uguale al numero di casi, come se fosse scritto come una cascata if / else-if / else. Tuttavia, gli umani tendono a percepire un interruttore / caso molto più semplice.
- Inoltre, CC non può realmente tenere conto del flusso delle eccezioni, poiché ogni sottoespressione che potrebbe generare è effettivamente un punto di diramazione. Tuttavia, molte persone percepiscono le eccezioni in modo molto più semplice di un condizionale per ogni operazione che potrebbe fallire, e le eccezioni sono tipicamente ignorate quando si calcola CC (ma come si dovrebbe considerare try / catch?)
- Ci sono anche alcuni operatori di flusso di controllo che spesso non sono percepiti come flusso di controllo, come gli operatori di cortocircuito come in
if (a && b)
, o operatori di navigazione sicuri come foo.?bar
(ad es. in C #).
- Alcuni flussi di controllo possono essere nascosti da funzioni di ordine superiore, ad es. confronta i loop
for x in things: foo(x)
con il% equivalente in% di co_de.
Esistono metriche che tentano di risolvere alcuni di questi problemi, ad es. Cognitive Complexity di SonarQube .
Gli strumenti di analisi statica, come i linters e i controller di stile, utilizzano varie metriche per avvisarti di eventuali problemi. Possono operare su un livello puramente sintattico (ad esempio, pycodestyle), altri eseguono analisi semantiche (ad esempio findbugs opera su bytecode Java compilato, non sul codice sorgente). Molti eseguono una combinazione, ad es. operare su una rappresentazione analizzata del codice sorgente. Per le lingue dinamiche, i linters potrebbero anche eseguire una certa quantità di controllo dei tipi. Un correttore di stili potrebbe essere in grado di abbinare la tua fonte a modelli conosciuti di quelli che possono essere sostituiti con un'alternativa più elegante o quando il pattern è probabilmente un bug.
Nel lavoro di sviluppo che sto facendo attualmente (Python), trovo i seguenti assegni o metriche più utili:
- un controllo di stile di base che applica formattazione e denominazione coerenti (flake8)
- semplici controlli semantici, come lamentarsi quando una variabile viene assegnata ma non utilizzata, o quando chiamo una funzione che non esiste (flake8, pylint)
- un controllo di tipo esterno (mypy)
- semplici metriche di copertura del test (copertura delle dichiarazioni) (pytest-cov)
Nessuno di questi ha messo un numero su quanto è buono il mio codice, ma mi aiutano a trovare e prevenire i problemi. Esistono strumenti simili disponibili gratuitamente per Java, ad es. checkstyle. Questi strumenti tipicamente definiscono le politiche e non le metriche, ma un criterio potrebbe essere che una metrica dovrebbe essere all'interno di un determinato limite (ad esempio meno di 20 variabili locali nell'ambito).
Vale la pena leggere la documentazione di alcuni di questi strumenti per vedere quali aspetti della leggibilità cercano di misurare o quali problemi cercano di rilevare.