approfondimento

Tool per la generazione di software, cosa possono fare realmente



Indirizzo copiato

I sistemi di supporto allo sviluppo di codice basati su GenAI sono in grado di trasformare il lavoro degli sviluppatori, rendendolo non solo più efficiente, più rapido e meno ripetitivo, ma anche più efficace. Per esempio, grazie alla capacità di proporre soluzioni alternative a uno stesso problema

Pubblicato il 3 lug 2024

Francesco Bertolotti

Assegnista di ricerca Scuola di Ingegneria Industriale dell'Università Cattaneo – LIUC

Luca Mari

Professore Ordinario Scuola di Ingegneria Industriale dell'Università Cattaneo – LIUC



reti generative

Nel settembre 2022, tre mesi dopo il rilascio della prima versione di GitHub Copilot, una ricerca interna ha dimostrato che gli sviluppatori che lo utilizzavano erano più efficaci: il tasso di risoluzione dei problemi aumentava almeno del 70%, e lavoravano in media due volte più rapidamente rispetto ai colleghi che non lo utilizzavano. È quindi noto da quasi due anni che i tool di supporto allo sviluppo di codice basati su Intelligenza Artificiale Generativa (GenAI) possono trasformare il lavoro degli sviluppatori, rendendolo non solo più efficiente, perché più rapido e meno ripetitivo, ma spesso anche più efficace, per esempio grazie alla capacità di questi sistemi di proporre soluzioni alternative a uno stesso problema.

I possibili utilizzi dei sistemi di GenAI per gli sviluppatori di software

Per questo motivo, è particolarmente interessante cercare di comprendere lo scenario attuale dei sistemi di GenAI “verticalizzati” per gli sviluppatori di software, a partire da un’esplorazione dei loro possibili utilizzi. Quelli che mostriamo qui, con esempi volutamente semplici per mantenere l’enfasi sul genere di funzionalità che è possibile ottenere, sono tra i più importanti tool per lo sviluppo di software.

Scrittura di codice

L’attività più semplice e immediata che questi strumenti possono svolgere è di scrivere un pezzo di codice, a partire da una richiesta che può essere anche solo di spiegazione generica di un problema tecnico. Tipicamente, il codice richiesto non deve essere troppo lungo, per evitare di superare la dimensione della context window del modello linguistico che si sta usando (ovvero il numero massimo di token che un LLM può gestire in una conversazione). L’esperienza suggerisce che una buona strategia sia di chiedere la generazione di funzioni semplici, da assemblare successivamente.

Domanda: Come si ottiene il tipo di una variabile Python?
Risposta: In Python, è possibile ottenere il tipo di una variabile utilizzando la funzione built-in type(). Ecco un esempio:
x = 5
print(type(x)) # Output: <classe ‘int’>
In questo esempio, type(x) restituisce la classe int, che sta per intero. Ecco un altro esempio:
y = “Ciao, mondo!”
print(type(y)) # Output: <classe ‘str’>
In questo esempio, type(y) restituisce la classe str, che sta per stringa.
È possibile utilizzare type() per verificare il tipo di qualsiasi variabile Python, compresi elenchi, dizionari, funzioni e classi.
Esempio di scrittura di codice prodotto da un LLM

Identificazione di bug in un programma

Un’altra importante attività in cui i LLM possono supportare lo sviluppo del codice è l’identificazione e la correzione di bug. Contrariamente all’esempio precedente, il valore dell’uso di questi strumenti aumenta con la complessità del codice in fase di debugging. Questo è particolarmente vero se si opera con un IDE, come GitHub Copilot, AWS Whisperer o Continue, che ha accesso diretto al codice nel contesto, anziché un semplice chatbot come ChatGPT, Claude o Gemini. In tali casi, la capacità di focalizzarsi anche su dettagli risulta estremamente utile per individuare problemi specifici che potrebbero essere stati trascurati e che potrebbero influenzare in modo inaspettato il comportamento del programma in esame.

Domanda: Dov’è il bug in questo codice Python?
a = [1,2,3)
Risposta: Il bug in questo codice Python è un errore di sintassi dovuto alla mancanza di una parentesi quadra di chiusura nella definizione dell’elenco. Per risolvere il problema, sostituite la parentesi di chiusura con una parentesi quadra di chiusura come segue:
a = [1, 2, 3]
In questo modo si definisce una lista con tre elementi: 1, 2 e 3.
Esempio di identificazione di bug eseguita da un LLM

Spiegazione del comportamento di una parte di un programma

Quando si lavora su codice sviluppato da altri programmatori, come avviene solitamente in ambiti professionali, o si ha a che fare con linguaggi e framework poco familiari, può essere utile domandare a un LLM di spiegare il comportamento di un pezzo di codice. Sebbene questi sistemi siano generalmente efficaci in tale compito, la mancanza di contesto può causare imprecisioni ed errori, potenzialmente gravi anche perché potrebbero non essere messi immediatamente alla prova – a differenza di un pezzo di codice che può essere eseguito – e cambiando la comprensione dello sviluppatore possono ripercuotersi nel medio e lungo periodo.

