Javascript, HTML, CSS e... !
0 commenti

Debug, Log e Trascrizione esecuzione

Identificare e risolvere gli errori in Google Apps Script con il debug e gli altri strumenti

Non importa il livello di esperienza che uno ha nella programmazione, commettere errori durante la scrittura del codice è inevitabile!
Tuttavia, che siano errori causati dalla fretta, dalla distrazione o dalla mancanza di visione completa del progetto esiste sempre un modo per scovarli e poterli correggere.

In generale esistono 3 tipologie di errore, gli errori di sintassi, gli errori logici e gli errori di semantica:

- errori sintattici: si verificano quando viene commesso un errore nella scrittura di un'istruzione non prevista dal linguaggio di programmazione;
- errori logici: si verificano quando il programma, durante la sua esecuzione, incontra delle eccezioni;
- errori semantici: si verificano quando il programma restituisce un risultato incoerente a quello atteso o si comporta in modo inaspettato.

I primi due sono facili da individuare in quanto sono segnalati dall'editor dell'ambiente di sviluppo, i terzi invece, in base al loro grado di annidamento, possono richiedere analisi del codice approfondite.

Per descrivere come sia possibile identificare e risolvere gli errori negli script in Google Apps Script ho messo a punto un semplice esempio, di per se fine a se stesso, che aiuta a descrivere facilmente come comportarsi di fronte alle situazioni di errore appena descritte.
Quello che dovrebbe effettuare il seguente codice è creare un array di parole da una stringa ed inviare una mail con l'indicazione della dimensione di tale array ad un indirizzo di destinazione previo controllo dell'integrità del relativo formato:

function controllaMail(email_address) {
  if (/^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$/.test(email_address)) {
    return true;
  }
  return false;
}

function inviaMail(email_address, email_subject, email_message) {
  var chkmail = controllaMail(email_address);
  if (chkmail) {
    MailApp.sendEmail(email_address, email_subject, email_message);
    return "mail inviata"
  }
  return "mail non inviata"
}

