Due persone che guardano il codice software su uno schermo

Cos'è la qualità del codice?

Qualità del codice e come migliorarla

La qualità del codice si riferisce alla robustezza del codice, al di là del fatto che venga semplicemente eseguito e svolga la funzione desiderata. Il codice di alta qualità si differenzia per efficienza, manutenibilità, leggibilità e riusabilità, mentre il codice di bassa qualità è fragile, difficile da analizzare e incline ad accumulare debiti tecnici nel tempo.

Gli elevati standard di codifica sono per il processo di sviluppo del software ciò che la corretta mise en place e il "lavoro pulito" sono per il funzionamento di una cucina commerciale. Le pratiche che elevano la qualità del tuo codice possono offrire funzionalità migliori nel breve termine, ma i loro benefici più importanti sono meno problemi, progressi più rapidi e costi di manutenzione più bassi nel lungo termine.

I benefici a lungo termine di un codice di qualità superiore possono talvolta essere difficili da comunicare per i programmatori ai dirigenti meno esperti nelle minuzie del ciclo di vita dello sviluppo del software. Bilanciare i benefici olistici del codice ottimale con le pressioni immediate delle priorità aziendali spesso comporta compromessi complessi. Detto questo, uno studio del 2022 su 39 codebase di produzione proprietaria ha affermato, tra gli altri risultati,1 che: 

  • Il debito tecnico dovuto a codice affrettato fa sprecare fino al 42% del tempo degli sviluppatori.

  • Il codice di bassa qualità presenta 15 volte più difetti rispetto al codice di alta qualità.

  • Risolvere problemi in codice di bassa qualità richiede (in media) il 124% in più di tempo rispetto a risolvere problemi in codice di alta qualità.

Un codice di qualità superiore aumenta la facilità e la velocità di comprensione, refactoring, debug e aggiunta di nuove caratteristiche a una codebase. Un codice chiaro, coerente e ben scritto facilita un coordinamento più fluido tra i team di sviluppo e riduce la complessità e le complicazioni delle modifiche al codice. Favorisce non solo una qualità software solida, ma anche una solida esperienza per gli sviluppatori e l'esperienza utente.

Il semplice fatto che un codice compili e raggiunga il suo obiettivo durante il tempo di esecuzione non è sufficiente a valutarne la qualità generale. Scrivere codice non è come completare un cruciverba, in cui esiste un solo modo corretto per portare a termine il compito: spesso ci sono innumerevoli soluzioni a un dato problema di codifica. La funzionalità rappresenta quindi la mera conformità del codice a un livello accettabile. Il valore del codice di alta qualità si manifesta nei suoi effetti secondari sul contesto circostante.

Cosa definisce un'alta qualità del codice?

Il codice di alta qualità è un concetto relativamente astratto. La qualità complessiva di un pezzo di codice è definita tanto da come viene realizzato e da come interagisce con la base di codice più ampia in cui esiste, quanto da qualsiasi insieme specifico di metriche di qualità del codice discrete e oggettive (anche se molte di queste metriche esistono).

Le caratteristiche comuni del codice di alta qualità includono:

  • Leggibilità: la leggibilità del codice è essenziale per la manutenzione, il debug e il coordinamento tra team e tempo. Un altro membro del team può capire facilmente il tuo codice? Un altro programmatore, che lavorerà tra anni, può interpretare accuratamente il tuo codice senza che tu sia presente per fornire il contesto?

  • Manutenibilità: la complessità del codice è spesso inversamente proporzionale alla sua manutenibilità. Il tuo codice è facilmente testabile, permettendo al team di valutarlo in modo efficiente per vulnerabilità di sicurezza e opportunità di ottimizzazione? È abbastanza robusto da aggiungere nuove caratteristiche senza interrompere le funzionalità di base o è troppo fragile per essere adattato senza richiedere un importante refactoring? Dare priorità al codice mantenibile può comportare ulteriori complicazioni iniziali, ma fa risparmiare tempo ed energie significativi in futuro.

  • Efficienza: un codice ben scritto può ridurre la latenza e il consumo di risorse di un sistema. Ad esempio, strutture dati scelte con cura possono ridurre il numero di operazioni CPU richieste per una determinata funzione. Strategie di cache dati attente riducono le costose operazioni di input/out (I/O) eliminando query ridondanti del database e richieste di rete, mentre il rilascio tempestivo della memoria inutilizzata evita un uso eccessivo della RAM.

  • Affidabilità: meno difetti e strutture resistenti alle modifiche del codice significano meno frequenti guasti e tempi di inattività. L'affidabilità è essenziale per l'esperienza utente e la fiducia, così come per lo stato di salute dei sistemi critici su cui la tua azienda si basa.