Domanda: Puoi spiegare cosa fa questo codice Python?
x = [i for i in range(10) if i/2 == int(i/2)]
Risposta: Questo codice Python crea una lista x che contiene tutti i numeri pari da 0 a 9 (inclusi).
Ecco come funziona: range(10) crea una sequenza di numeri da 0 a 9 (inclusi). Il ciclo for itera su ogni numero della sequenza. L’istruzione if filtra tutti i numeri che non sono pari. La condizione i/2 == int(i/2) verifica se il numero è pari dividendolo per 2 e controllando se il risultato è un intero. Se il risultato è un intero, il numero è pari. Infine, il valore i che ha superato l’istruzione if viene aggiunto all’elenco x utilizzando un’espressione di list comprehension. Pertanto, l’elenco x risultante conterrà i numeri pari da 0 a 9 (inclusi):
[0, 2, 4, 6, 8]
Esempio di spiegazione del comportamento di un codice prodotta da un LLM

Miglioramento e ottimizzazione di codice

Ci sono casi in cui è necessario migliorare un pezzo di codice già funzionante, magari per renderlo più mantenibile o per aumentarne le prestazioni. In tali situazioni, i suggerimenti degli LLM si rivelano spesso sensati e quindi preziosi. È importante ricordare che questi sistemi sono addestrati, non programmati, e rispondono in modo che chi ha generato i testi e il codice utilizzati per l’addestramento considererebbe appropriato, e migliorare in questo senso un pezzo di codice è un ottimo metodo per renderlo più facilmente utilizzabile da altri sviluppatori.

Domanda: Puoi migliorare questo codice Python?
x = [i for i in range(10) if i/2 == int(i/2)]
Risposta: Il codice Python x = [i for i in range(10) if i/2 == int(i/2)] può essere migliorato in termini di leggibilità ed efficienza.
Ecco alcuni suggerimenti per migliorare il codice: Utilizzate l’operatore modulo % per verificare la parità invece di dividere per 2 e controllare se il risultato è un intero:
x = [i for i in range(10) if i % 2 == 0] Utilizzate un’espressione generatrice invece di una comprensione di elenco se dovete iterare sull’elenco una sola volta e non avete bisogno di memorizzare l’intero elenco:
x = (i for i in range(10) if i % 2 == 0)
Ciò crea un generatore che produce i numeri pari da 0 a 9 quando vengono richiesti. Utilizzate nomi di variabili significativi per migliorare la leggibilità:
even_numbers = [i for i in range(10) if i % 2 == 0]
In questo modo è chiaro che l’elenco even_numbers contiene numeri pari. Apportando queste modifiche, il codice diventa più conciso, efficiente e facile da leggere.
Esempio di miglioramento di codice eseguito da un LLM

Produzione di documentazione di un programma

La produzione di documentazione del codice è un’attività tediosa ma spesso necessaria, in cui gli LLM, specialmente quando impiegati negli IDE, eccellono. La loro efficacia aumenta poi operando in modo bottom-up, ovvero facendo commentare prima le singole righe, poi i vari blocchi di codice e infine le intere funzioni, poiché il codice si arricchisce progressivamente di contesto rendendo più semplice per un LLM scrivere commenti complessi, comprendendo ciò che accade in sezioni sempre più ampie di codice. In modo simile, se si fornisce al codice una chiara connotazione semantica – per esempio assegnando nomi significativi a classi, variabili e funzioni – rapidità ed efficienza della documentazione aumentano sensibilmente.

