Spiegazione e prova
I linguaggi di programmazione non esistono solo per comunicare istruzioni alla macchina. Esistono per trasformare idee vaghe in rappresentazioni formali, libere da ambiguità.
L’impatto degli strumenti di IA generativa basati su LLM nell’industria dello sviluppo software è stato indubbiamente considerevole (e controverso). Tra le varie domande e riflessioni che si sono fatte, una in particolare attira la mia attenzione: che ne sarà dei linguaggi di programmazione ora che gli agenti sono capaci di scrivere programmi interi attraverso cicli di interazione con gli esseri umani? Dato che queste interazioni si basano sulla spiegazione delle specifiche del programma in linguaggio naturale, la formulazione di una rappresentazione del programma in JavaScript, C, Rust o Go, per esempio, diventerebbe obsoleta, ridondante. Se così fosse, perché dovremmo insegnare alle nuove generazioni a programmare? L’agente potrebbe generare il codice binario, già pronto per l’esecuzione, giusto? Hm… forse non esattamente. L’errore che vedo in questa prospettiva sta nel non osservare la differenza fondamentale tra spiegazione e prova.
Un buon prompt
Una persona può spiegare alla macchina comandi, comportamenti e caratteristiche che vorrebbe integrare in un programma. Il linguaggio naturale, tuttavia, porta intrinsecamente ambiguità, che hanno la loro funzione nella comunicazione umana, ma che condizionano la comprensione della spiegazione a un carattere non deterministico. Cioè, è possibile che l’interpretazione del messaggio da parte del destinatario trovi compatibilità con l’intenzione del mittente, ma può anche non farlo.
Il codice sorgente, d’altra parte, utilizza strutture formali per definire flussi e relazioni logiche, contesto, variabili, ecc.. Questo garantisce una corrispondenza tra ciò che è rappresentato nel codice e l’effetto della sua esecuzione. Pertanto, un programma, nel provare l’idea nel suo codice, non semplicemente comunica le sue caratteristiche, ma è incorporato dalla macchina che lo esegue quando garantisce un’esecuzione deterministica.
Si nota che spesso si dice che un buon prompt deve usare le parole giuste, deve essere costruito in modo succinto e oggettivo, esponendo punti di interesse specifici, non può contenere informazioni superflue, ecc.. Tutta questa cura serve affinché la macchina non si perda in interpretazioni che deviano dall’intenzione originale del prompt. Se continuassimo a restringere le possibilità di comunicazione (parole che possono essere usate, formulazioni sintattiche) per mitigare le ambiguità, quale sarebbe il risultato? Non sarebbe questa la conversione di un linguaggio naturale in un linguaggio formale?
Un punto di vista matematico
Nel processo di sviluppo software, partiamo dalla raccolta dei requisiti che consolidano un’idea, ancora a un alto livello di astrazione. Quando usiamo un linguaggio di programmazione per trascrivere tale idea in codice sorgente, stiamo definendo una rappresentazione che cerca di formalizzarla.
Per illustrare questo punto, ricorriamo alla matematica. Consideriamo la seguente descrizione:
Una linea parte dal suolo, passa per il punto in cui l’altezza è a 1 metro dal suolo, e tocca di nuovo il suolo a un metro dall’origine.
Ora proviamo a rappresentare questa idea attraverso un disegno.

Tutti i requisiti di questa prima spiegazione sono verificabili nella rappresentazione grafica sopra, tuttavia, questa non è necessariamente accurata rispetto all’idea inizialmente immaginata. Possiamo reiterare la spiegazione e cercare di avvicinarci all’idea, ma questa porterà sempre un grado di imprecisione che trasforma questa ricerca in qualcosa di praticamente casuale.



Infine, descriviamo la linea usando la seguente notazione:
x -> distanza orizzontale in metri con origine nel punto iniziale della linea,
y -> altezza in metri a partire dal suolo
Così, è possibile osservare la posizione inequivocabile della linea in ogni punto della traiettoria tra l’origine e la destinazione.

Questa precisione e osservabilità si raggiungono solo attraverso la proposta di una prova formale dell’idea, che esclude ambiguità. Se diciamo che la linea ancora non corrisponde alla specifica iniziale (il che sarebbe un bug), possiamo e sappiamo come regolare l’espressione matematica data per raggiungere il risultato desiderato. Espressioni matematiche e programmi computazionali, equivalenti per la loro natura formale, condividono questa stessa capacità.
Chi leggerà il codice di domani?
Ciò che gli agenti di IA basati su LLM fanno attualmente è tradurre una spiegazione, data in linguaggio naturale, in codice sorgente fatto a pezzi. Rimuovere completamente il peso umano di imparare le regole sintattiche di un linguaggio formale, delegare tutto il peso dell’interpretazione alla macchina e ai suoi modelli linguistici può sembrare allettante. Tuttavia, non credo che sia desiderabile per nessuno (aziende, banche, ospedali, enti governativi, ecc..) che i programmi diventino artefatti inosservabili, virtualmente incorreggibili, la cui unica possibilità di rettifica sarebbe un altro prompt e la fede che l’agente azzecchi la specifica. Ci sarà sempre la necessità che qualcuno convalidi, mantenga, interpreti i guasti e certifichi la sicurezza di ciò che viene prodotto. Siamo vincolati alla necessità di mantenere i programmi in una forma che sia intelligibile per noi e incorporabile dalla macchina. I linguaggi di programmazione continuano a essere elementi fondamentali dell’ingegneria del software e, con questo, la necessità di persone che li comprendano.