Velocità senza struttura significa caos. Come abbiamo portato la logica del Double Diamond nello sviluppo AI-assisted per definire problemi non ambigui e validare l’implementazione in modo sistematico.
Negli ultimi mesi, la rapida evoluzione dei Coding Agent ha completamente stravolto il nostro modo di lavorare in Buildo. Era chiaro che non potevamo semplicemente farci trascinare da questo cambiamento senza un piano preciso. Dovevamo capire come rispondere a questa rivoluzione in modo strutturato, per guidare il cambiamento invece di esserne sopraffatti.
Il nostro percorso è stato probabilmente simile a quello di molti altri team. Abbiamo iniziato con i primi suggerimenti di codice negli editor, abbiamo poi iniziato a utilizzare l’AI per generare piccole parti di logica, fino ad arrivare ad implementare interi prototipi interattivi e progetti pilota completamente sviluppati dall'AI.
Il ritmo del nostro lavoro cambiava rapidamente e i vantaggi di questo approccio erano evidenti fin dall'inizio, ma abbiamo anche capito che c'era il rischio concreto che la velocità, senza una struttura chiara, potesse portare a perdita di controllo e caos.
Quello che funzionava bene per MVP e prototipi non poteva essere applicato direttamente ai progetti più strutturati, con requisiti precisi, mockup da seguire e un processo di validazione formale. Lasciando libera l’AI, si riusciva a ottenere un prodotto spesso sufficientemente funzionante, ma che presentava imprecisioni, divergenze rispetto alle linee guida, funzionalità incomplete o imprecise.
Era chiaro che dovevamo ripensare l’intero sistema in un’ottica AI: come organizziamo il lavoro, come specifichiamo i task e il contesto necessario a implementarli in modo completo e non ambiguo, come gestiamo le dipendenze tra task e la loro prioritizzazione, fino a come validiamo l’implementato e garantiamo la qualità in modo sistematico.
In questo post ci concentriamo su un singolo mattone, che va dalla specifica di un task alla sua validazione post-implementazione. È un punto di partenza deliberato, che andrà a incastrarsi in una visione più ampia in cui l'AI assiste l'intera gestione del progetto.

È stato chiaro fin dal principio come l'intelligenza artificiale sia particolarmente efficiente nell'esplorazione, nell’individuare incongruenze nei ragionamenti, o nel suggerire soluzioni da seguire. La stessa propensione a trovare sempre una risposta che la rende utile nell'esplorazione, però, la porta a colmare le lacune di requisito con la risposta che sembra più plausibile, anche se non è quella voluta.
Quando diamo agli agenti più libertà di azione, aumenta il rischio che essi escano dai binari e creino qualcosa di diverso da quello che avevamo in mente. In progetti con requisiti meno rigorosi, come prototipi di UI o MVP da validare, questa tendenza può essere un vantaggio, perché possiamo arrivare più rapidamente a un risultato sufficientemente completo da poter essere testato con il cliente, sfruttando anche una componente di brainstorming e ideazione offerta dall’AI.
Tuttavia, nei progetti che richiedono più rigore, vorremmo che gli agenti seguissero dei percorsi ben precisi, limitando il più possibile le deviazioni dell’AI da quello che vorremmo ottenere. Una schermata non progettata, uno stato non considerato o istruzioni troppo vaghe portano l'agente a riempire i buchi a modo suo, con conseguente perdita di fiducia verso il risultato, che può portare a un eccessivo controllo sugli agenti da parte dello sviluppatore e quindi all’annullamento di tutti i vantaggi di efficienza promessi.
Dobbiamo quindi trovare un processo che individui da un lato le lacune prima che diventino problemi e, dall’altro, un modo per permettere all'intelligenza artificiale (e a noi) di verificare efficientemente il risultato prodotto.
La questione era quindi chiara, e addirittura indipendente dall’utilizzo dell’AI. Dovevamo potenziare la nostra capacità di definizione del problema, in modo da renderlo meno ambiguo, e sfruttare l’AI stessa per trovare qualsiasi incongruenza o mancanza che potesse tradursi in risultati non desiderati.
Essendo noi di Buildo abituati a lavorare a stretto contatto con i designer, sapevamo che il loro processo già affronta un problema molto simile. Il loro framework mentale, noto come Double Diamond, divide infatti il lavoro di ricerca e progettazione in due fasi distinte: la definizione del problema e l’ideazione della soluzione, ciascuna composta da un primo momento di esplorazione (divergenza) seguito da uno di decisione (convergenza).

