<?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; Ingegneria del software</title>
	<atom:link href="http://www.micheledellatorre.net/category/informatica/ingegneria-del-software/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.micheledellatorre.net</link>
	<description>Informatica in moto</description>
	<lastBuildDate>Tue, 27 Jul 2010 21:04:59 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</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>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>
	</channel>
</rss>
