<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>micheledellatorre.net &#187; Informatica</title>
	<atom:link href="http://www.micheledellatorre.net/category/informatica/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.micheledellatorre.net</link>
	<description>Informatica in moto</description>
	<lastBuildDate>Sat, 21 Aug 2010 10:37:41 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.1.2</generator>
		<item>
		<title>Ottimizzazione codice tra JVM diverse</title>
		<link>http://www.micheledellatorre.net/2008/06/29/ottimizzazione-codice-tra-jvm-diverse/</link>
		<comments>http://www.micheledellatorre.net/2008/06/29/ottimizzazione-codice-tra-jvm-diverse/#comments</comments>
		<pubDate>Sun, 29 Jun 2008 19:53:11 +0000</pubDate>
		<dc:creator>Michele Della Torre</dc:creator>
				<category><![CDATA[Informatica]]></category>
		<category><![CDATA[Ingegneria del software]]></category>

		<guid isPermaLink="false">http://www.micheledellatorre.net/?p=25</guid>
		<description><![CDATA[Capita davvero di rado di avere problemi di prestazioni e quindi quando capita è un evento talmente eccezionale che merita uno studio approfondito. Prima di entrare nei dettagli del codice e della soluzione, faccio una breve introduzione al problema. L&#8217;applicazione in oggetto è un sistema di controllo domotico relativamente semplice, infatti il compito richiesto è [...]]]></description>
			<content:encoded><![CDATA[<p>Capita davvero di rado di avere problemi di prestazioni e quindi quando capita è un evento talmente eccezionale che merita uno studio approfondito.</p>
<p>Prima di entrare nei dettagli del codice e della soluzione, faccio una breve introduzione al problema.<br />
L&#8217;applicazione in oggetto è un sistema di controllo domotico relativamente semplice, infatti il compito richiesto è il coordinamento della sola parte audio e video, senza altri tipi di integrazione.<br />
Il controllo dei sistemi audio e video è un problema che ricorre in tutti gli impianti realizzati dall&#8217;azienda in cui lavoro attualmente, quindi per accelerare i tempi ho scritto un framework in Java in modo tale che tutte le problematiche ricorrenti vengano gestite nel modo più automatico possibile.; tale framework è abbastanza complesso perchè ogni impianto è fatto ad hoc per ogni cliente e quindi si ha una grande varietà di classi in grado di risolvere i problemi tipici.<span id="more-25"></span></p>
<p>Nell&#8217;ultima installazione, sebbene i singoli compiti fossero confinati al controllo dell&#8217;audio e del video, si aveva per la prima volta un insieme piuttosto vasto di apparecchi; in altri termini la singola stanza è semplice, ma quello che è elevato è il numero delle stanze stesse.<br />
La centrale di controllo si interfaccia con i dispositivi o tramite una delle sue porte seriali oppure tramite una connessione IP.<br />
Al momento del test dell&#8217;impianto è stato evidente che in alcuni casi le cose non andavano come previsto: la centrale di controllo inviava effettivamente i comandi, il dispositivo rispondeva in tempi brevissimi, ma l&#8217;applicativo di controllo vedeva la risposta solo dopo un po&#8217;, a volte il ritardo era anche di alcuni secondi.</p>
<p>Era necessario capire il problema e trovare la soluzione.<br />
Avevamo due indizi fondamentali: il primo erano tutti gli impianti fatti in precedenza, anche più grandi di quello in oggetto e scritti nel linguaggio di programmazione proprietario della centrale, che hanno sempre funzionato senza problemi e che le connessioni seriali non davano alcun problema di sorta.<br />
La conclusione era abbastanza evidente: per qualche motivo c&#8217;era un problema sulla ricezione di pacchetti IP dall&#8217;applicativo Java&#8230; ma dove?<br />
Gli indagati erano 3:</p>
<ol>
<li>Il framework nella sua completezza</li>
<li>la gestione delle connessioni IP a livello applicativo</li>
<li>la JVM e il sistema operativo della centrale</li>
</ol>
<p>Il framework nella sua completezza non sembrava il responsabile, visto che gestisce senza alcun rallentamento le connessione seriali, quindi il problema era o nelle connessioni IP a livello applicativo o in uno degli strati a cui si appoggia, ma sul campo non avevo modo di capirlo, infatti se la regola numero uno dell&#8217;ottimizzazione è</p>
<blockquote><p>Non ottimizzare</p></blockquote>
<p>la seconda è</p>
<blockquote><p>Misurare, non tirare a indovinare</p></blockquote>
<p>quindi sono tornato in ufficio e con calma mi sono messo a lavorare sulle connessioni IP a livello applicativo, che erano l&#8217;unica possibilità per me di migliorare la situazione: un rallentamento a livello di JVM o di sistema operativo infatti non sarebbero stato risolvibili da me direttamente.</p>
<p>L&#8217;ambiente di test che ho realizzato è stato molto semplice: due connessioni TCP/IP su socket locale che si scambiano dati secondo un protocollo banale, cioè un processo inviava dei dati all&#8217;altro che li rispediva indietro (in sostanza una delle due parti è un echo server).<br />
Usando il profiler di Netbeans scopro che la maggior parte del tempo viene passata nella funzione di lettura dei dati da socket, questo mi ha dato due indicazioni importanti:</p>
<ol>
<li>il problema probabilmente era lì: il campo di ricerca si era ridotto</li>
<li>la lettura però è bloccante, quindi è ragionevole che si passi molto tempo in quel metodo</li>
</ol>
<p>Il metodo di lettura da socket è qualcosa di questo tipo:</p>
<p><code>public String read() throws IOException {</p>
<p>  char[] buffer = new char[BUFFER_SIZE];</p>
<p>  int length = reader.read(buffer);</p>
<p>  // qualche check sui dati</p>
<p>  return new String(buffer, 0, length);<br />
}</p>
<p></code><br />
Il modo di procedere è stato analizzare i 4 blocchi lo compongono: ho cercato una soluzione più veloce per ogni parte confrontando i dati con quelli del caso base.<br />
I check e la creazione della stringa in pratica non hanno impatto sulle prestazioni, così come la sostituzione del bufferedReader usato per incapsulare il socket con qualcosa di più leggero, mentre riciclando il buffer al posto di ricrearlo ad ogni invocazione le performance sono migliorate di un 40% abbondante, che è un ottimo incremento, superiore alle mie aspettative, infatti sarei stato pronto a scommettere che il collo di bottiglia fosse sulla lettura e non lì: ecco perchè è importante misurare sempre quando si ottimizza, lasciando in disparte il proprio intuito. </p>
<p>Molto soddisfatto di quanto ottenuto, modifico anche il programma che sulla centrale e lo provo: con immensa sorpresa noto che l&#8217;incremento di prestazioni è qualcosa si eccezionale, oserei dire mostruoso. Giusto per dare qualche dato, sul mio pc si passa da 25 secondi a 14 per l&#8217;esecuzione di un certo numero di test, sulla centrale di controllo (con un numero di test diversi rispetto a quelli del pc, quindi i dati non sono confrontabili direttamente) da 209 secondi a 10!!! Un miglioramento di 20 volte è a dir poco incredibile.<br />
La motivazione risiede nella JVM usata: su pc ho una Sun ufficiale ultima versione (1.6 con tutti gli aggiornamenti), mentre sulla centrale vi è una JVM non meglio definita capace di far girare J2ME (quindi 1.4).</p>
<p>Le conclusioni sono semplici:</p>
<ol>
<li>L&#8217;ottimizzazione fa effettuata solo quando vi è una forte evidenza della sua necessità</li>
<li>Codice semplice, modulare e leggibile è da preferire sempre perchè rende più semplice l&#8217;eventuale sua ottimizzazione</li>
<li>Non fidarsi mai del proprio intuito, è decisamente meglio affidarsi ad un profiler</li>
<li>Se è stata effettuata una modifica che non ha apportato miglioramenti significativi, ritornare alla versione originale del codice se ne è stata compromessa la leggibilità</li>
<li>Prestare grandissimi attenzione se si sta effettuando sviluppo multipiattaforma o cross-piattaforma: assicurarsi sempre che i miglioramenti siano evidenti anche per la piattaforma su cui si andrà in produzione: spesso le virtual machine e i compilatori sono in grado di aumentare le prestazioni molto più di quanto si creda</li>
</ol>
]]></content:encoded>
			<wfw:commentRss>http://www.micheledellatorre.net/2008/06/29/ottimizzazione-codice-tra-jvm-diverse/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Ruby: prime sensazioni</title>
		<link>http://www.micheledellatorre.net/2008/05/24/ruby-prime-sensazioni/</link>
		<comments>http://www.micheledellatorre.net/2008/05/24/ruby-prime-sensazioni/#comments</comments>
		<pubDate>Sat, 24 May 2008 13:13:03 +0000</pubDate>
		<dc:creator>Michele Della Torre</dc:creator>
				<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false">http://www.micheledellatorre.net/?p=23</guid>
		<description><![CDATA[Come ho scritto qualche tempo fa, ho iniziato a giocare un po&#8217; con Ruby, cercando di realizzare un piccolo gioco. Il primo approccio non è stato dei più felici. Ruby è un linguaggio dinamico che sfrutta la tipizzazione dinamica, quindi può essere modificato a runtime il comportamento di una classe e non vi sono controlli sul tipo a [...]]]></description>
			<content:encoded><![CDATA[<p>Come ho scritto qualche tempo fa, ho iniziato a giocare un po&#8217; con Ruby, cercando di realizzare un piccolo gioco.<br />
Il primo approccio non è stato dei più felici.<span id="more-23"></span></p>
<p>Ruby è un linguaggio dinamico che sfrutta la tipizzazione dinamica, quindi può essere modificato a runtime il comportamento di una classe e non vi sono controlli sul tipo a compile-time.<br />
Queste due caratteristiche danno una flessibilità incredibile al linguaggio, ad esempio pensate di avere a che fare con un&#8217;applicazione in cui i numeri devono essere trasmessi sulla rete con una codifica particolare a 16 bit; con un linguaggio come Java svilupperemo un metodo con la seguente signature</p>
<pre>public static byte[] encodeFloat(float f)</pre>
<p>ma non è molto &#8220;object oriented&#8221; come soluzione, in Ruby è possibile aggiungere il metodo encode direttamente alla classe numerica, arrivando poi a scrivere codice del tipo</p>
<pre>socket.sendData( 10.encode )</pre>
<p>che è sicuramente più pulito.</p>
<p>Tutta questa flessibilità però ha un prezzo molto salato,infatto il compilatore non è più un nostro alleato e si finisce col perdere tantissimo tempo alla ricerca di un errore comune come la scrittura errata del nome di una variabile o di un suo metodo. Il fatto più irritante è che questo problema può essere evidenziato solo dopo molto tempo. Prendiamo il seguente esempio in pseudocodice:</p>
<pre>numero = random(10000)
if (numero &gt; 0) 
    risultato = log(numero).toString()
else
    risultato = numro.toString()</pre>
<p>in un linguaggio come Java o C# si viene segnalato subito che nell&#8217;ultima riga abbiamo sbagliato a scrivere il nome della variabile, mentre in Ruby ce ne accorgiamo solo quando viene eseguito quel ramo di codice, ma è evidente che la probabilità è molto bassa.</p>
<p>Il test diviene quindi fondamentale visto che deve prendersi carico anche dei compiti che normalmente vengono eseguiti dal compilatore, quindi una metodologia test first è praticamente obbligatoria (tant&#8217;è che Ruby ha integrato un framework di test simile a JUnit).</p>
<p>Preso singolarmente questa mancanza non sembrerebbe quindi così grave: chi, come me, scrive sempre i test prima del codice non ha particolari problemi. Peccato che non sia vero.<br />
Tanto per cominciare il compilatore è davvero comodo, cioè ci fa risparmiare tempo, per alcuni tipi di modifiche: ad esempio supponiamo di esserci resi conto che una certa classe è inutile e perchè può essere sostituita con una classe fornita da una libreria. La cosa più rapida è cancellare la vecchia classe, guardare quali sono i file che non compilano più e modificarli: con un IDE come Eclipse l&#8217;operazione è davvero molto veloce, visto che con un semplice doppio click sull&#8217;errore si viene rimandati dalla riga corrispondente.<br />
In Ruby invece bisogna continuare a lanciare i test finchè la barra non è verde&#8230; insomma, è un lavoro decisamente più lungo, specialmente se i test non riescono a darci un&#8217;idea precisa di dove sia l&#8217;errore.</p>
<p>Il secondo limite, ben più grave, è in sede di refactoring, specialmente per quelli molto comuni come la rinominazione di un metodo o una variabile visto che la mancanza di tipizzazione statica non fornisce alcun indizio al motore di refactoring stesso (tant&#8217;è che Netbeans ci obbliga a vedere la preview e accettarla).</p>
<p>Dalla mia breve esperienza, posso dire che Ruby è ottimo quando si devono scrivere programmi relativamente piccoli in tempi rapidi, mentre mi affiderei ad un linguaggio con un numero maggiori di controlli a compile time, come Java o C#, per programmi più vasti o critici.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.micheledellatorre.net/2008/05/24/ruby-prime-sensazioni/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Suite di test in Ruby</title>
		<link>http://www.micheledellatorre.net/2008/04/14/suite-di-test-in-ruby/</link>
		<comments>http://www.micheledellatorre.net/2008/04/14/suite-di-test-in-ruby/#comments</comments>
		<pubDate>Mon, 14 Apr 2008 20:12:58 +0000</pubDate>
		<dc:creator>Michele Della Torre</dc:creator>
				<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false">http://www.micheledellatorre.net/?p=15</guid>
		<description><![CDATA[Una della basi per poter effettuare il refactoring in modo sicuro e tranquillo è l&#8217;avere a disposizione un insieme di test sufficientemente grande da lanciare molto spesso per verificare che il lavoro svolto non abbia introdotto errori. Utilizzando Java ed Eclipse è molto semplice lanciare tutti i test di un progetto, basta cliccare con il [...]]]></description>
			<content:encoded><![CDATA[<p>Una della basi per poter effettuare il refactoring in modo sicuro e tranquillo è l&#8217;avere a disposizione un insieme di test sufficientemente grande da lanciare molto spesso per verificare che il lavoro svolto non abbia introdotto errori.<br />
Utilizzando Java ed Eclipse è molto semplice lanciare tutti i test di un progetto, basta cliccare con il pulsante destro sul progetto e selezionare &#8220;run as&#8230; JUnit test&#8221;, ma con Netbeans e Ruby non è così immediato: è infatti necessario creare una suite di test, cioè un insieme di test cases che quando lanciato esegue tutti i test contenuti.</p>
<p><span id="more-15"></span>In Java questo è un tipico caso di Composite, mentre in Ruby è possibile sfruttare la sua capacità di eseguire altri file in modo molto semplice a runtime grazie alla funzione require.</p>
<p>Il modo più semplice di procedere è usare una qualche convenzione per il nome dei singoli file di test, io, ad esempio, chiamo foo_test.rb il file che contiene i test della classe foo.rb.<br />
Ora, ricordandosi che la require non è una direttiva del compilatore, ma una vera e propria funzione, è possibile richiamarla all&#8217;interno di un semplice ciclo che scorre tutti i file della directory il cui nome matcha il pattern *_test.rb:</p>
<blockquote>
<pre>Dir.glob("../test/*_test.rb").each do |file|
  require file
end</pre>
</blockquote>
<p>Notare che la glob ritorna un insieme di stringhe e non di file, quindi è possibile passare direttamente ogni elemento alla require senza altre forme di processamento.</p>
<p>Lascio a voi per esercizio l&#8217;implementazione dello script che esegue anche i test delle sottocartelle :p</p>
]]></content:encoded>
			<wfw:commentRss>http://www.micheledellatorre.net/2008/04/14/suite-di-test-in-ruby/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Ruby Tower Defense &#8211; strumenti</title>
		<link>http://www.micheledellatorre.net/2008/04/05/ruby-tower-defense-strumenti/</link>
		<comments>http://www.micheledellatorre.net/2008/04/05/ruby-tower-defense-strumenti/#comments</comments>
		<pubDate>Sat, 05 Apr 2008 20:24:49 +0000</pubDate>
		<dc:creator>Michele Della Torre</dc:creator>
				<category><![CDATA[Ruby]]></category>

		<guid isPermaLink="false">http://www.micheledellatorre.net/2008/04/05/ruby-tower-defense-strumenti/</guid>
		<description><![CDATA[In &#8220;Extreme Programming Adventures in C#&#8221; ho apprezzato soprattutto lo spirito di Ron Jeffries che voleva scrivere un editor XML in C# senza avere una conoscenza approfondita del linguaggio. Io mi sono messo in testa di imparare Ruby, giusto per avere un punto di vista differente da quello di Java senza cambiare completamente paradigma di [...]]]></description>
			<content:encoded><![CDATA[<p>In &#8220;Extreme Programming Adventures in C#&#8221; ho apprezzato soprattutto lo spirito di Ron Jeffries che voleva scrivere un editor XML in C# senza avere una conoscenza approfondita del linguaggio.<br />
Io mi sono messo in testa di imparare Ruby, giusto per avere un punto di vista differente da quello di Java senza cambiare completamente paradigma di programmazione; seguendo le orme di Jeffries proverò a scrivere un piccolo gioco della serie &#8220;Tower defense&#8221;, che tanto apprezzo, in Ruby.</p>
<p>Premetto subito che il mio scopo non è fare il gioco, ma imparare un po&#8217; il linguaggio, quindi sono conoscio che il gioco potrebbe non vedere la mai la luce, ma in fondo non è problema grave dal mio punto di vista: se per qualcuno di voi lo è può sempre darmi una mano <img src='http://www.micheledellatorre.net/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>Ruby è un linguaggio orientato agli oggetti completamente dinamico, a prima vista sembra ottima l&#8217;idea di poter, ad esempio, aggiungere un metodo ad una classe a runtime, ma se a questo aggiungiamo il fatto che Ruby è interpretato si capisce subito che non si ha un compilatore che ci fa notare alcuni errori. I test quindi hanno un valore ancora più elevato perchè devono essere loro a farci notare i problemi che normalmente sono rilevabili staticamente, perciò userò un approccio TDD (sai che novità, ormai lo uso per tutto!).<br />
Come ambiente di sviluppo non mi sento di usare un normale editor di testo: qualcuno sostiene che facendo tutto a mano si impara di più, ma sicuramente si perde molto più tempo; avendo già scritto qualche programmino di esempio senza un IDE credo di avere almeno un&#8217;idea dei fondamentali e quindi mi sono orientato su Netbeans 6.0.1 che possiede il supporto per Ruby.<br />
Mi appoggerò alla libreria Rubygame, che è un framework per lo sviluppo di giochi in, nemmeno a dirlo, Ruby.</p>
<p>Ora, facciamo due conti: conosco giusto le basi di Ruby, ho letto due tutorial su Rubygame e normalmente non uso Netbeans&#8230; non sembra di certo il miglior modo di partire, ma in fondo sono fiducioso: come ho già detto il mio obiettivo è imparare il linguaggio, quindi non sarà una tragedia che il gioco non sarà mai terminato e comunque credo di avere delle buone basi per tirare fuori qualcosa.</p>
<p>Appena ho scritto un po&#8217; di codice significativo lo posto.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.micheledellatorre.net/2008/04/05/ruby-tower-defense-strumenti/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>La lavagna parte seconda</title>
		<link>http://www.micheledellatorre.net/2008/04/05/la-lavagna-parte-seconda/</link>
		<comments>http://www.micheledellatorre.net/2008/04/05/la-lavagna-parte-seconda/#comments</comments>
		<pubDate>Sat, 05 Apr 2008 20:20:52 +0000</pubDate>
		<dc:creator>Michele Della Torre</dc:creator>
				<category><![CDATA[Informatica]]></category>

		<guid isPermaLink="false">http://www.micheledellatorre.net/2008/04/05/la-lavagna-parte-seconda/</guid>
		<description><![CDATA[Il mio primo post è stato dedicato all&#8217;uso della lavagna per lo sviluppo software: ora è finito l&#8217;esaltamento iniziale dello vedere il nuovo pannello appeso al muro dell&#8217;ufficio ed è il caso di tirare le prime somme. Io seguo la metodologia di sviluppo TDD che non prevede una fase di design iniziale, ma il design [...]]]></description>
			<content:encoded><![CDATA[<p>Il mio primo post è stato dedicato all&#8217;uso della lavagna per lo sviluppo software: ora è finito l&#8217;esaltamento iniziale dello vedere il nuovo pannello appeso al muro dell&#8217;ufficio ed è il caso di tirare le prime somme.</p>
<p>Io seguo la metodologia di sviluppo TDD che non prevede una fase di design iniziale, ma il design deve &#8220;nascere&#8221; in base alle esigenze del progetto e da quello che il codice comunica. Prima o poi tornerò sull&#8217;argomento.<br />
Devo dire che per quello che rigurda il design di dettaglio, cioè la struttura di una o poche classi, il design emergente è effettivamente quello che dà i risultati migliori; quando ho provato ad applicare un approccio classico disegnando sulla lavagna un diagramma UML i risultati non sono stati altrettanto soddisfacenti.<br />
Il problema fondamentale è che un diagramma delle classi rappresenta molto bene le relazioni tra le entità, ma non riesce a fornire alcuna indicazione su come saranno le interazioni tra di esse; prima di scrivere il codice si ha solo un&#8217;indicazione e durante la fase di implementazione rimane molto difficile, soprattutto psicologicamente, modificare o rivedere un diagramma che sulla carta (o sulla lavagna) risulta così ben equilibrato e ragionevole.</p>
<p>Per la progettazione di algoritmi invece la lavagna è uno strumento comodissimo, in particolare per quelli concorrenti che non possono essere facilmente sviluppati a partire dai test.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.micheledellatorre.net/2008/04/05/la-lavagna-parte-seconda/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Siamo uguali?</title>
		<link>http://www.micheledellatorre.net/2008/01/17/siamo-uguali/</link>
		<comments>http://www.micheledellatorre.net/2008/01/17/siamo-uguali/#comments</comments>
		<pubDate>Thu, 17 Jan 2008 20:43:56 +0000</pubDate>
		<dc:creator>Michele Della Torre</dc:creator>
				<category><![CDATA[Informatica]]></category>
		<category><![CDATA[Ingegneria del software]]></category>

		<guid isPermaLink="false">http://www.micheledellatorre.net/2008/01/17/siamo-uguali/</guid>
		<description><![CDATA[Ci sono argomenti di ingegneria del software che inizialmente sembrano semplici, ma poi ragionandoci sopra ci si rende conto che non è proprio così: l&#8217;uguaglianza tra oggetti è uno di questi. La domanda sembra banale: sotto quali condizioni un oggetto a è uguale ad un oggetto b? In termini formali l&#8217;uguaglianza è una relazione riflessiva, transitiva e [...]]]></description>
			<content:encoded><![CDATA[<p>Ci sono argomenti di ingegneria del software che inizialmente sembrano semplici, ma poi ragionandoci sopra ci si rende conto che non è proprio così: l&#8217;uguaglianza tra oggetti è uno di questi.</p>
<p>La domanda sembra banale: sotto quali condizioni un oggetto a è uguale ad un oggetto b?<span id="more-9"></span></p>
<p>In termini formali l&#8217;uguaglianza è una relazione riflessiva, transitiva e simmetrica; le specifiche di Java richiedono anche che sia consistente, cioè che il risultato dell&#8217;operazione rimanga lo stesso purchè nessuna informazione usata nella comparazione venga modificata: in altri termini due oggetti il cui stato non viene modificato devono essere sempre uguali o sempre diversi.<br />
In Java, e in molti linguaggi OO, esiste una strettissima relazione tra l&#8217;equals e l&#8217;hash code: due oggetti uguali devono avere lo stesso hash code, inoltre quest&#8217;ultimo non deve cambiare se non ci sono cambiamenti nello stato.</p>
<p>Oggetti immutabili non pongono particolari problemi, mentre per quelli mutabili la situazione è più complicata (altrimenti questo post non avrebbe nemmeno molto senso <img src='http://www.micheledellatorre.net/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' />  ).</p>
<p>Fondalmentalmente esistono due scuole di pensiero: la prima dice che due oggetti devono essere sempre uguali o sempre diversi per tutta la durata dell&#8217;applicazione, la seconda invece permette variazioni nel risultato.<br />
Nelle API di Java si adotta spesso il secondo approccio, ad esempio per la classe <a target="_blank" href="http://java.sun.com/javase/6/docs/api/java/util/Calendar.html">Calendar </a>(che comunque non rimane un esempio di design da seguire&#8230;), ma questo crea problemi tutte le volte in cui si indicizza qualcosa tramite hash code, come nelle HashMap o HashSet e in generale nei Set, tant&#8217;è che nella javadoc si trova questa frase:</p>
<blockquote><p>Note: Great care must be exercised if mutable objects are used as set elements. The behavior of a set is not specified if the value of an object is changed in a manner that affects <tt>equals</tt> comparisons while the object is an element in the set.</p></blockquote>
<p>Per evitare questi problemi si può seguire l&#8217;approccio opposto, cioè sostenere che se due oggetti sono uguali, allora lo sono per sempre e che se sono diversi allora lo sono per sempre. E&#8217; possibile spingersi oltre e dire che deve valere l&#8217;uguaglianza comportamentale, cioè che due o più oggetti sono uguali allora non è possibile distinguerli richiamando in un ordine qualsiasi i loro metodi. Questo è l&#8217;approccio consigliato da Liskov.<br />
La diretta conseguenza è piuttosto radicale: due oggetti mutabili sono uguali solo se sono lo stesso oggetto, quindi il metodo equals non deve essere ridefinito, così come il metodo hashCode.</p>
<p>In <a target="_blank" href="http://www.refactoring.com/">Refactoring</a> <a target="_blank" href="http://martinfowler.com/">Martin Fowler</a> fa una classificazione decisamente interessante in questo senso: ci sono oggetti dei quali ci interessa il valore e oggetti di cui ci interessa l&#8217;identità. Fanno parte della prima categoria ad esempio le date e la valuta: in questo caso andrebbero implementati come oggetti immutabili con l&#8217;override di equals; appartengono alla seconda categoria ad esempio le persone dove il reale interesse è legato all&#8217;identità: istanze mutabili sono quindi legittime, ma potrebbe essere necessario introdurre una factory per garantire che l&#8217;esistenza di una singola istanza quando si richiede lo stesso oggetto in punti diversi del programma.</p>
<p>Inizialmente ero molto scettico riguardo a questa definizione di uguaglianza, ma poi ho iniziato a seguirla in modo metodico e devo ammettere che funziona molto bene. Non vi è una grande perdita di libertà nell&#8217;implementazione, ma se ne guadagna parecchio in chiarezza del design: ogni volta che mi trovo a creare una nuova classe mi chiedo se sono interessato al valore o all&#8217;identità, prendendo poi le decisioni del caso.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.micheledellatorre.net/2008/01/17/siamo-uguali/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>La lavagna</title>
		<link>http://www.micheledellatorre.net/2008/01/13/la-lavagna/</link>
		<comments>http://www.micheledellatorre.net/2008/01/13/la-lavagna/#comments</comments>
		<pubDate>Sun, 13 Jan 2008 19:47:04 +0000</pubDate>
		<dc:creator>Michele Della Torre</dc:creator>
				<category><![CDATA[Informatica]]></category>

		<guid isPermaLink="false">http://www.micheledellatorre.net/2008/01/13/la-lavagna/</guid>
		<description><![CDATA[Tra i tantissimi strumenti che si usano per la progettazione e lo sviluppo del software, il mio preferito è sicuramente la lavagna, tant&#8217;è che sono giunto alla conclusione che non si sta facendo nulla di complicato se non si sente la necessità di averne sempre una a portata di mano. La lavagna permette di scrivere [...]]]></description>
			<content:encoded><![CDATA[<p>Tra i tantissimi strumenti che si usano per la progettazione e lo sviluppo del software, il mio preferito è sicuramente la lavagna, tant&#8217;è che sono giunto alla conclusione che non si sta facendo nulla di complicato se non si sente la necessità di averne sempre una a portata di mano.</p>
<p>La lavagna permette di scrivere molto velocemente sia testo che diagrammi o formule matematiche, cosa che non accade stando davanti allo schermo di un computer, mantenendo un costo di correzione molto basso, utilissimo in fase di esplorazione delle possibili soluzioni; oltre a questo fattore tecnico, io apprezzo molto l&#8217;aspetto psicologico: la possibilità di fare due passi davanti al pannello e parlare guardando quando è stato scritto rende il processo più &#8220;vivo&#8221; e intenso, senza pesare troppo.</p>
<p>Strumenti del genere sono di grandissima utilità, ad esempio all&#8217;università mi capitava spesso di scrivere a matita sul tavolo specialmente durante le discussioni con il mio fido compagno di studi Mauro: bastava uno schema chiaro, per quanto abbozzato, per risolvere molti dubbi.</p>
<p>Se vogliamo ben vedere l&#8217;unico limite della lavagna è la mancanza del &#8220;copia/incolla&#8221; che sarebbe particolarmente apprezzabile quando ci si rende conto di dover spostare degli elementi da un punto all&#8217;altro, ad esempio durante la fase di posizionamento delle classi nei vari package: in certe occasioni può essere più comodo l&#8217;uso di <a target="_blank" href="http://en.wikipedia.org/wiki/Class-Responsibility-Collaboration_card">crc cards</a> o varianti&#8230; in attesa che tecnologie come <a target="_blank" href="http://www.microsoft.com/surface/">Surface di Microsoft</a> diventino di uso comune.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.micheledellatorre.net/2008/01/13/la-lavagna/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>