Portare questo principio nello sviluppo significava creare un processo che si concentrasse prima sulla comprensione e formalizzazione del problema in modo da renderlo comprensibile all’agente, definendo tutti i parametri che lo possano guidare nella successiva fase di implementazione, e solo successivamente lavorare insieme ad esso sulla soluzione. Durante le fasi divergenti, l’intelligenza artificiale può essere sfruttata per esplorare, identificare incoerenze, buchi di specifica e proporre una prima bozza di formalizzazione dei requisiti o della soluzione, mentre la fase convergente viene guidata dall’umano, che revisiona, raffina e ratifica il risultato finale sulla base degli artefatti generati dall’AI.
Vediamo quindi più nel dettaglio come abbiamo strutturato le 4 fasi sulla base di questi principi, arrivando a creare un processo a supporto dello sviluppo di un progetto pilota in ambito MedTech. Partivamo da una fase di design già conclusa, che aveva prodotto User Stories, requisiti ad alto livello e mockup delle schermate principali.
In questa prima fase, diamo all'agente il contesto del nuovo sviluppo su cui andremo a lavorare, fornendogli tutto il materiale raccolto sul problema: note di progetto, requisiti, mockup, codice già esistente. Lo istruiamo a non pensare alla soluzione, ma a identificare tutto ciò che può risultare poco definito o fuorviante.
Lo scopo in questa fase non è discutere della soluzione, ma far emergere dubbi, mancanze e incongruenze prima che diventino problemi in fase di implementazione.
Nel nostro caso, ad esempio, una skill istruisce l’agente a generare una serie di domande rivolte ai diversi ruoli del team: dubbi di prodotto per il PO, osservazioni sull’interazione utente da rivolgere agli UX designer e analisi tecniche e di fattibilità indirizzate ad un Software Architect.
Sarà poi lo sviluppatore a raccogliere le informazioni necessarie dalle persone coinvolte e a fornirgli le risposte, in modo che, nella fase successiva, l’agente possa formalizzare le specifiche che guideranno lo sviluppo.
Le risposte fornite nella fase precedente, insieme a tutto il materiale di partenza, devono ora prendere una forma precisa, strutturata per essere consumata da un agente AI in fase di implementazione. Iniziamo qui a spostare l’attenzione dal problema (il “cosa”) alla soluzione (il “come”).
Nel nostro processo, un requisito utente di alto livello formalizzato dai designer, come ad esempio "i settings devono essere accessibili ai soli utenti amministratori" si trasforma in una serie di scenari precisi:
Dato che l'utente ha un ruolo admin, quando apre il menu, il link ai settings è visibile.
Dato che l'utente non ha un ruolo admin, quando apre il menu, il link ai settings non compare.
Dato che l'utente ha un ruolo admin, quando naviga direttamente all'URL dei settings, vede il form di configurazione.
Dato che l'utente non ha un ruolo admin, quando naviga all'URL dei settings, viene reindirizzato alla homepage.
Il formato riprende la struttura Gherkin del Behavior-Driven Development (BDD), uno standard diffuso nello sviluppo software per scrivere requisiti in linguaggio semi-formale.
Rispetto ai requisiti utente di partenza, in cui ci si focalizza sull’obiettivo dell’utente ad alto livello, gli scenari scritti in questa fase fanno emergere una serie di decisioni tecniche precise che generalmente non vengono formalizzate in fase di design, perché scontate per il destinatario umano o perché troppo di dettaglio per quella fase (es. “cosa succede se un utente non autorizzato accede direttamente all’URL?”)
Si cerca quindi di colmare più lacune possibili nella definizione di quello che dovrà essere implementato, diminuendo il più possibile il grado di libertà che l’agente avrà nella successiva fase di ideazione della soluzione, e di conseguenza il rischio che possa inventare.
Ancora una volta, l’AI viene sfruttata per la sua capacità di prevedere scenari a cui potremmo non pensare, mentre l’umano interviene per revisionare questi scenari, potendo quindi guidare la fase di convergenza. Usando un formato di specifica leggibile, possiamo anche coinvolgere figure diverse dagli sviluppatori nella review di questi scenari tecnici.
Gli scenari così formalizzati non costituiranno solamente la guida per l’implementazione, ma anche il contratto da validare in fase di testing, fornendo agli agenti anche una serie precisa di requisiti da verificare per valutare il proprio lavoro.

