Archive

Posts Tagged ‘codice’

fare del buon codice!

September 20, 2009 Leave a comment

Nell’ultimo  mese ho approfondito la mia conoscenza sull’erlang leggendo l’ottimo libro ERLANG Programming di Francesco Cesarini. Il libro (in inglese) è davvero ottimo, pieno di esempi e di consigli per chi vuole imparare/migliorare erlang.

 



Tra i capitoli che ho letto con particolare attenzione c’è il numero 20 “Style and Efficiency” che da alcuni consigli su come scrivere del buon codice.

Una guida più o meno tale può essere trovata sulle pagine web ufficiali. Scorrendole pagine del libro e quelle online ho scoperto alcuni dei miei errori, che vado ad elencarvi.

1) Nested case: 

Un nested case consiste in istruzioni case/if/receive che contengono altre istruzioni case/if/receive. E’ veramente una pessima abitudine scrivere nested code con profondità superiore a 2, in quanto il codice tende a “spostarsi” rapidamente verso la destra della pagina diventando in fretta illeggibile.  Ecco un esempio di deep nested code, seguito da una soluzione migliore (almeno spero 🙂 !). Tale codice dovrebbe rappresentare una porta logica and che prende come ingressi due valori provenienti da altrettante porte logiche.

Result1 = get_first_result(),
Resutl2 = get_second_resutl(),

TotalResult = case Result1 of
		  {result, true} ->
		      case Result2 of
			  {result, true} ->
			      {result, true};
			  {result, false} ->
			      {result, false}
		      end;
		  {result, false} ->
		      {result, false}
	      end.

Come potete notare questo codice ha profondità 2 (ci sono due case), ma cosa accadrebbe se gli ingressi fossero 3 o 4? Il numero di case salirebbe in modo proporzionale, rendendo il codice alquanto illeggibile.

Cerchiamo di riscrivere tale codice in modo un pò più ordinato.

Result1 = get_first_result(),
Resutl2 = get_second_resutl(),

TotalResult = case {Result1, Result2} of
		  {{result, true}, {result, true}} ->
		      {result, true};
		  {{result, false}, {result, true}} ->
		      {result, false};
		  {{result, true}}, {result, false} ->
		      {result, false};
		  {{result, false}}, {result, false} ->
		      {result, false}
	      end.

In questo caso abbiamo creato una tupla formata da due elementi, il primo e il secondo risultato. Possiamo vedere che in questo caso il codice non tende a spostarsi verso destra…certo è vero che in questo caso a due soli ingressi il codice con i nested case sembra più facile, ma questo è solo un esempio! Inoltre se notate in entrambe le implementazioni non ho utilizzato il don’t care..se lo avessi fatto, dopo il primo case nella seconda implementazione, avrei potuto ritornare subito un {result, false} ma ciò introduce il concetto di programmazione difensiva.

2) Programmazione difensiva:

Con il nome “programmazione difensiva” si identificata quel tipo di codice in cui il programmatore non si fida degli ingressi che il suo codice deve gestire. Generalmente invece, ci si dovrebbe fidare degli ingressi e non testarli. A mio avviso ciò è vero in quanto se gestite i vostri codici con parecchi don’t care, rischiate di non accorgervi di errori che altrimenti diverrebbero palesi. Supponiamo ad esempio che nel vostro codice dobbiate registrare una certa funzione dopo un spawn_link con un atom che viene fornito come ingresso. Potreste controllare se il valore in ingresso è veramente un atom:

spawn_and_register(Name) ->
    case is_atome(Name)
	true ->
	    register(spawn_link(Name, fun() ->
					      loop()
				      end));
	false ->
	    io:print("no atom~n", [])
    end.

Oppure potreste semplicemente fidarvi del fatto che il valore in ingresso sia un atom, poi se qualcosa va storto il codice genera un errore e così trovate il punto che chiama la vostra funzione nel modo sbagliato!

spawn_and_register(Name) ->
	    register(spawn_link(Name, fun() ->
					      loop()
				      end)).

Io di mio sto ancora imparando, quindi tutto ciò che vi dico cercate di approfondirlo da voi!