Scrivendo su Harvard Data Science Review nel 2023, alcuni ricercatori di Calvin University, Amherst College e Columbia hanno proposto un framework per il buon codice: "Le quattro C".2

  • Correttezza: il codice fa quello che dovrebbe fare. Gli autori hanno sottolineato due corollari di questa ovvia inclusione: "In primo luogo, la correttezza è una metrica necessaria ma insufficiente per un buon codice. In secondo luogo, gli altri obiettivi sostengono e promuovono la correttezza."

  • Chiarezza: chiunque legga e scriva il codice può dire cosa è destinato a fare e apportare in modo intuitivo le modifiche necessarie.

  • Contenimento: evitare la dispersione incontrollata, la ridondanza e le dipendenze non necessarie. Un contenimento corretto comporta, tra le altre cose, "usare funzioni per contenere codice riutilizzabile e mantenere il codice utilizzato tra file o progetti in un modulo o pacchetto".

  • Coerenza: una base di codice dovrebbe mantenere la coerenza interna di stile, convenzioni di denominazione, commenti, indentazione e altre pratiche.

Poiché lo sviluppo software moderno continua a essere sempre più guidato da assistenti di agentic coding come IBM Bob, contenimento e coerenza sono particolarmente utili per massimizzare l'efficacia e la precisione degli strumenti automatizzati. Detto questo, la capacità di piattaforme di nuova generazione come IBM di identificare le opportunità di refactoring AI in tempo reale può ridurre lo sforzo necessario per applicare quel livello di disciplina stilistica.

Best practice per codice di alta qualità

Sebbene ogni linguaggio di programmazione e caso d'uso abbia le sue sfumature specifiche e considerazioni granulari, esistono alcune best practice universali per un codice di qualità in qualsiasi scenario.

Un modo per concettualizzare un'elevata qualità del codice è considerarlo semplicemente come codice che evita il più possibile i segnali di cattivo codice, che saranno esaminati più avanti in questo articolo.

Per un approccio più normativo, il già citato documento Harvard Data Science Review (HDSR) delinea una serie di linee guida per garantire la qualità del codice. Sebbene queste linee guida siano apparentemente ottimizzate per le esigenze dei data scientist, la maggior parte è applicabile in qualsiasi disciplina di codifica.

Scegli dei buoni nomi

Le forti convenzioni di denominazione sono essenziali per la leggibilità e la coerenza del codice. Gli autori suggeriscono le seguenti pratiche:

  • La lunghezza dei nomi deve essere proporzionale al loro scopo. Maggiore è la distanza – sia in termini di tempo, linee di codice o struttura organizzativa – tra la definizione iniziale e l'uso di un termine, più è essenziale che il suo nome ne comunichi chiaramente il ruolo.

  • Tieni un riepilogo delle abbreviazioni. I nomi di variabili brevi o addirittura composti da un solo carattere possono contribuire a semplificare il codice, ma possono anche risultare incomprensibili a chi ha meno familiarità con il progetto. Mantenere una sorta di "glossario" mitiga questo compromesso.

  • Utilizza le maiuscole e le minuscole in modo coerente. È inoltre consigliabile evitare i casi in cui due nomi si differenziano unicamente per la maiuscola o la minuscola.

  • Eviti i nomi non descrittivi. Aumentano significativamente la difficoltà dell'interpretazione del codice.

  • Scegli convenzioni di denominazione dei file che ne permettano un ordinamento naturale. Ad esempio, puoi adottare lo standard ISO 8601 per data e ora, oppure numeri di pad con 0 per assicurarti che abbiano tutti lo stesso numero di cifre.

Convenzioni di denominazione chiare e coerenti possono anche aiutare a semplificare l'azione di richiesta agli assistenti di codifica AI e ad aumentare la precisione del loro output. Ad esempio, invece di chiedere a un agente di ispezionare certi tipi di variabili o di esplorare tutti i file di un determinato intervallo di date – cosa che potrebbe richiedere al tuo agente AI di dedurre probabilisticamente dal contesto quali variabili o file soddisfano i criteri – puoi invitare esplicitamente un agente a esplorare tutti i file che iniziano con un numero specifico, o tutte le variabili con un nome specifico.

Segui una guida di stile in modo coerente

Oltre a codificare forti convenzioni di denominazione, una guida di stile completa dovrebbe idealmente standardizzare gli elementi di formattazione, inclusi l'uso di spazi bianchi e rientri, i commenti e i tipi di dati, così come i "dialetti di codifica". Su GitHub è possibile trovare un'ampia gamma di guide di stile collaudate per diversi linguaggi di programmazione, come quelle incluse in questo elenco accurato.

