#Blog

I pattern sono nati per gli umani

La mia opinione sincera sull'esperimento di Dan Luu sul testing agentico

01/10/2026

Per garantire una maggiore leggibilità, i post del blog rispecchiano il font di default impostato dal sistema, anziché il comune Press2Start presente nel resto del sito.

🇬🇧 Are you looking for the english version? Click here

Disclaimer.

Da anni scrivo i miei articoli prima in inglese e solo dopo li traduco in italiano. Di conseguenza reputo la versione inglese di questo articolo molto più chiara e comprensibile e suggerisco a chi si senta a proprio agio con la lingua di leggerlo nella lingua nella quale è stato redatto qui.

Introduzione

Un paio di settimane fa ho letto l’ultimo esperimento di Dan Luu, e mi ha dato dei numeri su qualcosa a cui penso da un po’.

La domanda che si pone è circoscritta. Cosa succede quando qualcuno senza competenze di testing, che ha sentito dire che bisogna usare il TDD o il property-based testing, dice a un agente di farlo? Ha fatto implementare ad alcuni agenti un decoder Zstd in Rust, ha valutato i risultati con test nascosti e ha eseguito lo stesso compito con 26 istruzioni diverse, dal TDD e dal fuzzing a TLA+ e Lean 4, più quattro skill. Una delle condizioni, Default, non conteneva alcuna istruzione di testing. È arrivata ben sopra la media.

I dettagli sono peggiori del titolo. Quando nomini una tecnica, gli agenti continuano per lo più a scrivere i test che avrebbero scritto comunque, travestiti con il framework che hai chiesto. Con il TDD hanno scritto in anticipo tanti piccoli test facili da far passare, e si sono lasciati sfuggire i bug sottili. Con gli strumenti formali hanno dimostrato proprietà che non c’entravano nulla con i test che fallivano. In un caso gli agenti hanno usato un SMT solver (ammetto di aver dovuto controllare cosa fosse) per dimostrare cose su un calcolo, e hanno comunque scritto | dove serviva +. Con il fuzzing e il property-based testing hanno per lo più verificato che un input malformato non mandi in panic il programma. Quando gli si chiedeva il differential testing, implementavano la cosa due volte allo stesso modo e mettevano lo stesso bug in entrambe le copie.

Le skill non hanno salvato la situazione. Quelle che un agente ha trovato quando gli è stato chiesto di cercare buone skill di testing erano lunghe e si leggevano come tutorial. La skill ufficiale di Hegel ha reso le run fino al 41% più costose e non più corrette. Il risultato migliore è arrivato da una skill che Luu ha scritto da sé in un paio di minuti. Sono cinque righe: individua le aree che probabilmente nascondono bug sottili prima di implementare, scegli controlli su entrambi i lati di un confine, rideriva i risultati rischiosi in un contesto nuovo, e smetti di sprecare sforzo su input casuali che dimostrano solo che nulla va in crash.

È facile leggerlo come “scrivete skill brevi”. Credo che così si perda quello che è successo, e credo che Luu sarebbe d’accordo. La sua skill non spiegava il testing a chi non ha mai testato. Somiglia di più al collega che si è già scottato con questo tipo di codice e, mentre lavori, si china sulla tua spalla per dirti dove di solito morde. Lo dice anche più avanti: ciò che funziona per lui è dedicare qualche minuto alla struttura di Zstd e dare indicazioni specifiche su Zstd, e non vuole affatto una skill di test generica. La brevità è un effetto collaterale del fatto che la skill sa di cosa sta parlando e si rivolge al divario tra ciò che l’agente fa di default e ciò che serve a questo lavoro.

Due avvertenze oneste prima di costruirci sopra. Luu stesso definisce la sua skill una prima bozza che non ha funzionato come previsto, dato che il passo del contesto nuovo non è quasi mai avvenuto. Avverte anche che persino 160 run per condizione sono rumorose, e che i numeri in cima fuorviano se non si legge cosa hanno fatto davvero gli agenti. Lo considero quindi l’esperimento di una persona attenta, e capita che coincida con quello che vedo ogni giorno.

Il rituale senza il motivo

Il fallimento descritto da Luu ha una forma precisa: l’agente esegue la parte visibile di una tecnica e salta la parte che le dà valore. Il caso più chiaro è rstest, una libreria Rust che esiste per rendere facili i casi di test parametrizzati. Gli agenti l’hanno importata, ci hanno scritto dentro i test e non hanno mai usato la parametrizzazione, cioè l’unica cosa che rende rstest utile. Col property-based testing hanno trovato una proprietà banale e ci hanno fatto girare contro input casuali. Sulla carta la tecnica è stata applicata ogni volta.

