Top

Il Goto E La Buona Programmazione [Parte I – II – III]

spaghetti code

Chiunque sia avvicinato alla programmazione e i suoi linguaggi, che sia alle scuole superiori, all’università o perfino da autodidatta imparando da varie fonti è stato indottrinato con una serie di dogmi sulla buona programmazione, ad es: ogni funzione deve avere al più un unico parametro in uscita, o la parola riservata goto è da considerarsi obsoleta e il suo uso è sconsigliato.

Fai parte anche tu della setta contro Go To?

Per avere un’idea di quanto siano radicate queste convinzioni, basti citare una pubblicazione di Edsger Dijkstra, (uno dei mostri sacri dell’informatica scomparso poco più di dieci anni fa) dall’eloquente titolo:  Go To Statement Considered Harmful (il titolo in realtà non è dello scienziato olandese che lo pubblicò nel 1968 con un più umile: A Case against the GO TO Statement).

Edsger-Dijkstra-Quotes-3

E’ quindi piuttosto facile imbattersi in esponenti di una setta di programmatori che sono soliti considerare l‘uso del Go To come un crimine della peggior risma, retaggio di un passato ormai dimenticato e superato da tempo, una pratica deprecabile paragonabile ai sacrifici umani dell’antichità.

Appena uscito dall’università, anche io, inconsapevolmente, facevo parte di questa setta integralista, e non faccio fatica a immaginare che buona parte dei lettori di questo articolo, almeno quelli che sono arrivati fino a questo punto senza addormentarsi, ne facciano altrimenti parte, in maniera più o meno consapevole. Immaginatevi il mio orrore quindi, quando per la prima volta, cercando di adattare un driver del kernel di linux alle mie esigenze, mi trovai faccia a faccia con, si è proprio quello che state pensando, la  parola (vietata) riservata.

Dallo stupore passai subito alla guerra santa, chi era mai quel barbaro senza dio che aveva fatto ricorso a questa pratica deprecabile ? Come aveva potuto un simile codice essere accettato all’interno del kernel ufficiale ? Non trovai immediata risposta a quella domanda e, pieno di orgoglio giovanile, decisi quindi di riscrivere la funzione in maniera strutturata, immaginando di sottoporla poi all’accettazione del kernel ufficiale.

Ed è qui che, da giovane soldato quale ero, iniziai ad incontrare le prime difficoltà, vi invito a seguire il prossimo articolo, disponibile domani, per capire come sono andate a finire le cose per me. Se poi avete voglia di esporvi, fatemi sapere nei commenti se vi siete rivisti anche voi in questo mio articolo.

Parte Due…

Come tutti sanno, è possibile riscrivere ogni programma che fa uso di goto in modo più strutturato, tuttavia la funzione riscritta divenne più lunga, ma non solo, sembrava  più complicata.

Nel riscriverla avevo adottato un’altro dogma che viene spesso insegnato nei corsi di informatica: una funzione deve avere un unico punto di uscita. Poiché come spesso accade nella programmazione di basso livello, dovevo far uso di risorse hardware per cui dovevo ottenere il controllo esclusivo e rilasciarle al termine dell’utilizzo (o in caso di errore) il risultato finale era una cosa del genere:

if get_resource
   if get_resource
     if get_resource
       if get_resource
         .... corpo della funzione ......
         free_resource
       else
         error_path
       free_resource
     else
       error_path
     free_resource
   else
     error_path
   free_resource 
 else
   error_path

Senza volerlo ero incappato in quello che si chiama l’antipattern arrow.

Arrow_review_1600-1

Per chi non sapesse di cosa si tratta, i pattern sono delle soluzioni eleganti e ben pensate a dei problemi ricorrenti nel campo dell’ingegneria del software. Il loro contrario, cioè errori comuni nella soluzione di problemi ricorrenti è detto antipattern.

Le soluzioni che comportano ad avere una serie di condizioni annidate come quella rappresentata prima è detta antipattern arrow (a causa della tipica forma a freccia che assume il codice)

 if
   if
     if
       if
         .....corpo della funzione....
       endif
     endif
   endif
 endif