Una guida di stile è anche un riferimento prezioso per un assistente di codifica AI, fungendo da contesto per compiti specifici o persino come parte del prompt di sistema del tuo agente AI.

Seleziona un toolkit coerente e minimale (ma adeguato)

Sfruttare toolkit e librerie è un vantaggio naturale per la riutilizzabilità e l'efficienza del codice, aiutando a standardizzare i workflow e gli output tra i diversi team e ad accelerare in modo ampio la creazione del codice. Sono particolarmente utili quando il codice deve mediare le interazioni con sistemi complessi di terze parti o gestire problemi ripetitivi e "risolti".

Ma un eccessivo affidamento sui toolkit può aggiungere inutili ingombri e introdurre dipendenze esterne, riducendo la robustezza e la manutenibilità del codice. Inoltre, tendono ad astrarre la logica sottostante del codice, diminuendone la leggibilità. Gli autori dell'HDSR descrivono l'equilibrio ideale in termini semplici: "Vogliamo che il nostro toolkit sia il più semplice possibile, ma non più semplice di così".

Non ripeterti

Se ti capita spesso di copiare, incollare e modificare gli stessi blocchi di codice, potrebbe esserti utile una funzione che racchiuda il codice ripetuto in un unico punto. I parametri di questa funzione possono riflettere gli elementi che cambiano da un'istanza all'altra. Questo pulisce il codice e semplifica la manutenzione, in quanto consente di regolare tutte le istanze di quella funzione in un unico passaggio e in un unico luogo (anziché regolare individualmente ogni duplicato di un blocco di codice).

Impiega controlli di coerenza

I controlli di coerenza sono validazioni automatiche che verificano se i dati potenziali o gli stati di sistema rispettano regole e convenzioni logiche predefinite, aiutando a evitare e tenere conto di conflitti e contraddizioni imprevisti nel codice. Questi test automatizzati sono in genere una componente standard e critica delle pipeline CI/CD (integrazione continua/distribuzione continua).

Questo è un esempio perfetto dell'importanza della testabilità del codice. È difficile o impossibile progettare test unitari che convalidino in modo esaustivo ogni funzione se il codice è troppo complesso o contiene troppe dipendenze strettamente interconnesse.

Applica il controllo delle versioni

I sistemi di controllo delle versioni aiutano a promuovere la coerenza, il controllo della qualità, il coordinamento e i processi di recensioni del codice tra i team. Quando si utilizzano framework di codifica basati su AI – specialmente quelli che possono regolare autonomamente la tua codebase – assicurati di avere un modo per annullare facilmente eventuali cambiamenti indesiderati o negativi. IBM Bob, ad esempio, versiona automaticamente i file della tua area di lavoro come checkpoint per consentire un facile rollback delle modifiche al codice quando necessario.

Cosa definisce il codice errato?

In generale, il codice scadente è difficile da leggere e da mantenere, fragile alle modifiche e alle nuove caratteristiche, inefficiente e inaffidabile. Spesso presenta caratteristiche inutili, in cui moduli diversi sono intrecciati tra loro e ogni modifica a uno richiede un lavoro extra per evitare di rompere l'altro. Manca di documentazione adeguata ed è mal organizzato, privo di una struttura logica e coerente, una situazione spesso definita "codice spaghetti".

Il codice errato è spesso il prodotto non (solo) di scarse capacità di codifica, ma anche di incentivi e struttura organizzativa scadenti: dare priorità al lancio di caratteristiche in modo troppo aggressivo a scapito della qualità del codice in genere produce un time-to-market più rapido, ma maggiori complicazioni future e debito tecnico.

È importante ricordare che il codice sbagliato spesso funziona, almeno temporaneamente. Il debito tecnico non si accumulerebbe se non fosse così, perché il codice innegabilmente rotto dovrebbe essere risolto. Refactoring: Improving the Design of Existing Code, il libro fondamentale di Martin Fowler e Kent Beck pubblicato per la prima volta nel 1999 (e aggiornato molte volte da allora), utilizzava quindi il termine "code smells" (cattivi odori di codice) per descrivere il codice di scarsa qualità. Di solito non sono bug e non impediscono intrinsecamente il funzionamento di un programma, ma indicano debolezze di progettazione e problemi di qualità del codice che potrebbero rallentare lo sviluppo o causare bug in futuro.