Niente di tutto questo dovrebbe sorprendere chi ha lavorato in una codebase con una soglia di coverage. Ne avevo già scritto nel 2024 con un esempio volutamente sciocco: una funzione sum(a, b) e quattro test che sommano piccoli interi positivi. Ottieni il 100% di coverage e una pipeline verde, e nessuno si è chiesto cosa succede con '2', null o undefined. La coverage è la parte del testing che si vede. Il valore sta nei casi limite a cui qualcuno si è dovuto sedere a pensare, e il numero non può dirti se qualcuno l’ha fatto.

Yossi Kreinin ha lasciato un commento al pezzo di Luu a cui continuo a tornare. Lo stato del testing del software là fuori è pessimo, quindi quando gli agenti ripiegano su ciò che hanno imparato dobbiamo aspettarci risultati scarsi. E ciò che hanno imparato eravamo noi. Milioni di repository in cui “facciamo TDD” voleva dire “c’è una cartella tests”, e il modello ha copiato l’abitudine alla lettera.

Quindi non leggo l’esperimento come se gli agenti fossero scarsi nel testing in un modo nuovo. Lo sono in un modo molto umano, quello di un team che adotta un metodo perché lo ha detto un talk a una conferenza e non si chiede mai quale problema il metodo risolvesse. Ciò che è cambiato è la velocità: un team impiega mesi a trasformare il TDD in un rituale, un agente lo fa prima del primo commit.

Fatti per gli umani

Verso la fine del pezzo Luu fa un’osservazione che secondo me regge tutto l’argomento. Ogni skill che ha provato, a parte la sua, era scritta come le istruzioni di un tutorial per un umano: il suo scopo era spiegare come fare qualcosa. Il modello sa già come farlo, almeno in teoria. Ha letto sul property-based testing più di quanto abbia fatto qualunque di noi. Ciò che gli serve, per usare le sue parole, sono affermazioni che modifichino il suo comportamento di default, mentre un tutorial per lo più gli aggiunge testo da leggere e ignorare.

A luglio ho scritto su LinkedIn che i framework non sono mai serviti a scrivere codice, servivano a risparmiare fatica umana. Convenzioni condivise perché un nuovo assunto capisca il progetto in un giorno, un ecosistema perché nessuno riscriva da zero l’autenticazione, un nome come React che mille sviluppatori possono mettere nel CV. Nessuno di questi vantaggi è tecnico. Sono costi umani, pagati in anticipo.

Penso che lo stesso valga per la maggior parte dei pattern e dei metodi con cui siamo stati formati, e i risultati di Luu mostrano che aspetto ha dimenticarlo. Il TDD tiene un problema abbastanza piccolo da stare nella testa di una persona un passo alla volta, e rende sopportabile la paura di rompere qualcosa. I design pattern ci danno un vocabolario condiviso, così che dire “questo è un Observer” in una review fa risparmiare dieci minuti tra due persone che sanno entrambe cosa significhi. Le convenzioni permettono a una persona di intuire dove si trova un pezzo di codice senza chiedere. Sono strumenti modellati sulla nostra memoria, sulla nostra attenzione e sui nostri nervi, e funzionano benissimo proprio per quello.

Un agente non ha quei limiti nella stessa forma. Ne ha altri: va alla deriva, è troppo compiaciuto del proprio lavoro, applica la forma di un’istruzione e perde l’intento. Le cinque righe di Luu puntavano a quelli.

Questo non significa buttare via i metodi, e voglio essere preciso, perché ho passato gran parte della carriera a schierarmi contro il dogma e “niente dogmi” si fraintende facilmente come “niente metodo”. Lavorare senza dogmi significa comunque lavorare con dei criteri. In What Sits and What Fits ho scritto che le regole danno struttura e che il mestiere sta nel sapere quando il contesto deve prevalere su di esse. Questo non è cambiato. È cambiato che uno degli elementi del contesto adesso è il lettore. Luu ha potuto scrivere la sua skill solo perché conosce il fuzzing e il property-based testing abbastanza da sapere come falliscono, quindi conoscere i metodi è ciò che ti permette di dare a un agente qualcosa di meglio dei loro nomi. E alcuni restano per gli umani che sono ancora nel ciclo: il TDD come modo per una persona di fissare cosa significhi un requisito prima che qualcuno scriva codice, i pattern come il linguaggio che usiamo quando discutiamo un design e non quando lo digitiamo.

Cosa mettere nelle istruzioni al loro posto

Se il nome di una tecnica non porta con sé il suo scopo, lo scopo deve entrare nelle istruzioni in un altro modo. Quello che scrivo oggi per gli agenti c’entra pochissimo con le librerie. Per lo più è ciò che so del dominio e dei suoi punti fragili: quali calcoli hanno una legge dietro, quali toccano denaro, quale import ha già prodotto duplicati. Sempre più spesso è anche ciò che deve essere vero a lavoro finito, scritto come una frase contro cui il risultato si possa verificare. Le ho chiamate prompted gate in In un mondo di proprietà emergenti e non ripercorrerò l’argomento. “L’importer non deve mai creare un cliente duplicato, qualunque sia il file” resta l’esempio che sceglierei.