Una volta stabilito cosa l’agente deve creare, possiamo finalmente concentrarci sulla soluzione tecnica. È solo a questo punto che passiamo a sfruttare la modalità di pianificazione dei nostri Coding Agent, chiamata Plan Mode.
Questa modalità, presente ormai nella maggior parte dei tool di sviluppo AI, impone agli agenti di non modificare direttamente il codice, producendo prima un documento con un piano di implementazione, che deve essere approvato o modificato dallo sviluppatore prima di essere eseguito.
Il Plan Mode è per sua natura orientata a trovare soluzioni, quindi tende a produrre piani tecnici in sé coerenti, anche se si basano su assunzioni incomplete. Utilizzandolo solo dopo aver definito gli scenari in modo rigoroso, invitiamo l'agente a muoversi liberamente nello spazio delle possibili soluzioni, senza però uscire dai vincoli che ne definiscono il problema.
Ancora una volta, il ruolo umano sarà quello di validare il piano tecnico, correggere quello che non torna e ratificare le scelte sensate, guidando così la convergenza verso il codice.
Una volta confermata la direzione, l'agente inizia a scrivere il codice seguendo il piano approvato. Il primo passo sarà sfruttare gli scenari ratificati nelle fasi precedenti per generare test automatici che fungeranno da cartina tornasole per capire quando ritenersi soddisfatti dell’implementato: finché i test di accettazione non passeranno, l’agente non potrà considerare il proprio lavoro completato.
Nelle istruzioni fornite, chiediamo anche di aggiungere ai test prodotti la generazione di artefatti che serviranno come prova della corretta implementazione del task. Siccome il progetto pilota su cui abbiamo testato questo flusso ha un’importante componente UI, abbiamo deciso di concentrare questi artefatti sulla produzione di screenshot dell’interfaccia utente, sia dello stato di precondizione, sia dello stato finale. Questi artefatti avranno un triplice scopo:
Nel nostro caso abbiamo sperimentato playwright-bdd per trasformare gli scenari in test E2E con Playwright.
Una volta che tutti i test di accettazione passano, l'agente entra nella fase di "ship" del codice. Prima di inviare il codice in review, viene eseguita una serie di controlli automatici per migliorare la qualità del codice: rimozione del codice morto, eliminazione dei duplicati, e una review secondo linee guida predefinite usando skill ufficiali dell’agente e istruzioni specifiche. Solo una volta superati questi controlli, e migliorato il codice di conseguenza, questo viene pubblicato per revisione.
Una volta fatto questo, in attesa della review umana da parte di un altro sviluppatore, possiamo utilizzare l’agente per aiutarci nella fase di validazione. In parallelo quindi, l’agente:
Seguendo il processo qui sopra descritto, ci stiamo rendendo conto sempre di più di come il lavoro di noi sviluppatori si sta spostando verso la definizione del problema e la verifica del risultato, piuttosto che sul codice che sta nel mezzo.

