Gli agenti AI scrivono codice a una velocità che fino a due anni fa sembrava fantascienza. Eppure, chiunque li abbia messi al lavoro su un progetto reale conosce il prezzo nascosto: lo slop. Codice ridondante, allucinato, di bassa qualità, generato in fretta e da rifare a mano.
Ne abbiamo parlato al nostro ultimo meetup in presenza a Milano, che abbiamo ospitato qui in Datapizza insieme al team di Effect - la libreria che sta portando in TypeScript un sistema di tipi rigoroso per gestire errori, dipendenze ed effetti collaterali in modo esplicito.
Non è stato un incontro casuale: con alcuni dei ragazzi di Effect condividiamo le stesse radici universitarie. Ma, soprattutto, noi stessi usiamo Effect internamente.
Per questo, ci siamo ritrovati per affrontare insieme una domanda scomoda:
se gli agenti producono così tanto slop, di chi è la colpa?
In questo articolo:
Per capire come si elimina lo slop, conviene capire da dove nasce.
Un agente non scrive codice scadente perché è "stupido": lo scrive perché lavora senza vincoli e senza contesto.
Il codice che produciamo per gli esseri umani è ottimizzato per essere conciso e astratto. Nasconde i dettagli, dà per scontato ciò che un collega esperto colmerebbe con l'esperienza. Un agente, quei vuoti, non li riempie con l'esperienza: li riempie tirando a indovinare. Inventa API che non esistono, riscrive la stessa funzione venti volte, risolve la stessa query al database in venti modi diversi.
C'è poi un secondo fattore, più strutturale. A Philosophy of Software Design di John Ousterhout definisce la complessità come tutto ciò che rende un software difficile da capire e da modificare, e distingue i moduli superficiali - tante scatoline che si parlano con interfacce intricate, senza nascondere nulla - dai moduli profondi, che chiudono la complessità dietro un'interfaccia semplice.
Il punto, sollevato sul palco da Leonardo Trapani, founding engineer di Datapizza, è netto: gli agenti non prosperano nella complessità, la creano. Lasciane uno a "vibe-codare" per due giorni e ti ritrovi un cumulo di moduli superficiali aggrovigliati.