Un caso concreto del nostro setup mostra cosa intendo per specifico. Ponytail è una skill pubblica che trasforma l’agente in “uno sviluppatore senior pigro”. Chiede se il codice debba esistere, se qualcosa nella codebase lo fa già, se la libreria standard lo copre, se può stare in una riga. È una buona skill, ed è costruita per tutto: scrivere, rifattorizzare, fare review, progettare, scegliere dipendenze, con livelli di intensità, un formato di output e l’istruzione di restare attiva a ogni risposta. È la forma generica e tuttofare contro cui mettono in guardia i numeri di Luu.

Noi non l’abbiamo installata così com’era. L’abbiamo letta con una domanda in mente: cosa c’è qui dentro che rende più facile da rivedere il codice che arriva in review? La review è dove sta il nostro collo di bottiglia, e ne ho scritto più di una volta, quindi era l’unica domanda che contava per noi. Abbiamo tenuto un paio delle sue regole, un paio di pioli della sua scala, e buona parte della sezione su quando non essere pigri, l’elenco delle cose che non si semplificano mai. Quello che riguardava lo stile di scrittura, o un pattern fine a se stesso, è rimasto fuori. Poi abbiamo collegato ciò che avevamo tenuto a due agenti del nostro harness: l’executor, che scrive il codice, e il test writer. Ognuno riceve la parte che riguarda il proprio lavoro e nient’altro.

Quello che lo fa funzionare per noi c’entra poco con la brevità. Codifica ciò che vogliamo vedere in una pull request, nella nostra codebase, per i nostri reviewer. Un team con un collo di bottiglia diverso taglierebbe la stessa skill in un punto diverso, ed è giusto così. È questo che intendo quando dico che le skill vanno scritte come esperti di dominio.

Pensare da product engineer

Nel 2025 ho scritto un breve pezzo intitolato Resta nello spazio del problema. L’esempio centrale era una richiesta di prodotto: “ci serve qui un pulsante che invii una notifica”. La mia lamentela era che si tratta di una soluzione presentata come problema. Il problema vero è “gli utenti non si accorgono quando avvengono cambiamenti importanti”, e un ingegnere a cui arriva questa frase al posto del pulsante potrebbe trovare qualcosa di meglio di un pulsante.

Leggendo Luu mi sono accorto che “usa il TDD” è il nostro pulsante. Con un agente noi siamo il team di prodotto e l’agente è l’ingegnere, e continuiamo a consegnargli soluzioni presentate come problemi. Lui fa allora ciò che gli ingegneri hanno sempre fatto davanti a una richiesta di pulsante senza spiegazioni: costruisce il pulsante, in modo pulito, e nessuno controlla se adesso gli utenti si accorgono di qualcosa.

In quel pezzo ho scritto che il passaggio da software engineer a product engineer sarebbe contato di più in un mondo guidato dall’AI. Lo penso ancora, anche se per una ragione un po’ diversa da quella che avevo in mente. Pensavo che la sensibilità di prodotto sarebbe contata perché gli ingegneri lavorano più vicini al business. Conta perché, davanti a un agente, l’ingegnere è chi deve formulare il problema. Quindi le domande che funzionano sono quelle che si fa un product engineer: cosa deve succedere, per chi, e come me ne accorgerei se non succedesse. Per un decoder Zstd, “non deve mai restituire byte sbagliati in silenzio, e questi sono i punti in cui di solito lo fa” dice all’agente cosa testare molto più del nome di qualunque tecnica. “Come me ne accorgerei se non succedesse” è anche ciò per cui serviva un test, molto prima che iniziassimo a contarli.

La parte che a nessuno piace

C’è un’altra conseguenza, ed è quella su cui mi aspetto più obiezioni. Se i pattern, le convenzioni e le regole di leggibilità esistono in gran parte per l’umano che legge il codice, allora non è ovvio che in futuro leggeremo ogni riga, né che dovremmo preoccuparci di farlo.

La prima metà l’ho raccontata in Costruire loop, quindi sarò breve. A febbraio sostenevo di verificare ogni riga prodotta da un agente, e ad agosto ho dovuto ammettere che al volume di oggi una lettura completa sarebbe una review finta. Non ho smesso del tutto di leggere, e sarebbe disonesto dire il contrario. Quello che mi sto allenando a fare è prima una review funzionale, e poi uno sguardo alle parti critiche, quando serve. Chiudere una review senza aver scorso il diff mi dà ancora la sensazione di uscire di casa senza aver controllato il gas.

