Un coding agent può scrivere molto codice in poco tempo. Questo, però, non significa che il codice sia corretto.
La frase “implementazione completata, il codice è pronto all’uso” non è una verifica. È solo una dichiarazione del modello. Per capire se possiamo fidarci del risultato servono prove che non dipendano dalla sua interpretazione.
La tecnica che mostro in questo video consiste nel mettere il coding agent dentro un ambiente controllato, con strumenti capaci di produrre risultati chiari: sì o no, verde o rosso, conforme o non conforme.
Il problema: il codice non basta
I modelli linguistici sono bravi a generare codice e a spiegare quello che hanno fatto. Possono anche fare supposizioni e presentarle come fatti.
Un coding agent può quindi:
- inventare dettagli che non ha verificato;
- dichiarare conclusa un’implementazione incompleta;
- leggere il codice e supporre che funzioni senza eseguirlo;
- spendere molti token per cercare una risposta quando potrebbe eseguire una verifica.
Non è un problema che si risolve chiedendo al modello di essere più sicuro di sé. Serve un meccanismo esterno che gli permetta di controllare il proprio lavoro.
I controlli deterministici
Un controllo deterministico restituisce un risultato che il coding agent può interpretare senza doverlo indovinare.
Un test automatico è un esempio semplice. Se il test passa, il risultato è verde. Se fallisce, il risultato è rosso. Il modello può leggere l’errore, correggere il codice e ripetere la verifica.
Lo stesso principio vale per una compilazione, un controllo di analisi statica, una regola di linting o un benchmark. Il coding agent non deve basarsi soltanto sulla propria lettura del codice: può usare strumenti che misurano il comportamento reale.
Questo approccio porta almeno tre vantaggi:
- Più controllo: il lavoro viene confrontato con regole e risultati osservabili.
- Più qualità: gli errori emergono durante l’implementazione, non solo alla fine.
- Meno costi: il modello non deve fare tanti giri di ragionamento per capire se è sulla strada giusta. Può eseguire un controllo, leggere il risultato e decidere il passo successivo.
Un esempio: da CSV a JSON
Nel video parto da un progetto C# vuoto, composto da un progetto applicativo e da un progetto di test.
L’obiettivo è realizzare una piccola utility da riga di comando che trasformi un file CSV in un file JSON. Il CSV contiene, tra gli altri dati, il titolo di un libro, l’autore e l’anno di pubblicazione. Il JSON atteso contiene una struttura books con queste stesse informazioni mappate nei campi corretti.
Il progetto contiene già due file reali:
demo.csv, il file di ingresso;demo.json, il risultato atteso.
Questi file sono importanti perché impediscono al coding agent di lavorare su un esempio astratto inventato da lui. Il prompt gli chiede di usarli in modo estensivo e di verificarli ogni volta che modifica il codice.
Il file CSV usa il punto e virgola come delimitatore. Anche questo dettaglio non viene dato per scontato: il coding agent deve leggerlo dal file e tenerne conto nella propria implementazione.
I test come guardrail
Dopo aver analizzato i file reali, il coding agent implementa il convertitore e aggiunge una serie di test automatici.
I test verificano il caso principale e alcuni casi più delicati:
- la conversione del file reale
demo.csvnel JSON atteso; - la presenza di punti e virgola all’interno del testo;
- la gestione delle virgolette e dei caratteri di escape;
- il rifiuto di un file malformato con un numero errato di colonne.
In questo modo il progetto non ha soltanto del codice che sembra funzionare. Ha un confine operativo esplicito. Finché i test sono verdi, sappiamo che il comportamento verificato è rispettato. Se un cambiamento rompe una regola, il test lo segnala subito.
I test non dimostrano che il programma sia corretto in ogni situazione possibile. Dimostrano però che le situazioni che abbiamo scelto di descrivere sono controllate. Possiamo quindi aggiungerne altre quando scopriamo nuovi requisiti o nuovi errori.
Dalla correttezza alle prestazioni
Una volta protetto il comportamento con i test, possiamo chiedere al coding agent di migliorare un altro aspetto: le prestazioni.
In questo caso entra in gioco BenchmarkDotNet, una piattaforma per misurare tempo di esecuzione, CPU e allocazioni di memoria del codice .NET.
Il benchmark crea una baseline, cioè una misura di riferimento dell’implementazione iniziale. Il coding agent può quindi provare a migliorare l’algoritmo usando numeri concreti, invece di decidere a sensazione. I test unitari continuano a controllare che l’ottimizzazione non cambi il comportamento del convertitore.
Nell’esempio mostrato nel video, l’implementazione ottimizzata passa da circa 26,4 millisecondi a circa 5 millisecondi su file di grandi dimensioni. È un’accelerazione di circa 4,75 volte. Le allocazioni di memoria diminuiscono di circa il 27 per cento.
Questi numeri descrivono quel benchmark e quel contesto. Non sono una garanzia per ogni programma o per ogni macchina. Sono però una base concreta per confrontare due versioni e capire se una modifica ha davvero migliorato il codice.
Progettare l’ambiente del coding agent
Il punto non è usare soltanto i test. Il punto è progettare un ambiente nel quale il coding agent abbia a disposizione più sensori e controlli deterministici.
Un ambiente di questo tipo può contenere:
- file reali che descrivono l’input e il risultato atteso;
- test unitari e test di integrazione;
- compilazione del progetto;
- regole di linting;
- analisi statica del codice;
- benchmark per tempo, CPU e memoria;
- hook che eseguono controlli durante o alla fine dell’implementazione.
Ogni strumento riduce lo spazio delle supposizioni. Il coding agent può eseguire un’azione, osservare il risultato e correggere il proprio percorso. Non lavora più soltanto in base a ciò che pensa di aver fatto.
La fiducia nasce dal feedback
Un coding agent affidabile non è quello che scrive più codice o che usa parole più convincenti. È quello che lavora dentro un sistema capace di dirgli, in modo rapido e ripetibile, se il risultato rispetta le regole.
La combinazione è semplice:
- definisci il comportamento atteso;
- rendilo verificabile con file reali e test;
- misura le prestazioni con una baseline;
- lascia che il coding agent esegua i controlli e reagisca ai risultati;
- aggiungi nuove verifiche quando impari qualcosa di nuovo.
Questo trasforma il coding agent da generatore di codice a componente di un ambiente di sviluppo controllato. La qualità non dipende soltanto dalle sue intenzioni o dalla sua capacità di spiegarsi: dipende dal feedback che riceve dal sistema.
Per approfondire il lavoro strutturato con i coding agent, in particolare con GitHub Copilot, trovi anche il mio corso su Udemy.