Domanda: Puoi aggiungere della documentazione a questo codice Python?
for i in range(10):
if i % 2 == 0:
print(f'{i} è un numero pari’)
Risposta: Certo! Ecco un esempio di come si potrebbe documentare il codice Python:
# Questo ciclo itera sui numeri da 0 a 9 (inclusi)
# e stampa un messaggio per ogni numero pari.
for i in range(10):
if i % 2 == 0: # Controlla se il numero è pari
print(f'{i} è un numero pari’) # Stampa un messaggio se il numero è pari
La documentazione fornisce una breve spiegazione di ciò che fa il codice, oltre a commenti che spiegano cosa fa ogni riga di codice. I commenti aiutano a rendere il codice più leggibile e comprensibile per altri programmatori che potrebbero leggere o modificare il codice in futuro.
Esempio di documentazione di codice scritta da un LLM

Traduzione in un’altra lingua dei testi e dei commenti di un programma

Da tempo è nota l’abilità dei modelli di GenAI nella traduzione del linguaggio naturale. Gli LLM sono anche in grado di distinguere i tipi di testo all’interno del codice, per esempio comprendendo cosa sia una stringa da stampare e cosa sia codice da eseguire, discernendo in questo modo ciò che deve essere tradotto in una lingua diversa in base a specifiche istruzioni.

Domanda: Puoi tradurre in italiano le stringhe di questo codice Python?
x = input(“What’s your name?”)
print(f “Welcome {x}”)
Risposta: Certo! Ecco la traduzione in italiano:
x = input(“Qual è il tuo nome? “)
print(f “Benvenuto {x}”)
Esempio di traduzione di stringhe in un’altra lingua eseguita da un LLM

Traduzione di codice in un altro linguaggio di programmazione

Un LLM è anche in grado di tradurre codice da un linguaggio all’altro. In questo caso, come per la scrittura, l’estensione del codice diventa una caratteristica critica: oltre una certa lunghezza, la qualità del risultato diminuisce drasticamente, richiedendo spesso ulteriore lavoro per renderlo funzionante.

Domanda: Puoi tradurre questo codice Python in JavaScript?
x = input(“Come ti chiami?”)
print(f “Benvenuto {x}”)
Risposta: Certo! Ecco la traduzione:
let x = prompt(“Come ti chiami? “);
console.log(Benvenuto ${x});
Esempio di traduzione di codice in un altro linguaggio di programmazione eseguita da un LLM

Generazione di codice per mettere alla prova parti di codice

In un contesto industriale, è fondamentale dotarsi di metodi strutturati per mettere alla prova il codice che si scrive, e un LLM può generare funzioni di unit test.

Domanda: Puoi generare il codice per fare il testing della correttezza del comportamento di questo codice Python?
x = input(“Come ti chiami?”)
print(f “Benvenuto {x}”)
Risposta: Certo! Per testare il comportamento di questo codice Python, possiamo utilizzare la libreria unittest per scrivere dei test automatizzati. Considerando che il codice utilizza input e print, dobbiamo utilizzare il modulo unittest.mock per simulare l’input e catturare l’output.
Ecco un esempio di come fare questo::
import unittest from unittest.mock import patch import io def get_name_and_greet(): x = input(“Come ti chiami?”) print(f”Benvenuto {x}”) class TestGetNameAndGreet(unittest.TestCase): @patch(‘builtins.input’, return_value=’Mario’) @patch(‘sys.stdout’, new_callable=io.StringIO) def test_get_name_and_greet(self, mock_stdout, mock_input): get_name_and_greet() self.assertIn(“Benvenuto Mario”, mock_stdout.getvalue().strip()) if __name__ == ‘__main__’: unittest.main()
Esempio di generazione di codice di testing prodotto da un LLM

Guida sulle scelte di programmazione

Infine, si può chiedere a un LLM di guidarci nelle scelte di progettazione, per esempio identificando i framework da utilizzare in un determinato contesto, o suggerendo quale algoritmo esistente implementare per risolvere un certo problema.

Domanda: Puoi discutere quando, in un’applicazione web Python basata su Flask, è meglio usare i template Jinja e quando il semplice HTML?
Risposta: In un’applicazione web Python basata su Flask, è meglio usare i template Jinja quando è necessario generare contenuti HTML dinamici che cambiano in base al contesto o ai dati visualizzati. I modelli Jinja consentono di incorporare facilmente il codice Python nei modelli HTML per generare contenuti dinamici, come l’iterazione di un elenco di elementi per visualizzarli in una tabella o la visualizzazione condizionata di contenuti in base allo stato di autenticazione dell’utente o ad altri fattori.
D’altra parte, è meglio usare il semplice HTML quando si ha un contenuto statico che non ha bisogno di essere generato dinamicamente. Ad esempio, si può usare l’HTML semplice per pagine statiche come la pagina Informazioni o Contatti, dove il contenuto non è destinato a cambiare frequentemente e non dipende da dati dinamici o da input dell’utente.
In generale, nella vostra applicazione web Flask potete usare un mix di modelli Jinja e HTML semplice, a seconda dei requisiti di ogni pagina o componente. Potete usare i modelli Jinja per i contenuti dinamici e il semplice HTML per i contenuti statici. Inoltre, potete usare CSS e JavaScript per creare stile e aggiungere interattività alla vostra applicazione web, indipendentemente dal fatto che stiate usando i modelli Jinja o il semplice HTML.
Esempio di guida su scelte di sviluppo di codice proposta da un LLM

Conclusioni

C’è ancora molto da sperimentare e molto da imparare in tutto ciò, ma una prima, plausibile conclusione che già oggi possiamo trarre è che, dotati di strumenti con capacità di questo genere, gli sviluppatori di software cambieranno il loro modo di lavorare, e cambieranno le competenze che sono loro richieste.

Articoli correlati

Articolo 1 di 4