Lo slop, in fondo, è questo: codice generato in assenza di vincoli e di una mappa.
Se il problema è la mancanza di vincoli e di contesto, la soluzione è allora rendere il codice più esplicito.
Ed è qui che emerge la verità controintuitiva del meetup: ciò che uno sviluppatore umano percepisce come verboso - tipi scritti per esteso, errori dichiarati, dipendenze visibili - è esattamente la mappa di cui un agente ha bisogno per smettere di indovinare.
Più informazioni esplicite = meno chance di allucinare
Per questo, Mattia Manzati, founding engineer di Effectful Technologies (l'azienda dietro Effect), pone spesso l’accento sulla differenza tra Developer Experience (DX) e Agent Experience (AX).

La DX punta a semplificare la vita all'uomo con sintesi e astrazione. La AX vuole l'opposto: per un agente, il codice esplicito funziona come una mappa semantica che elimina le ambiguità da cui nasce l'errore.
Ok, tutto chiaro. Ma concretamente, come si traduce la verbosità in vincolo?
Attraverso i tipi, ma in un modo diverso da quello a cui TypeScript ci ha abituati.
Di solito il tipo di una funzione racconta una cosa sola: cosa restituisce. Tutto il resto - cosa può andare storto, di cosa ha bisogno per funzionare - resta implicito, sepolto nell'implementazione.
Ed è esattamente lì che un agente si perde e ricomincia a indovinare.
Ecco, Effect ribalta questa logica: ogni operazione viene descritta da un "effetto", e ogni effetto dichiara apertamente tre cose:
Questi tre canali sono vincoli che il compilatore fa rispettare, creando una backpressure - una pressione di ritorno - in cui il sistema di tipi diventa un guardiano che respinge il codice sbagliato verso l'agente, prima che faccia danni.
Il vero game changer, però, è l'LSP (Language Server Protocol) personalizzato di Effect, che funziona da trainer in tempo reale per il modello.
Facciamo un esempio.
Un agente scrive una funzione che usa un servizio - il modulo che, mettiamo, legge e scrive gli utenti - ma dimentica di collegarlo al programma.
Con TypeScript normale riceverebbe un errore generico, tipo "Type X is not assignable to never". Corretto, ma inutile, perché non gli dice cosa ha sbagliato né come rimediare.
L'LSP di Effect, invece, specifica chiaramente il tipo di errore: "manca il servizio UserRepo, vai a fornirlo". In questo modo, l'agente non riceve un enigma, ma un'istruzione: sa cosa correggere e dove.
Dai vincoli si passa all'architettura. Effect usa in modo estensivo la dependency injection, il pattern che permette di scrivere codice debolmente accoppiato, e lo fa con due primitive: i service e i layer.
Il service dichiara solo l'interfaccia - i metodi con cui parli al modulo, per esempio list, search, invoke - e, dettaglio prezioso per un agente con context window limitata, dichiara anche cosa può andare storto, senza che il modello debba aprire l'implementazione per scoprirlo.
Il layer è invece l'implementazione concreta, iniettabile e sostituibile. Interfaccia da una parte, implementazione dall'altra: esattamente i moduli profondi di cui sopra. E le squiggle, le sottolineature rosse dell'editor, diventano l'alleato migliore dell'agente: se prova a usare un effetto senza fornire il layer richiesto, il type checker lo blocca e gli dice cosa manca.
Trapani l'ha mostrato sul sistema che stiamo costruendo in Datapizza: Dual OS, una piattaforma di agenti "a forma d'azienda". Orchestrazione di agenti, esecuzione di workflow, ma soprattutto integrazione profonda con l'infrastruttura del cliente - perché le aziende non usano quasi mai software standard, e la piattaforma deve adattarsi all'azienda, non il contrario. In Dual OS una capability è uno strumento che un agente può usare - per esempio "invia una mail con Gmail" - con input, output ed errori dichiarati in modo esplicito.
Facciamo un esempio, che rende bene l'idea.
Un cliente arriva e dice: "il nostro gateway LLM gira su un tenant Azure, e le credenziali stanno in un vault, non nel database". Senza buoni fondamentali, un agente produce codice orribile: nessuna dependency injection, tutto incastrato a mano.
Con Effect, invece, il server di Dual dichiara nel canale dei Requisiti tutto ciò che gli serve - queue service, credential service, model gateway, sandbox, telemetria - in modo esplicito. I forward deployed engineer compongono i layer specifici di quell'azienda e li iniettano. Se il type system passa, sai che l'hai implementato correttamente.
Lo stesso meccanismo abilita un testing chirurgico: poiché ogni funzione dichiara i suoi requisiti nel canale dei tipi, l'agente individua subito il set minimo di componenti da mockare. Niente simulazione dell'intero ambiente, niente token sprecati - solo ciò che serve a validare quella logica. Si può persino istruirlo a mockare precisi stati di bug per verificare la resilienza del sistema.
Messi in fila, i pezzi raccontano una sola strategia.
Lasciare emergere lo slop iniziale, osservarlo con occhio umano, e poi costruire il sistema che lo blocca alla radice - i tipi come gate, l'LSP come guida, i layer come architettura navigabile.
Effect non è solo uno strumento per programmatori funzionali. È un'infrastruttura per rendere gli agenti AI affidabili e deterministici, trasformando la generazione di codice da scommessa statistica a processo ingegneristico.
La domanda con cui ci siamo lasciati al meetup è la stessa che lasciamo a te: siamo pronti a smettere di scrivere codice solo per noi stessi e iniziare a progettare sistemi che gli agenti AI possano finalmente capire senza sbagliare?