Nella pratica, il processo si traduce in una serie di file markdown che descrivono le fasi che l'agente deve seguire, e in una serie di skills atomiche e riutilizzabili, orchestrate da questi file, che gestiscono le funzionalità generiche che possono essere condivise tra più progetti: la fase di challenge dei requisiti, i pre-flight checks prima dell'apertura della Pull Request, e così via.
Abbiamo pensato il processo in modo tale che ogni singolo progetto possa definire il proprio workflow specifico in base al contesto e alle proprie necessità, combinando mattoni di base condivisi e affinati nel tempo.
Già dalle prime retrospettive, è infatti emersa la necessità che il processo si adatti non solo tra un progetto e l'altro, ma anche tra task di natura diversa all'interno dello stesso progetto.
In progetti o task più esplorativi, ad esempio, ci siamo resi conto che la prima fase di challenge dei requisiti può risultare molto onerosa se l’obiettivo del progetto (o dello specifico incremento) è arrivare ad un’implementazione prototipale rapida da testare con il cliente, per rifinire i requisiti solo in un secondo momento in base ai feedback del cliente. In questo caso, preferiamo iterare più velocemente sulla soluzione (a costo di lasciare più libertà all’agente), per poi sfruttare la skill di generazione di scenari a posteriori, per ratificare le scelte una volta approvate e garantire l’assenza di regressioni nei prossimi sviluppi.
Diverso è il caso di progetti già ben avviati, dove lo sforzo si sposta dall’aggiunta di nuove funzionalità alla risoluzione di bug su funzionalità esistenti. In questa fase di progetto, la challenge del requisito avrà meno rilevanza. Sarà invece fondamentale raccogliere tutti gli indizi utili a identificare il dominio, i requisiti di partenza della funzionalità, il problema osservato e la sua causa, e guidare l'agente nella scrittura dei test necessari a verificare la risoluzione. Anche in questo caso, riutilizziamo skill già esistenti, come quelle di verifica e produzione degli artefatti di accettazione, per guidare la risoluzione del bug.
Considerando che la natura del compito da svolgere può variare tanto anche all’interno dello stesso progetto, dove si possono alternare task più esplorativi, task di risoluzione di difetti e task di implementazione di feature più rifinite, stiamo esplorando l’inserimento di una fase di triage dell’agente stesso all’interno del processo. L’agente, prima di iniziare a seguire il task assegnato, cerca di capire dal contesto fornito (o chiedendo direttamente allo sviluppatore) la natura del task, e quindi il processo più sensato da seguire.
Questa architettura modulare è, in realtà, un primo passo verso qualcosa di più ampio, che inizia a prendere il nome di Software Factory. In questa visione, l’automazione non riguarderà solo il singolo task, ma l’intero ciclo di vita del progetto: dalla gestione delle dipendenze tra task, al mantenimento di una knowledge base condivisa fino al monitoraggio della qualità del prodotto complessivo nel tempo. Il processo che qui abbiamo descritto costituisce il nucleo di quella visione, che in futuro potrà lasciare agli agenti sempre più autonomia anche nella gestione dell’intero progetto.
Diventa sempre più evidente come il processo possa essere considerato un vero e proprio asset, che va curato e fatto evolvere per seguire le evoluzioni dell’AI e dell’ambiente circostante.
Un mantra che in Buildo ci piace professare è quello del Continuous Improvement: ogni processo, per continuare a funzionare, deve essere soggetto a continue migliorie.
E anche in questo l'AI stessa può aiutarci molto. Al termine di ogni sessione di esecuzione di un task, abbiamo a disposizione tutta l’interazione con l’agente, gli sbagli fatti, le correzioni che è stato necessario impartire, i feedback lasciati in seguito alla review del codice, le linee guida non seguite e le deviazioni dal processo. Tutto questo materiale può essere usato per chiedere all’agente stesso di riflettere sul suo operato, e di proporre cambiamenti alle istruzioni che potrebbero migliorare le iterazioni future.
In questo modo, siamo stati in grado di specificare nuove linee guida del codice che l’agente non stava applicando, migliorare istruzioni per fargli seguire passi che tendeva a ignorare, migliorare il modo in cui verificava il lavoro eseguito (ad esempio con l’aggiunta di strumenti come playwright-mcp per la verifica in tempo reale in browser) o inserire, su suggerimento dell’agente stesso, degli hook che iniettavano contesto per ricordare all’agente le cose da fare al verificarsi di particolari condizioni (come l’aggiornamento di uno specifico file).
Così facendo, con il progredire del progetto abbiamo osservato un continuo miglioramento nel funzionamento del processo stesso, migliorando ulteriormente l’efficienza.

Il processo che qui abbiamo descritto si sta dimostrando robusto su progetti anche molto diversi tra loro.
Questo non è però un punto di arrivo. Quello che stiamo ancora cercando di calibrare è la granularità giusta per ogni tipo di task, per fare in modo che il processo non diventi un peso, ma continui a essere un vantaggio reale.
Una cosa che abbiamo imparato a non sottovalutare è il ruolo della verifica. Una testing strategy solida non serve solo a far passare i test, ma aiuta l'agente a validare il suo lavoro e correggersi automaticamente, oltre a fornire agli sviluppatori e al cliente gli artefatti per fidarsi del risultato senza dover leggere ogni riga di codice. Avere la giusta miscela di test, suddivisi tra le varie tipologie, e assicurarsi che questi verifichino effettivamente tutti i cambiamenti di stato da osservare, diventa fondamentale per guidare l’agente verso l’implementazione corretta e ridurre ulteriormente la possibilità di deriva.
Il cambiamento più grande che stiamo osservando, però, è più sottile: il codice sta diventando sempre meno rilevante. Passiamo più tempo a definire il problema, a fare le domande giuste, a giudicare se la soluzione proposta è quella corretta. Stiamo raffinando i nostri modi di definire i requisiti, a diversi livelli di dettaglio, e in modo tale che siano esaustivi e non ambigui.
Il giudizio umano non è sparito, ma si è spostato e rafforzato.
L’ambizione è costruire un processo che lasci all’AI sempre più autonomia di gestione del progetto, permettendo alla componente umana di focalizzarsi su ciò che conta davvero: la comprensione dei bisogni dell’utente, l’ideazione di soluzioni creative e la validazione del risultato in base all’aspettativa del cliente.
Se sei interessato a collaborare con noi all’interno di questa trasformazione (come cliente, come partner, o come collega) mettiti in contatto con noi. Saremo felici di aiutarti!

Vincenzo è entrato in Buildo nel 2016 come Fullstack Engineer, con una forte specializzazione nelle tecnologie Frontend. È particolarmente attento al miglioramento dei processi e alla qualità del lavoro di squadra, impegnandosi ogni giorno a favorire una collaborazione efficace e a valorizzare il contributo di ogni membro del team.
Stai cercando un partner affidabile per sviluppare la tua soluzione software su misura? Ci piacerebbe sapere di più sul tuo progetto.