Il Goto E La Buona Programmazione [Parte II]

spaghetti code

Ho iniziato a parlarvi nell’articolo di ieri riguardo alla prima volta che ho cercato di adattare un driver del kernel di linux alle mie esigenze, e mi sono trovato davanti a goto, ho subito pensato di riscrivere la funzione in maniera strutturata. Infatti, 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.

© 2008 Ziogeek.com

Tag: ,