function avvioFunzione() {
  var my_var = "appsscript.it augura a tutti una buona giornata";
  var array = my_var.split(" ";
  var array_len = array.length;
  var email_address = "nome.cognome@.email.it";
  var email_subject = "Risultato";
  var email_message = "La lunghezza dell'array è: " + array_len;
  var response = inviaMail(email, email_subject, email_message);
  Logger.log(response);
}

Riportando il codice nell'editor di script di Google Apps Script e provando a salvarlo, verrà evidenziato subito un messaggio di errore, in una barra rossa in alto allo schermo, che cita ") mancante dopo l'elenco di argomenti" (Fig. 1). Questo tipo di errore, facile da individuare e correggere (sia perchè la riga dell'errore viene evidenziata sia perchè la causa dell'errore viene mostrata nel messaggio a video), può essere definito errore di sintassi e non permette il salvataggio del codice fino a che non è stato corretto:



errore di sintassi in google apps script

Fig. 1 - Errore di sintassi in Google Apps Script


Basterà pertanto aggiungere una parentesi tonda di chiusura alla fine dell'istruzione indicata nel messaggio di errore:

// Genera un errore di sintassi al momento del salvataggio del file:
// ) mancante dopo l'elenco di argomenti
var array = my_var.split(" ";

Questa anomalia era facilmente identificabile a priori da un occhio più attento in quanto all'interno dell'editor la colorazione delle istruzioni successive alla riga incriminata (vedere ad esempio le dichiarazioni delle variabili) non era coerente con il resto delle colorazioni proprio perchè la mancanza della parentesi di chiusura creava al compilatore ambiguità di interpretazione del codice successivo.

Corretta l'incongruenza diventa possibile salvare il codice.
Provando ad eseguire ora lo script, tramite avvioFunzione(), verrà restituito un altro errore sempre all'interno della barra rossa in alto allo schermo, che cita "ReferenceError: "email" non definito" (Fig. 2). Questo tipo di errore, che come il precedente è facile da individuare e correggere (anche in questo caso viene evidenziata la riga incriminata ed indicata la causa dell'errore), può essere definito come errore logico in quanto viene restituito dall'ambiente solo dopo che l'eccezione è stata incontrata durante l'esecuzione del codice.



errore logico in google apps script

Fig. 2 - Errore logico in Google Apps Script


Nel caso specifico la variabile "email", passata alla funzione, non è stata precedentemente definita pertanto nel momento in cui viene richiamata la funzione in questione si genera un'eccezione dovuta a tale variabile che non ha ne tipo ne contenuto:

// Genera un errore di esecuzione al momento dell'avvio del codice:
// ReferenceError: "email" non definito

var email_address = "nome.cognome@.email.it";
var email_subject = "Risultato";
var email_message = "La lunghezza dell'array è: " + array_len;
var response = inviaMail(email, email_subject, email_message);

La soluzione è quella di definire la viaribile "email" oppure, nel caso del codice di esempio in questione, sostituirla con la relativa variabile già presente allo scopo, "email_address".

Gli errori logici sono mostrati anche in Trascrizione esecuzione, che è una finestra di log apribile dal menu "Visualizza -> Trascrizione esecuzione" che in questo caso apparirebbe come segue, Fig. 3:



errore logico mostrato in trascrizione esecuzione in google apps script

Fig. 3 - Errore logico mostrato in Trascrizione esecuzione in Google Apps Script


Corretta anche questa incongruenza è possibile salvare nuovamente e riprovare ad eseguire il codice che magicamente va a buon fine senza restituire alcun messaggio errore, Fig. 4:



trascrizione esecuzione che mostra il completamento dell'operazione in google apps script

Fig. 4 - Trascrizione esecuzione con messaggio di completamento operazione in Google Apps Script


La conferma la posso ottenere grazie al messaggio di log che ho fatto scrivere come ultima riga eseguita dallo script:

Logger.log(response);

I messaggi di log sono un efficace metodo per eseguire il debug delle applicazioni, basterà indicare, nei punti del codice di nostro interesse, l'istruzione Logger.log(dato_da_visualizzare) come indicato nel codice di cui sopra, dove tra parentesi basterà specificare la variabile o l'istruzione di cui se ne vuole visualizzare il risultato.

Per visualizzare i messaggi di log basterà cliccare sulla voce di menu "Visualizza -> Log", apparirà una finestra con i messaggi di log impostati relativi all'ultima esecuzione effettuata, come nel caso dell'esempio in questione (Fig. 5):



messaggio di log in google apps script

Fig. 5 - Messaggio di log in Google Apps Script


Non avendo ricevuto a video alcun messaggio di errore mi sarei aspettato che l'operazione si fosse conclusa con successo, ma la risposta all'interno del log è "mail non inviata"!
Ci troviamo di fronte ad un errore semantico... ossia il programma giunge alla conclusione senza eccezioni ma il risultato non è quello che ci saremo aspettati.

Per un controllo approfondito di ciò che succede durante l'esecuzione dello script potrei avvalermi dell'uso di un serie Logger.log() all'interno del codice per visualizzare il contenuto di variabili o il risultato di funzioni, tuttavia esiste uno strumento integrato nell'editor di script più pratico da utilizzare, e che dà una visione completa e puntuale sullo stato di variabili e funzioni, per verificare in tempo reale quello che succede all'interno del codice istruzione dopo istruzione, il Debug.

Per poter utilizzare il debug è necessario, nell'editor di script, posizionare uno o più breakpoint (letteralmente, punto di interruzione) nel codice dell'applicazione in cui vogliamo che l'esecuzione del codice venga sospesa così da consentire un controllo step by step sulle istruzioni eseguite da quel momento in poi.
Impostare un breakpoint è piuttosto semplice, basterà (all'interno dell'editor di script) effettuare un click sopra il numero di riga dove vogliamo posizionarlo ed apparirà a fianco un piccolo pallino rosso, come mostrato in Fig. 6 al punto 1.
Per rimuoverlo sarà sufficiente cliccare nuovamente sullo stesso numero di riga.

Nel caso del nostro esempio, considerando che la mail sembra non essere inviata, posiziono un breakpoint alla riga 24 (vedere Fig. 6), ovvero nel punto in cui viene richiamata la funzione inviaMail() alla quale vengono passati come parametri i valori relativi all'indirizzo di destinazione, all'oggetto ed al corpo del messaggio della mail.
A questo punto, cliccando sull'icona dello scarabeo, Fig. 6 punto 2, l'editor entra in modalità debug aprendo i relativi pannelli ed eseguendo il codice. Una volta raggiunto il punto di interruzione l'esecuzione dell'applicazione viene sospesa ed è possibile osservare nel pannello in basso all'editor di script la situazione del contenuto delle variabili in quel preciso momento.
In questo momento, non essendo ancora stata eseguita la funzione inviaMail(), la variabile response, il cui scopo è quello di ospitare la risposta a tale chiamata, non è stata ancora valorizzata risultando, come ci si può aspettare, undefined.



debug ed impostazione breakpoint in google apps script

Fig. 6 - Debug ed impostazione Breakpoint in Google Apps Script


Da questa situazione è possibile scorrere istruzione dopo istruzione il codice, senza che venga eseguito tutto in una volta, ed osservare nel pannello in basso all'editor come il contenuto delle variabili cambia di conseguenza. Per farlo abbiamo a disposizione i comandi di navigazione del debug, mostrati in Fig. 6 punto 3 e dettagliati di seguito, Fig. 7:



comandi di navigazione del debug in google apps script

Fig. 7 - Comandi di navigazione del Debug in Google Apps Script


Il primo set di icone (indicato dai punti 1, 2 e 3 in Fig. 7) gestisce l'esecuzione del codice in maniera generica, ovvero:

1) Continua con il debug, avvia nuovamente l'esecuzione del codice dal punto in cui è stato sospeso fino alla fine delle sue istruzioni o fino al successivo breakpoint;
2) Sospendi debug, mette in pausa l'esecusione del codice nel punto in cui viene cliccato, una sorta di breakpoint non definito;
3) Arresta debug, esce dalla modalità di debug.