L'elenco di Fowler e Beck dei cattivi odori di codice di cui diffidare comprende esempi come:

  • Funzione lunga (metodo lungo): un metodo contenente troppe righe di codice.

  • Classe grande: una classe che cerca di fare troppo e contiene troppe variabili, mancando di coesione.

  • Ossessione primitiva: utilizzare tipi di dati primitivi invece di piccoli oggetti specializzati.

  • Nome misterioso: funzioni o variabili denominate male, che nascondono il loro vero intento.

  • Aggregati di dati: gruppi di variabili che spesso appaiono insieme ovunque.

  • Elementi pigri: classi o funzioni che fanno troppo poco per esistere.

  • Elenco di parametri lungo: funzioni che richiedono troppi argomenti per funzionare correttamente.

  • Chirurgia a raffica: una modifica richiede la modifica simultanea di molti moduli sparsi (che è essenzialmente l'opposto di una classe grande).

  • Codice duplicato: strutture di codice identiche o molto simili in più punti.

Un elenco completo dei cattivi odori di codice, con spiegazioni, esempi e citazioni, è disponibile qui. La loro presenza è solitamente un segnale che indica la necessità di un refactoring. Una comprensione approfondita e a livello organizzativo di questi problemi e delle complicazioni che ne derivano è utile per stabilire una concezione condivisa degli standard di qualità tra i team di sviluppo.

Mixture of Experts | 12 dicembre, episodio 85

Decoding AI: Weekly News Roundup

Unisciti al nostro gruppo di livello mondiale di ingegneri, ricercatori, leader di prodotto e molti altri mentre si fanno strada nell'enorme quantità di informazioni sull'AI per darti le ultime notizie e gli ultimi insight sull'argomento.

Misurare la qualità del codice

La misurazione della qualità del codice dovrebbe sempre comportare una valutazione sia qualitativa che quantitativa. Sebbene le metriche oggettive come la complessità ciclomatica possano essere utili, possono anche essere fuorvianti senza un contesto adeguato.

Ad esempio, il tuo team potrebbe scrivere una suite di test automatizzata e il tuo codice potrebbe raggiungere una copertura del 100% del codice in una serie di test unitari. Ma se la suite di test manca di alcune delle asserzioni significative necessarie per convalidare sinceramente che il codice funzioni completamente secondo necessità, la falsa fiducia derivante da quella copertura di test potrebbe fare più male che bene.

Allo stesso modo, una struttura di revisioni robusta dovrebbe includere sia la revisione manuale del codice che la revisione del codice AI. Uno strumento di agentic coding moderno come IBM Bob può eseguire un'analisi statica del codice e un refactoring approfonditi in tempo reale, ma trae beneficio da regole personalizzate e modalità personalizzate che trasmettano le esigenze e le intenzioni specifiche dello sviluppatore. Gli esseri umani non sono esaustivi e l'AI non è infallibile, ma rafforzarsi l'uno con l'altro è il modo più sicuro per confermare che tutti i potenziali problemi siano stati indagati con il giusto contesto.

Ricorda sempre che la qualità del codice dipende dal contesto. Immagina che un programmatore del tuo team abbia scritto un algoritmo o un blocco di codice eloquente, efficiente e perfettamente articolato che raggiunge perfettamente la funzione prevista. Se il problema poteva essere risolto efficacemente usando una funzione standard di libreria integrata che tutti già conoscono, quel codice eloquente è in realtà un problema di qualità perché aggiunge complessità e sovraccarico mentale inutile.

Autore

Dave Bergmann

Senior Staff Writer, AI Models

IBM Think

Soluzioni correlate
IBM Bob

Accelera la distribuzione del software con Bob, il tuo partner AI per uno sviluppo sicuro e consapevole degli intenti.

Esplora IBM Bob
Soluzioni di codifica AI

Ottimizza le attività di sviluppo del software con strumenti affidabili basati su AI che riducono al minimo il tempo dedicato alla scrittura, al debug, al refactoring o al completamento del codice, lasciando più spazio all'innovazione.

Esplora le soluzioni di codifica AI
Consulenza e servizi sull'AI

Reinventa i workflow e le operazioni critiche aggiungendo l'AI per massimizzare le esperienze, il processo decisionale in tempo reale e il valore di business.

Esplora i servizi di consulenza per l'AI
Prossimi passi

Utilizza l'AI generativa e l'automazione avanzata per creare più velocemente codice enterprise-ready. I modelli di Bob ampliano le competenze degli sviluppatori, semplificando e automatizzando le attività di sviluppo e modernizzazione.

  1. Scopri IBM Bob
  2. Esplora le soluzioni di codifica AI
Note a piè di pagina

1. "Code red: the business impact of code quality – a quantitative study of 39 proprietary production codebases", Proceedings of the International Conference on Technical Debt (consultato tramite l'Association for Computing Machinery Digital Libtary), 16 agosto 2022

2. "Fostering Better Coding Practices for Data Scientists", Harvard Data Science Review, 27 luglio 2023