Quando ho iniziato a giocare con gli strumenti di IA per programmare, avevo una fantasia molto semplice in testa. Pensavo che avrei aperto l’editor, collegato un agente intelligente, e lui avrebbe capito subito il mio progetto, il mio stile, le mie abitudini. Avrebbe letto tutta la codebase, seguito i miei gusti e mi avrebbe aiutato a costruire funzionalità quasi come un vero collega di lavoro.
La realtà non è stata così.
La maggior parte delle volte sembrava di stare seduto accanto a uno sviluppatore junior velocissimo, ma che si dimenticava tutto ogni cinque minuti. Dovevo ripetere come chiamo le cose, come organizzo le cartelle, quali pattern mi piacciono e cosa odio. Dovevo comunque rivedere ogni file. A volte finivo più stanco usando l’agente che lavorando da solo.
Questa sensazione mi ha ricordato qualcosa dei miei primi anni nello sviluppo. Intorno al 2016 ho imparato il Test Driven Development. Mi piaceva la teoria: prima scrivi i test che descrivono cosa dovrebbe fare il codice, poi scrivi il codice vero. L’idea è pulita e rigida. Ma nella vita reale non sono mai stato uno che fa “test prima” ogni giorno. Per me scrivere software è un processo creativo. Penso alla struttura e ai pattern prima di cominciare, ma spesso apro un file e inizio a scrivere. La forma della soluzione cambia mentre la costruisco. Scrivere prima i test può aiutare ad avere una struttura migliore, ma per me rallenta quella prima fase creativa.
Più tardi ho lavorato in un’azienda con un prodotto complesso, e lì ho visto un altro lato dello stesso problema. Avevamo user story con persona, criteri di accettazione e tutta la roba classica. Ma spesso le story non erano davvero precise. Il product owner aveva un’idea in testa, la story diceva qualcosa di un po’ diverso, io costruivo la mia interpretazione, il QA testava sulla sua. Ci volevano vari giri di “non è questo quello che volevamo” prima che tutti fossero contenti. Ho imparato una lezione dura: se le persone non sono allineate su cosa significa “finito”, lo paghi in tempo e frustrazione.
Arriviamo ad oggi con gli agenti di IA. All’inizio li usavo come un autocomplete più intelligente. Scrivevo un messaggio lungo con metà del contesto del problema, qualche file, alcune regole, e poi chiedevo una funzionalità. A volte il risultato era ok. Molte volte sembrava buono in superficie, ma era sbagliato nei dettagli. Edge case gestiti male, supposizioni sbagliate su come funzionano le cose nel mio sistema, stile di codice che non mi piaceva. Era di nuovo la sensazione delle brutte user story. Io e l’agente non avevamo la stessa idea di cosa stavamo facendo.
Dopo molti tentativi così, ho avuto due realizzi semplici ma importanti.
Il primo riguarda la memoria. L’agente non si ricorda la mia vita. Non conosce i miei vecchi ticket o le chat precedenti, a meno che non gliele incolli di nuovo. Vede solo il testo che gli do in questa chiamata. Quella “finestra” è il suo mondo intero. Se la riempio di rumore – log lunghi, vecchi messaggi, blocchi di codice enormi – le informazioni chiave si perdono. Quando invece gli do una descrizione breve e pulita, più solo i file che contano davvero, le risposte sono molto migliori. È lo stesso modello, ma il comportamento cambia tantissimo a seconda di cosa gli metto davanti.
Il secondo realizzo riguarda le conversazioni lunghe. Quando restavo troppo a lungo nella stessa chat, tutto diventava una zuppa. Decisioni iniziali, correzioni successive, tentativi falliti, mezze idee, tutto mescolato. Continuavo a correggere l’agente dentro quel thread infinito. “No, non così.” “Aspetta, fallo in quest’altro modo.” Dopo tanti messaggi sembrava che entrambi avessimo perso la storia principale. Se fossi io il modello a leggere quella cronologia, mi confonderei anche io. Il “passo successivo” che si adatta a quella storia confusa è solo un’altra serie di modifiche casuali e altre correzioni. Non stupisce che la qualità crolli.
Per questo ho iniziato a cambiare il mio modo di lavorare. Volevo qualcosa che mi lasciasse ancora spazio per essere creativo, ma che desse anche all’agente una possibilità reale di aiutarmi. Quello che ho trovato per me è uno schema molto semplice da dire: prima capire, poi tracciare, poi costruire. Non è un metodo rigido, ma una piccola regola mentale che mi ferma dal saltare troppo in fretta al “per favore scrivi il codice”.
Quando dico “capire”, intendo che prima che l’agente tocchi qualcosa, deve studiare il codice e spiegarmelo. Per esempio, immaginiamo che voglia aggiungere un nuovo flusso di login, tipo il magic link, in un progetto vecchio. In passato avrei detto all’agente direttamente “aggiungi il magic link” e speravo trovasse i file giusti. Ora faccio diverso. Chiedo all’agente di leggere il codice attuale di login e di scrivere una nota breve per me. In quella nota voglio vedere dove gestiamo le credenziali, come vengono create le sessioni, come vengono inviate le email, cosa sembra strano o speciale. Gli dico chiaramente di non cambiare nessun codice, solo osservare e riportare.
Quando ricevo questa nota, la posso leggere in un paio di minuti. Se manca qualcosa o c’è un errore, lo correggo. Magari c’è un modulo vecchio che in realtà non usiamo più, o un percorso critico che non può rompersi. Dopo questo, ho una vista compatta della situazione attuale, e l’agente ha appena elaborato le stesse informazioni. Stiamo guardando la stessa mappa piccola, non una giungla di file.
Il passo successivo per me è la “traccia”. In base a quella mappa, chiedo all’agente di descrivere come dovremmo affrontare il cambiamento. Voglio un testo che suoni quasi come un piccolo piano per un collega. Quali parti del sistema devono cambiare, che nuovo comportamento aggiungiamo, quale comportamento vecchio deve restare com’è, come testeremo il tutto, quali rischi vediamo. Ancora non do il permesso di toccare il codice qui. Prima leggo la traccia. È in questo punto che prendo i grossi errori. Magari l’agente vuole spostare la logica di login in un posto che non si integra bene con il resto dell’architettura. Magari si dimentica una validazione importante. Sistemare queste cose nella traccia costa poco rispetto a pulire una soluzione mezza implementata e sbagliata.
Quando la traccia mi sembra giusta, finalmente passo alla parte di “costruzione”. Adesso dico all’agente di seguire la traccia e cambiare davvero i file. Gli chiedo di farlo a piccoli pezzi, farmi vedere le modifiche, eseguire i test quando ha senso, e aggiustare se qualcosa fallisce. La mia revisione è più semplice adesso. Non devo più valutare di nuovo tutto il concetto, devo solo controllare se le modifiche concrete seguono la traccia e mantengono la qualità del codice che voglio. Alla fine chiedo sempre un file di riepilogo breve. In quel riassunto voglio sapere cosa è cambiato, dove, e come verificare il comportamento. Questo serve soprattutto al me del futuro. Quando riapro il progetto dopo un mese, posso leggere quel file e ricordarmi in fretta perché certo codice è diverso.
C’è anche il problema delle sessioni lunghe. Anche con questo flusso, alcuni task richiedono molti passi e molti messaggi. Output dei test, avvisi del linter, fix extra, rami diversi della traccia. A un certo punto sento che la conversazione diventa pesante e l’agente non è più così lucido. I fatti importanti ci sono ancora, ma nascosti nel rumore. Quando succede, ora faccio una specie di checkpoint. Chiedo all’agente di smettere di modificare e di scrivere un file di stato pulito che spiega dove siamo arrivati. Parti finite, cose ancora aperte, decisioni di design importanti e pezzi di codice delicati. Dopo questo, chiudo la chat e ne apro una nuova. Nella nuova chat incollo solo l’obiettivo iniziale e quel file di stato. È come caricare un salvataggio di un gioco senza tutti i log inutili. L’agente vede di nuovo un quadro semplice e concentrato, e la qualità risale.
In parallelo, ho anche iniziato a raccogliere le mie regole in piccole “guide” invece che in un unico prompt gigante. Una guida per me è solo un documento o una cartella che descrive come mi piace gestire un certo tipo di lavoro. Per esempio, posso avere una guida al refactoring dove scrivo le mie regole per fare refactor in modo sicuro, qualche esempio di cambiamenti fatti bene e fatti male, e magari una checklist veloce. Posso avere una guida per le modifiche al database che spiega come gestiamo migrazioni, backup e rollback. Posso avere una guida per la documentazione con il tono e la struttura che preferisco.
Queste guide vivono dentro il progetto, di solito come semplici file markdown vicino al codice o in una cartella dedicata. Quando chiedo all’agente di fare un task di quel tipo, lo indirizzo alla guida giusta. Invece di provare a codificare il mio stile in ogni prompt, dico semplicemente “segui la guida di refactoring in questo percorso” oppure “usa la guida per la documentazione qui”. L’agente può leggere quel file all’inizio del lavoro e poi agire dentro quel quadro. Il grande vantaggio è che posso migliorare queste guide nel tempo. Se vedo che un errore si ripete, aggiungo una riga alla guida. Se cambio gusto, aggiorno la guida. È versionata insieme al resto del codice, e posso condividerla con le altre persone nel team, così parliamo tutti la stessa lingua.
Ovviamente non mi serve tutto questo rituale per ogni singola modifica. Per cose minuscole, tipo cambiare una label, sistemare un bug semplice o formattare un po’ di codice, continuo a chiedere direttamente all’agente e a controllare il diff. Non ha senso scrivere una traccia per una riga sola. Per task medi, come aggiungere un nuovo campo in un form, a volte salto la fase di “capire” e scrivo io una piccola traccia, poi lascio che l’agente la segua. Per cambiamenti grandi e rischiosi, uso tutto il flusso con capire, tracciare, costruire, più guide e checkpoint. La quantità di struttura cresce insieme alla dimensione e al rischio del cambiamento.
Un’abitudine in più che mi piace è usare l’agente alla fine di una feature per migliorare le guide e il processo. Quando un task è finito, i test passano e sono soddisfatto del risultato, spesso chiedo all’agente di riguardare il percorso. Può confrontare l’obiettivo iniziale, la traccia e il codice finale. Poi faccio domande del tipo “dove abbiamo perso tempo”, “cosa non era chiaro nella descrizione”, “quale errore si è ripetuto più di una volta”. Le risposte non sono perfette, ma spesso indicano piccoli miglioramenti che posso fare. Magari mi accorgo che mi sono dimenticato di parlare delle regole di logging nella traccia. Magari scopriamo un edge case comune che merita una nota nella guida giusta. Poi cambio un po’ i miei template e le guide. Nel tempo, questo rende il sistema più solido.
C’è però un pericolo in tutto questo. Più sposto struttura dentro specifiche, tracce e guide, più do potere a quei testi. Una riga di codice sbagliata è solo una riga sbagliata che posso correggere. Una frase scritta male in una guida o un dettaglio sbagliato nella traccia possono generare tante righe di codice sbagliate. Quindi cerco di tenere il cervello concentrato su quei livelli più alti. Lascio che l’agente faccia il lavoro pesante di leggere e scrivere codice, ma non gli affido alla cieca la definizione delle regole. Leggo quello che propone. Decido io cosa diventa parte delle mie guide fisse.
Per questo, quando qualcuno mi chiede come ottenere più valore dagli agenti nello sviluppo, di solito non parto dal tema “qual è il modello leggermente migliore questo mese”. Penso che i modelli contino, ma per il lavoro di tutti i giorni il cambiamento più grande per me è arrivato da questo modo di lavorare. Tratto l’agente come un aiutante molto veloce, ma senza memoria a lungo termine. Sono io responsabile del contesto che gli do, della chiarezza della specifica e della qualità delle guide. Se faccio bene la mia parte lì, la maggior parte dei modelli forti mi dà risultati decenti. Se do input sbagliati, anche il modello migliore produrrà solo errori impacchettati bene.
Quindi, cosa significa questo con tutti i nuovi strumenti e modelli che spuntano ogni settimana? Mi piace ancora provarli, ma non inseguo più ognuno come se fosse una nuova religione. Ho il mio flusso base: capire, tracciare, costruire, più il mio set di guide in crescita e l’abitudine di fare checkpoint quando le cose diventano rumorose. Un nuovo modello è solo un motore diverso sotto la stessa macchina. Se va meglio, tanto meglio. Se no, posso tornare indietro. La parte importante è che finalmente sento di avere un modo di usare gli agenti che sostiene il mio modo creativo di lavorare invece di combatterlo.
Windsurf
All my projects and even this website is build using Windsurf Editor. Windsurf is the most intuitive AI coding experience, built to keep you and your team in flow.
Contattaci
Se hai bisogno di uno sviluppatore che offra soluzioni rapide, affidabili e concrete, contattaci. Trasformiamo la tua idea o il tuo progetto in qualcosa che funzioni.