Il secondo set di icone (indicato dai punti 4, 5 e 6 in Fig. 7) costituisce la parte più funzionale del debug e, una volta che l'esecuzione è stata sospesa da un breakpoint (o dal tasto pausa) permette di eseguire il codice in modo puntuale a seconda delle proprie esigenze, ovvero:

4) Esegui istruzione, esegue la singola istruzione e si posiziona sulla riga di codice successiva. In caso di esecuzione di una chiamata ad una funzione entrerà all'interno della funzione stessa posizionandosi sulla sua prima istruzione;
5) Esegui istruzione/routine, in caso di esecuzione di una chiamata ad una funzione eseguirà automaticamente tutte le sue istruzioni (senza entrare dentro di essa a singoli step) posizionandosi immediatamente sulla riga successiva a quella della chiamata alla funzione. Stesso concetto vale nel caso di blocco di codice condizionale (if, switch, ...) o di ciclo (for, while, ecc...);
6) Esci da istruzione/routine, se all'interno di una funzione, o di un blocco di codice condizionale o di un ciclo, eseguirà automaticamente tutte le sue istruzioni (senza doverle effettuare a singoli step) posizionandosi immediatamente sulla riga successiva a quella della chiamata alla funzione. Nel caso il ritorno fosse in uscita nella funzione principale, il codice continuerà la sua esecuzione.

Personalmente, durante le fasi di debug mi avvalgo principalmente dei comandi Esegui istruzione ed Esegui istruzione/routine (punti 4 e 5 in Fig. 7).