Anche a chi a poca esperienza di programmazione è evidente come una soluzione di questo tipo ha almeno due grossi svantaggi:

  • Elevata complessità (ciclomatica)
  • Scalabilità difficoltosa

Al di la dei paroloni, con questo tipo di approccio si ha difficolta ad aggiungere/togliere condizioni, e si rende la vita più difficile non solo al programmatore, ma anche al compilatore che spesso non riesce ad applicare alcune ottimizzazioni.

Torniamo all’esempio e diamo un’occhiata alla soluzione con i goto:

if(get_resource1() != SUCCESS) goto err1;
if (get_resource2() != SUCCESS) goto err2;
if (setup_registers() != SUCCESS)  err3;
  .. corpo della funzione ...

release_res1();
release_res2;();
return SUCCESS;

out3:
release_res1();
out2:
release_res2;();
out1:
return ERROR;
}

La natura lineare di questo approccio facilita l’inserimento di altre condizioni mantenendo la struttura semplice, e minimizza la duplicazione del codice. E domani ci ritroviamo per l’ultimo articolo di questa mia avventura, finirò per riabilitare l’uso del Go To? Sono aperte le scommesse.

Parte Tre

Possiamo programmare senza ricorrere a Goto? Che alternative abbiamo?

Esistono altre soluzioni possibili senza l’uso di goto, ne riporto solo una per motivi di praticità:

if (!get_resource1())
    return error1;

if (!get_resource2())
    {
        release (resource1)
        return error2;
    }

if (!get_resource3())
    {
        release (resource2);
        release (resource1);
        return error3;
    }

if (!get_resource4())
    {
        release (resource3);
        release (resource2);
        release (resource1);
        return error4;
    }

...corpo della funzione...

  release (resource4);
  release (resource3);
  release (resource2);
  release (resource1);

return 0;

Questa soluzione è certamente migliore dell’anti-pattern arrow, ma rispetto a quella che utilizza i goto presenta punti di uscita multipli, forte duplicazione del codice e problemi di manutenibilità (bisogna prestare particolare attenzione per aggiungere un nuovo caso).

Come dicevo, ci sono altre possibilità, i lettori che hanno familiarità con i linguaggi di alto livello sicuramente diranno che il problema potrebbe facilmente risolversi con l’utilizzo delle eccezioni. Bisogna però notare che la gestione delle eccezioni non è supportata da tutti i linguaggi, inoltre, non me ne vogliano i puristi, le eccezioni non sono altro che dei goto sotto mentite spoglie.

dijkstra_thumb

Chiarisco meglio il concetto per evitare flame nei commenti. L’eccezione cosa fa di preciso ? Sospende l’esecuzione sequenziale del programma per eseguire il codice di gestione della condizione inaspettata, in pratica quello che fa il goto nel nostro esempio, ovvero quando è usato bene (in realtà le eccezioni fanno qualcosa di più ma il concetto alla base è questo).

Concludo dicendo che il mio proposito non è quello di riabilitare il go to, che ha già perso la sua guerra negli anni 60, un uso sconsiderato porta a codice ingarbugliato difficile da decifrare (spaghetti code) anche per l’autore stesso, tuttavia esistono casi in cui il suo uso è ancora  legittimo. Ancora più importante, è sottolineare che nella programmazione, (come in qualsiasi attività umana) applicare le regole alla cieca spesso non è sufficiente per ottenre un risultato soddisfacente, non bisogna accettare ogni regola come un dogma, ma capire quali sono le motivazioni che hanno portato alla sua introduzione, e quali sono i suoi limiti di applicabilità.

 

email
Related Posts Plugin for WordPress, Blogger...

Non perdere l'opportunità di ricevere il meglio di Ziogeek!


Commenti


Fatal error: Uncaught Exception: 12: REST API is deprecated for versions v2.1 and higher (12) thrown in /home/ziogeek/public_html/wp-content/plugins/seo-facebook-comments/facebook/base_facebook.php on line 1273