La seconda metà, “né che dovremmo preoccuparci”, è la parte nuova per me. Nel post di luglio facevo notare che ci siamo già passati una volta. Quando siamo passati ai linguaggi di alto livello abbiamo smesso di chiederci cosa succede sotto il cofano, e oggi nessuno si sente in colpa per non sapere come il compilatore alloca i registri. La conoscenza non è sparita. È diventata qualcosa di cui si occupa qualcun altro al posto nostro, e la nostra attenzione è salita di un livello. Penso che buona parte di ciò che chiamiamo qualità del codice si stia muovendo nella stessa direzione, comprese alcune regole di leggibilità che difendo da dieci anni, che presuppongono tutte che chi manutiene sia una persona. Alcune sopravviveranno, perché qualcuno aprirà ancora quel file in una brutta giornata e avrà bisogno di capirlo, ma non mi aspetto più che sopravvivano tutte.

Preoccuparsi meno di ogni riga non significa preoccuparsi meno che il codice funzioni, ed è qui che voglio essere attento. Il controllo si sposta altrove. Sale, verso le decisioni prese prima che l’agente parta, scritte dove l’agente può leggerle. E si sposta fuori, verso ciò che il codice deve garantire, espresso in una forma verificabile. Leggere è stato il mio principale modo di controllare il codice per gran parte della carriera, e sta diventando costoso mentre gli altri modi diventano economici. Quello che mi preoccupa è un team in cui l’AI scrive, l’AI controlla e nessuno ha deciso niente nel mezzo. Leggere più righe non risolverebbe quel team.

Ma Mike, gli LLM non sono deterministici!

Qualcuno lo sta già scrivendo nei commenti, quindi arrivo prima io. Vero: fai la stessa domanda allo stesso modello due volte e puoi ottenere due risposte. Ora guardiamo le persone. Chiunque faccia code review da qualche anno ha visto lo stesso reviewer approvare un pattern il martedì e bocciarlo il giovedì, con totale convinzione in entrambi i casi, oppure ha visto il proprio codice rivisto in modo diverso alle 10 del mattino e alle 18 di un venerdì. Neanche gli umani sono deterministici, abbiamo solo concordato di non parlarne nelle retrospettive.

Quello che chiederei in cambio è con cosa stiamo confrontando il modello. Due ingegneri a cui si dà lo stesso ticket scrivono soluzioni diverse, e lo stesso ingegnere ne scrive una diversa dopo una brutta nottata. L’output umano varia molto, e abbiamo costruito l’intera disciplina di review, test e CI per conviverci. Un harness è lo stesso meccanismo, applicato di proposito a un agente. Tipi, linter, suite di test, image diff e i gate che ho descritto prima non dipendono dal fatto che il modello si comporti allo stesso modo due volte. Giudicano il risultato, e lo giudicano in modo identico a ogni esecuzione. Il modello resta variabile com’era, e più lavoro passa da lì, meno quella varianza conta, perché ciò che arriva a me è già passato dallo stesso filtro. Nel mio loop di Mir 2 quel filtro sono più di tremila controlli e novantaquattro screenshot di riferimento, e mi fido molto più di lui che della mia attenzione a fine giornata.

Niente di tutto questo copre ogni cosa. Dove il gate è debole, in un giudizio di merito o nel capire se un’architettura avrà ancora senso fra tre anni, nessun controllo deterministico può verificare la risposta, e lì la varianza del modello è un problema vero. Se volete sapere come costruisco questo tipo di harness nei miei progetti privati e me lo chiedete nei commenti, potrei scriverne.

Dove lascia i metodi

Continuo a studiare pattern e metodi, e preferirei comunque lavorare con un ingegnere che li conosce bene piuttosto che con uno che non li conosce. Quello che ho smesso di fare è mettere i loro nomi davanti a un agente aspettandomi che il nome porti con sé l’intento. I numeri di Luu dicono che per lo più non succede, e il nostro setup va nella stessa direzione.

Se volete un primo passo concreto, aprite le istruzioni che date ai vostri agenti e cercate ogni riga che nomina un metodo: usa il TDD, segui SOLID, applica il repository pattern. Per ognuna, chiedetevi cosa vi preoccupava davvero quando l’avete scritta, e scrivete quello, con le parole di qualcuno che conosce il vostro dominio. Spesso scoprirete che “usa il TDD” voleva dire “per favore non rompere di nuovo il calcolo della fattura”, e quella frase è un’istruzione molto migliore. Alcune righe si riveleranno non riguardare nulla in particolare, e quelle potete cancellarle.

Poi mi piacerebbe sapere cosa avete trovato. State ancora chiedendo ai vostri agenti di seguire un metodo, o avete iniziato a chiedere loro un risultato?

P.S. Questo articolo è stato scritto con il supporto dell'intelligenza artificiale.
Torna alla home