Tornando al caso del nostro esempio, avevamo avviato il debug ed il codice si era sospeso alla riga 24, considerando che in quel punto viene chiamata la funzione per l'invio della mail (mail che per qualche motivo non viene inviata, motivo per il quale stiamo appunto effettuando il debug), entro di un singolo step dentro tale funzione tramite il comando Esegui istruzione (punto 4 della Fig. 7). Ci ritroveremo alla riga 8 dove nel pannello del debug possiamo osservare il contenuto delle variabili passate come parametri (email_address, email_subject, email_message) ed una variabile, chiamata chkmail, non ancora valorizzata (undefined) che servirà per contenere il risultato (true o false) relativo al controllo di integrità del formato dell'indirizzo mail.
Proseguendo di un altro step non cambierà niente a livello di variabili, perchè nessuna particolare istruzione è stata eseguita, ma il codice si posizionerà alla riga 9 dove è presente una chiamata alla funzione controllaMail() che contiene una espressione regolare per verificare se il formato della mail passata come parametro (email_address) è corretto, restituendo la risposta nella variabile chkmail come appena descritto.
Possiamo a questo punto risparmiarci le singole istruzioni presenti all'interno di questa funzione cliccando su Esegui istruzione/routine (punti 5 della Fig. 7). Il codice si posizionerà di conseguenza sulla riga 10 che prevede un blocco condizionale sulla base della risposta del controllo appena effettuato contenuta nella variabile chkmail (vedere Fig. 8 punto 1).
Di conseguenza, ora che la relativa funzione è stata eseguita, il contenuto di tale variabile è visibile nel pannello del debug (Fig. 8 punto 2):



Identificazione delle anomalie tramite la navigazione nel debug in google apps script

Fig. 8 - Identificazione di anomalie nel codice tramite la navigazione nel Debug in Google Apps Script


Svelato l'arcano! Il controllo dell'integrità dell'indirizzo mail dà come risultato false, questo è il motivo per il quale l'invio della mail non è stato effettuato.

Osservando l'indirizzo definito nella variabile email_address diventa subito evidente il motivo per il quale non abbia superato il test della regex, ossia presenta un punto (.) subito dopo la et (@), che negli indirizzi di posta non è permesso:

// Errore di semantica, non immediatamente identificabile ma restituisce risultati incoerenti
// nel caso specifico la mail non è nel formato corretto

var email_address = "nome.cognome@.email.it";

Rimuovendo quel punto e riprovando ad eseguire normalmente il codice, come osservabile dal log (Fig. 9), l'operazione va finalmente, ed effettivamente, a buon fine.



messaggio di log con informazione di avvenuto invio mail in google apps script

Fig. 9 - Messaggio di Log con l'informazione di avvenuto invio mail in Google Apps Script


L'esempio di errore semantico riportato in questo contesto è al solo scopo esplicativo, solitamente tali errori sono molto più difficili da scovare e si annidano nelle logiche di sviluppo, i più comuni sono causati dallo scope delle variabili, ad esempio cicli il cui indice viene sovrascritto da un valore derivante da una seconda funzione chiamata all'interno del ciclo stesso, oppure utilizzo di metodi che in fase di test restituiscono il risultato aspettato ma che in situazioni diversificate (e non verificate) si comportano in modo imprevisto, ed altri casi più o meno simili che con l'esperienza si impara a limitarne l'involontaria generazione.

INDOVINELLO!
A dire il vero all'interno del codice di esempio utilizzato in questo articolo è presente un altro errore fin'ora non descritto. Non è un errore bloccante in questo contesto ma sicuramente a livello concettuale, nonostante la sua banalità, è un'imprecisione che sarebbe opportuno correggere.
Se lo trovate lasciate un commento qui sotto!

Tags

Michele Pisani

Michele Pisani

Sviluppatore Javascript ed esperto in Digital Analytics

L'esperienza nel settore Digital Analytics unita ad anni di sviluppo in Javascript ha trovato la massima espressione in Google Apps Script che mi ha permesso, con estrema facilità e poche righe di codice, di realizzare potenti applicazioni interattive e processi automatizzati integrati con i prodotti della G Suite.

Come contattarmi
scrivi un commento

0 Commenti

Non ci sono commenti

Nessuno ha ancora commentato questo articolo, fallo tu per primo!

scrivi un commento

Scrivi un commento

Il tuo indirizzo email non sarà pubblicato.I campi contrassegnati da un * sono obbligatori
Puoi utilizzare i seguenti tag nei commenti:
[bold]testo[/bold] se vuoi evidenziare un testo con il grassetto[code]function helloworld() { }[/code] se vuoi pubblicare una porzione di codice[url]http://www.appsscript.it[/url] se devi riferirti ad un indirizzo web