AntonioGanci http://blogs.ugidotnet.org/AntonioGanci/Default.aspx Il blog di Antonio Ganci it-IT Antonio Ganci Subtext Version 2.6.0.0 AntonioGanci http://blogs.ugidotnet.org/images/RSS2Image.gif http://blogs.ugidotnet.org/AntonioGanci/Default.aspx 77 60 Pensare ad oggetti Extreme Programming http://blogs.ugidotnet.org/AntonioGanci/archive/2012/01/12/pensare-ad-oggetti.aspx <p> Ne avevo già parlato in un precedente <a href="http://blogs.ugidotnet.org/AntonioGanci/archive/2010/07/23/imparare-a-pensare-ad-oggetti.aspx">post</a>, ma provo ad illustrare altri aspetti che avevo ignorato. </p> <p> Una delle cose che viene data per scontato in XP è che si sappia pensare ad oggetti che è un prerequisito per il simple design. Ma cosa significa veramente? </p> <p> Nella programmazione tradizionale o formale un oggetto è dato dai suoi dati (attributi) e i metodi che agiscono su tali dati. Questo però porta ad un esplosione del numero di classi perché basta un solo dato diverso e devo creare una nuova classe. </p> <p> L'idea centrale del pensare ad oggetti sono i <b>comportamenti</b> cioè la decomposizione di un problema avviene individuando i comportamenti e assegnandoli agli oggetti. </p> <p> Ad esempio: prendiamo una tigre e un gatto nella programmazione formale ho una classe unica e due istanze diverse con i valori degli attributi diversi perché la tigre e il gatto hanno le stesse caratteristiche. Se pensiamo ad oggetti invece sono due classi diverse in quanto dalla tigre mi aspetto che mi aggredisca mentre un gatto è un animale domestico e quindi hanno diversi comportamenti. </p> <p> <b>Un modo utile per scoprire gli oggetti adatti a risolvere un problema è quello della metafora</b>, cioè cerco di capire se esiste un qualcosa di analogo nel mondo reale che si mappa con il mio problema. Bisogna tenere presente che la metafora è un modello del problema e quindi ci possono essere delle differenze. </p> <p> Ad esempio supponiamo di voler realizzare un sito per cercare un volo tra due destinazioni. Una metafora potrebbe essere quella dell'agenzia di viaggio a cui comunico dove voglio andare, in che data e mi viene fornito un catalogo con tutte le informazioni per poter scegliere il volo. </p> <p> Seguendo la metafora posso iniziare a disegnare l'oggetto agenzia di viaggio a cui mando il messaggio forniscimi il catalogo e gli passo una richiesta. A quel punto il risultato del messaggio puo' essere l'oggetto catalogo che contiene un elenco delle offerte e così via. </p> <p> Il punto cruciale è provare a fare una simulazione mentale o facendosi aiutare dai colleghi dell'interazione tra i vari oggetti per capire se il modello è adatto a risolvere la storia da realizzare. Quindi si ragiona nello spazio del problema o dominio e inizialmente si ignora la soluzione del problema, cioè la sua implementazione. </p> <p> Una volta individuati gli oggetti si può inziare l'implementazione utilizzando il TDD; ricordandosi che non sempre ad un oggetto di dominio corrisponde una classe, a volte puo' essere più di una a volte nessuna come nel caso in cui avessi creato, durante l'analisi, l'oggetto utente che fa la richiesta. </p> <p> Per approfondire l'argomento consiglio la lettura del libro <a href="http://www.amazon.com/Object-Thinking-DV-Microsoft-Professional-David/dp/0735619654">Object Thinking</a> di David West (ringrazio <a href="http://matteo.vaccari.name/blog/archives/675">Matteo</a> per la segnalazione). Mentre per gli effetti sulla produttività usando il TDD consiglio la lettura del post <a href="http://blog.8thlight.com/uncle-bob/2012/01/11/Flipping-the-Bit.html">Flipping the Bit</a> di Zio Bob. </p><img src="http://blogs.ugidotnet.org/AntonioGanci/aggbug/100696.aspx" width="1" height="1" /> Antonio Ganci http://blogs.ugidotnet.org/AntonioGanci/archive/2012/01/12/pensare-ad-oggetti.aspx Thu, 12 Jan 2012 20:08:46 GMT http://blogs.ugidotnet.org/AntonioGanci/archive/2012/01/12/pensare-ad-oggetti.aspx#feedback http://blogs.ugidotnet.org/AntonioGanci/comments/commentRss/100696.aspx http://blogs.ugidotnet.org/AntonioGanci/services/trackbacks/100696.aspx Accedere ad un database sqlite con Ruby Tips http://blogs.ugidotnet.org/AntonioGanci/archive/2012/01/02/accedere-ad-un-database-sqlite-con-ruby.aspx <p> In questo post vedremo come accedere ad un database <a href="http://www.sqlite.org/">sqlite</a> utilizzando Ruby. La scelta di sqlite è dovuta alla sua estrema semplicità di gestione, in quanto il database consiste in un unico file. </p> <p> Per prima cosa occorre installare una libreria per poterlo utilizzare da ruby. Basta digitare da terminale <code>gem install sqlite3-ruby</code>. </p> <p> Ora creiamo il file sqlite-test.rb con il seguente contenuto: </p> <pre style="color:#d1d1d1;background:#000000;"><span style="color:#e66170; font-weight:bold; ">require</span> <span style="color:#00c4c4; ">'sqlite3'</span> <span style="color:#e66170; font-weight:bold; ">require</span> <span style="color:#00c4c4; ">'test/unit'</span> <span style="color:#e66170; font-weight:bold; ">class</span> DatabaseTest &lt; Test::Unit::TestCase <span style="color:#e66170; font-weight:bold; ">def</span> setup @db <span style="color:#d2cd86; ">=</span> SQLite3::Database<span style="color:#d2cd86; ">.</span><span style="color:#e66170; font-weight:bold; ">new</span> <span style="color:#00c4c4; ">'test.db'</span> <span style="color:#e66170; font-weight:bold; ">end</span> <span style="color:#e66170; font-weight:bold; ">def</span> teardown @db<span style="color:#d2cd86; ">.</span>close <span style="color:#e66170; font-weight:bold; ">end</span> <span style="color:#e66170; font-weight:bold; ">def</span> test_create assert File<span style="color:#d2cd86; ">.</span>exist? <span style="color:#00c4c4; ">'test.db'</span> <span style="color:#e66170; font-weight:bold; ">end</span> <span style="color:#e66170; font-weight:bold; ">end</span> </pre> <p> </p> <p> Come si puo' vedere dal test il database consiste in un unico file test.db creato nella stessa directory. Se lanciamo il test abbiamo barra verde. </p> <p> Proviamo ora a creare una tabella e ad inserire alcuni dati. Aggiungiamo quindi il test: </p> <pre style="color:#d1d1d1;background:#000000;"><span style="color:#e66170; font-weight:bold; ">def</span> test_create_table sql <span style="color:#d2cd86; ">=</span> &lt;&lt;SQL create table names <span style="color:#d2cd86; ">(</span> id int primary key, name text <span style="color:#d2cd86; ">)</span>; SQL @db<span style="color:#d2cd86; ">.</span>execute sql assert_equal @db<span style="color:#d2cd86; ">.</span>execute<span style="color:#d2cd86; ">(</span><span style="color:#00c4c4; ">'select * from names'</span><span style="color:#d2cd86; ">)</span>, <span style="color:#d2cd86; ">[</span><span style="color:#d2cd86; ">]</span> <span style="color:#e66170; font-weight:bold; ">end</span> </pre> <p> </p> <p> Proviamo a lanciarlo: Barra verde. Se proviamo però a rilanciarlo otteniamo l'errore: <code>SQLite3::SQLException: table names already exists</code>. Per risolvere il problema cancelliamo la tabella, se esiste, prima di crearla utilizzando il comando: <code>drop table if exists names;</code>. Un'altra alternativa potrebbe essere la cancellazione del file di database. </p> <pre style="color:#d1d1d1;background:#000000;"><span style="color:#e66170; font-weight:bold; ">def</span> test_create_table sql <span style="color:#d2cd86; ">=</span> &lt;&lt;SQL drop table <span style="color:#e66170; font-weight:bold; ">if</span> exists names; create table names <span style="color:#d2cd86; ">(</span> id int primary key, name text <span style="color:#d2cd86; ">)</span>; SQL @db<span style="color:#d2cd86; ">.</span>execute_batch sql assert_equal @db<span style="color:#d2cd86; ">.</span>execute<span style="color:#d2cd86; ">(</span><span style="color:#00c4c4; ">'select * from names'</span><span style="color:#d2cd86; ">)</span>, <span style="color:#d2cd86; ">[</span><span style="color:#d2cd86; ">]</span> <span style="color:#e66170; font-weight:bold; ">end</span> </pre> <p> </p> <p> Notare che ho modificato execute con execute_batch perché altrimenti sarebbe stata eseguita solo una delle due query. </p> <p> A questo punto siamo pronti per inserire alcuni dati e verificare che siano presenti nella tabella </p> <pre style="color:#d1d1d1;background:#000000;"><span style="color:#e66170; font-weight:bold; ">def</span> test_create_table sql <span style="color:#d2cd86; ">=</span> &lt;&lt;SQL drop table <span style="color:#e66170; font-weight:bold; ">if</span> exists names; create table names <span style="color:#d2cd86; ">(</span> id int primary key, name text <span style="color:#d2cd86; ">)</span>; insert into names values<span style="color:#d2cd86; ">(</span><span style="color:#008c00; ">1</span>, <span style="color:#00c4c4; ">'a'</span><span style="color:#d2cd86; ">)</span>; insert into names values<span style="color:#d2cd86; ">(</span><span style="color:#008c00; ">2</span>, <span style="color:#00c4c4; ">'b'</span><span style="color:#d2cd86; ">)</span>; SQL @db<span style="color:#d2cd86; ">.</span>execute_batch sql assert_equal @db<span style="color:#d2cd86; ">.</span>execute<span style="color:#d2cd86; ">(</span><span style="color:#00c4c4; ">'select * from names'</span><span style="color:#d2cd86; ">)</span>, <span style="color:#d2cd86; ">[</span><span style="color:#d2cd86; ">[</span><span style="color:#008c00; ">1</span>, <span style="color:#00c4c4; ">'a'</span><span style="color:#d2cd86; ">]</span>, <span style="color:#d2cd86; ">[</span><span style="color:#008c00; ">2</span>, <span style="color:#00c4c4; ">'b'</span><span style="color:#d2cd86; ">]</span><span style="color:#d2cd86; ">]</span> <span style="color:#e66170; font-weight:bold; ">end</span> </pre> <p> </p> <p>Come si puo' leggere dal test i dati vengono restituiti come un array di array.</p> <p> Altre informazioni su come usare sqlite le potete trovare <a href=" http://sqlite-ruby.rubyforge.org/sqlite3/faq.html">qui</a> </p><img src="http://blogs.ugidotnet.org/AntonioGanci/aggbug/100670.aspx" width="1" height="1" /> Antonio Ganci http://blogs.ugidotnet.org/AntonioGanci/archive/2012/01/02/accedere-ad-un-database-sqlite-con-ruby.aspx Mon, 02 Jan 2012 19:04:40 GMT http://blogs.ugidotnet.org/AntonioGanci/archive/2012/01/02/accedere-ad-un-database-sqlite-con-ruby.aspx#feedback 2 http://blogs.ugidotnet.org/AntonioGanci/comments/commentRss/100670.aspx http://blogs.ugidotnet.org/AntonioGanci/services/trackbacks/100670.aspx Sviluppare un sito web in TDD usando Ruby e Sinatra Tips http://blogs.ugidotnet.org/AntonioGanci/archive/2011/12/28/sviluppare-un-sito-web-in-tdd-usando-ruby-e-sinatra.aspx <p> In questo post illustrerò un modo per sviluppare un sito web che usa Sinatra usando la pratica del TDD. Per poter provare gli esempi occorre aver seguito i passi del mio precedente <a href="http://blogs.ugidotnet.org/AntonioGanci/archive/2011/12/27/primi-passi-con-sinatra.aspx">post</a>. </p> <p> Sinatra, come altri framework scritti in Ruby, aderisce allo standard <a href="http://rack.rubyforge.org/">Rack</a>. In sintesi basta realizzare un oggetto che risponde al messagio call, prende un hash come parametro e risponde con un vettore di tre elementi: lo status code, l'header http e il body. </p> <p> Un esempio di un oggetto che rispetta lo standard è: </p> <pre style="color:#d1d1d1;background:#000000;"><span style="color:#e66170; font-weight:bold; ">class</span> HelloWorld <span style="color:#e66170; font-weight:bold; ">def</span> call<span style="color:#d2cd86; ">(</span>env<span style="color:#d2cd86; ">)</span> <span style="color:#d2cd86; ">[</span><span style="color:#008c00; ">200</span>, <span style="color:#b060b0; ">{</span><span style="color:#00c4c4; ">"Content-Type"</span> <span style="color:#d2cd86; ">=</span>&gt; <span style="color:#00c4c4; ">"text/plain"</span><span style="color:#b060b0; ">}</span>, <span style="color:#d2cd86; ">[</span><span style="color:#00c4c4; ">"Hello world!"</span><span style="color:#d2cd86; ">]</span><span style="color:#d2cd86; ">]</span> <span style="color:#e66170; font-weight:bold; ">end</span> <span style="color:#e66170; font-weight:bold; ">end</span> </pre> <p> </p> <p> Questo ha il vantaggio di avere degli oggetti già pronti per poter scrivere i test. Prima occorre da terminale eseguire il comando: <code>gem install rack-test</code> in modo da installare tutto ciò che ci serve. </p> <p> A questo punto siamo pronti a scrivere il nostro primo test (il file l'ho chiamato sitetest.rb): </p> <pre style="color:#d1d1d1;background:#000000;"><span style="color:#e66170; font-weight:bold; ">require</span> <span style="color:#00c4c4; ">'./site'</span> <span style="color:#e66170; font-weight:bold; ">require</span> <span style="color:#00c4c4; ">'test/unit'</span> <span style="color:#e66170; font-weight:bold; ">require</span> <span style="color:#00c4c4; ">'rack/test'</span> <span style="color:#e66170; font-weight:bold; ">class</span> SiteTest &lt; Test::Unit::TestCase <span style="color:#e66170; font-weight:bold; ">def</span> test_homepage browser <span style="color:#d2cd86; ">=</span> Rack::Test::Session<span style="color:#d2cd86; ">.</span><span style="color:#e66170; font-weight:bold; ">new</span><span style="color:#d2cd86; ">(</span>Rack::MockSession<span style="color:#d2cd86; ">.</span><span style="color:#e66170; font-weight:bold; ">new</span><span style="color:#d2cd86; ">(</span>Sinatra::Application<span style="color:#d2cd86; ">)</span><span style="color:#d2cd86; ">)</span> browser<span style="color:#d2cd86; ">.</span>get <span style="color:#00c4c4; ">'/'</span> assert browser<span style="color:#d2cd86; ">.</span>last_response<span style="color:#d2cd86; ">.</span>ok? <span style="color:#e66170; font-weight:bold; ">end</span> <span style="color:#e66170; font-weight:bold; ">end</span> </pre> <p> </p> <p> Creiamo anche il file (site.rb) dell'applicazione che per ora non ha impostato nessun routing: </p> <pre style="color:#d1d1d1;background:#000000;"><span style="color:#e66170; font-weight:bold; ">require</span> <span style="color:#00c4c4; ">'sinatra'</span> </pre> <p> </p> <p>Se ora lanciamo il test con il comando <code>ruby sitetest.rb</code>. Vediamo che l'assert fallisce.</p> <p>Il codice minimo per la barra verde è:</p> <pre style="color:#d1d1d1;background:#000000;"><span style="color:#e66170; font-weight:bold; ">require</span> <span style="color:#00c4c4; ">'sinatra'</span> get <span style="color:#00c4c4; ">'/'</span> <span style="color:#e66170; font-weight:bold; ">do</span> <span style="color:#e66170; font-weight:bold; ">end</span> </pre> <p> </p> <p>Rilanciamo il test ed ecco la prima barra verde!</p> <p>A questo punto vogliamo che la nostra pagina abbia il contenuto Hello World. Aggiungiamo quindi un assert:</p> <pre style="color:#d1d1d1;background:#000000;">assert_equal browser<span style="color:#d2cd86; ">.</span>last_response<span style="color:#d2cd86; ">.</span>body, <span style="color:#00c4c4; ">'Hello World'</span> </pre> <p> </p> <p>Lanciamo nuovamente il test ed otteniamo il messaggio:</p> <pre> 1) Failure: test_homepage(SiteTest) [sitetest.rb:13]: &lt;""&gt; expected but was &lt;"Hello World"&gt;. </pre> <p>Modifichiamo il codice di produzione per la barra verde:</p> <pre style="color:#d1d1d1;background:#000000;"><span style="color:#e66170; font-weight:bold; ">require</span> <span style="color:#00c4c4; ">'sinatra'</span> get <span style="color:#00c4c4; ">'/'</span> <span style="color:#e66170; font-weight:bold; ">do</span> <span style="color:#00c4c4; ">'Hello World'</span> <span style="color:#e66170; font-weight:bold; ">end</span> </pre> <p> </p> <p>Alcune note:</p> <ul> <li>Affinchè un metodo venga eseguito dal test runner deve iniziare per test</li> <li><code>Sinatra::Application</code> è l'oggetto che rispetta lo standard rack</li> <li>Maggiori dettagli su come scrivere i test usando Rack e Sinatra sono <a href="http://www.sinatrarb.com/testing.html">qui</a></li> </ul> <p> Buon divertimento. </p> <img src="http://blogs.ugidotnet.org/AntonioGanci/aggbug/100658.aspx" width="1" height="1" /> Antonio Ganci http://blogs.ugidotnet.org/AntonioGanci/archive/2011/12/28/sviluppare-un-sito-web-in-tdd-usando-ruby-e-sinatra.aspx Wed, 28 Dec 2011 18:30:11 GMT http://blogs.ugidotnet.org/AntonioGanci/archive/2011/12/28/sviluppare-un-sito-web-in-tdd-usando-ruby-e-sinatra.aspx#feedback 2 http://blogs.ugidotnet.org/AntonioGanci/comments/commentRss/100658.aspx http://blogs.ugidotnet.org/AntonioGanci/services/trackbacks/100658.aspx Primi passi con Sinatra http://blogs.ugidotnet.org/AntonioGanci/archive/2011/12/27/primi-passi-con-sinatra.aspx <p> Ho iniziato a studiare lo sviluppo di applicazioni web con Ruby. Volevo qualcosa di più <i>leggero</i> di Rails per riuscire a padroneggiarlo in meno tempo così la scelta è ricaduta su <a href="http://www.sinatrarb.com/">Sinatra</a>. </p> <p> Di seguito i passi da fare per poter lavorare su Windows con una macchina virtuale Ubuntu: </p> <ul> <li>Scaricare VirtualBox per windows da <a href="https://www.virtualbox.org/wiki/Downloads">qui</a></li> <li>Scaricare l'iso dell'installazione di Ubuntu da <a href="http://www.ubuntu.com/download/ubuntu/download">qui</a>. Ho scaricato l'ultima versione 11.10 a 32 bit. </li><li>Da VirtualBox click su Nuova. Poi scegliere Linux e Ubuntu e dare un nome alla macchina virtuale (io ho scelto ubuntu-11.10)</li> <li>Come memoria ho impostato 1024Mb. Per il resto ho lasciato le impostazioni di default.</li> <li>Click su Avvia. Poi click sul simbolo della cartella e ho scelto il file appena scaricato dell'immagine di Ubuntu.</li> <li>Per l'installazione di Ubuntu ho lasciato tutti i default tranne il check di scaricare gli update.</li> <li>Una volta ravviata la macchina virtuale. Installare le Guest Additions (Menu di VirtualBox Dispositivi -&gt; Installa Guest Additions..). A me le ha installate automaticamente. Per verificare che siano installate dal menu Visualizza -&gt; Adatta alla dimensione della finestra deve essere abilitato. </li> </ul> <p>Ora possiamo installare Ruby</p> <ul> <li>Installiamo l'ultima versione (la 1.9.3) usando <a href="https://rvm.beginrescueend.com/rvm/install/">RVM</a></li> <li>Aprire Terminal e digitare il comando sudo apt-get update</li> <li>Poi installiamo curl con il comando: sudo apt-get curl</li> <li>Ora eseguiamo il comando: bash -s stable &lt; &lt;(curl -s https://raw.github.com/wayneeseguin/rvm/master/binscripts/rvm-installer ). Non riuscirà ad installarlo perché mancano delle dipendenze. L'output del comando ci dirà cosa installare. </li><li>Copiare quindi il comando: apt-get install build-essential openssl libreadline6 libreadline6-dev curl git-core zlib1g zlib1g-dev libssl-dev libyaml-dev libsqlite3-0 libsqlite3-dev sqlite3 libxml2-dev libxslt-dev autoconf libc6-dev ncurses-dev automake libtool bison subversion</li> <li>Rilanciare: bash -s stable &lt; &lt;(curl -s https://raw.github.com/wayneeseguin/rvm/master/binscripts/rvm-installer )</li> <li>Ora chiudere il terminale e riaprirlo</li> <li>Eseguire: rvm --default use 1.9.3</li> <li>se tutto è andato bene scrivendo ruby --version dovrebbe venire fuori che si sta usando la 1.9.3</li> <li>Ora siamo pronti per installare sinatra con: gem install sinatra</li> <li>Infine installiamo il webserver consigliato dal readme di Sinatra: gem install thin</li> </ul> <p> A questo punto siamo pronti a scrivere la prima applicazione che usa Sinatra. Apriamo Text Editor e creiamo il file myapp.rb con il seguente contenuto: </p> <pre style="color:#d1d1d1;background:#000000;"><span style="color:#e66170; font-weight:bold; ">require</span> <span style="color:#00c4c4; ">'sinatra'</span> get <span style="color:#00c4c4; ">'/'</span> <span style="color:#e66170; font-weight:bold; ">do</span> <span style="color:#00c4c4; ">'Hello world!'</span> <span style="color:#e66170; font-weight:bold; ">end</span> </pre> <p> </p> <p> Da terminal lanciamo il comando: ruby -rubygems myapp.rb. Partirà il webserver che si metterà in ascolto sulla porta 4567. Apriamo un browser e verifichiamo che il tutto funziona collegandoci all'url: locahost:4567. </p> <p> Have fun! </p><img src="http://blogs.ugidotnet.org/AntonioGanci/aggbug/100654.aspx" width="1" height="1" /> Antonio Ganci http://blogs.ugidotnet.org/AntonioGanci/archive/2011/12/27/primi-passi-con-sinatra.aspx Tue, 27 Dec 2011 16:44:39 GMT http://blogs.ugidotnet.org/AntonioGanci/archive/2011/12/27/primi-passi-con-sinatra.aspx#feedback 4 http://blogs.ugidotnet.org/AntonioGanci/comments/commentRss/100654.aspx http://blogs.ugidotnet.org/AntonioGanci/services/trackbacks/100654.aspx Le difficoltà nell'apprendere la pratica del TDD Extreme Programming http://blogs.ugidotnet.org/AntonioGanci/archive/2011/12/20/le-difficolta-nellapprendere-la-pratica-del-tdd.aspx <p> Una delle pratiche più invasive di extreme programming oltre al pair programming è il TDD (Test Driven Development) ed è anche la più difficile da padroneggiare. In questo post cercherò di analizzare i motivi, fornendo alcuni spunti su come superare le difficoltà. </p> <p> Le cose più difficili da accettare soprattutto se si ha già una certa esperienza è il fare emergenere il design dai test. Questo implica di <b>non anticipare eventuali feature successive o test successivi e scrivere il codice minimo indispensabile per fare passare il test appena scritto</b>. Nella fase di refactoring poi si toglieranno tutti gli smell introdotti a partire dal più importante che è la duplicazione. </p> <p> Quindi non basta scrivere i test prima, magari solo per realizzare un'idea di design che ho già deciso, ma significa <i>sorprendersi</i> del risultato ottenuto. </p> <p> Una grossa difficoltà è capire quali test scrivere all'inizio e quindi occorre partire molto lentamente, facendo piccoli passi tra un test e il successivo in modo da familiarizzare con la tecnica. </p> <p> Spesso nell'affrontare il design in questa maniera ci si accorge di avere delle carenze nei concetti di OOP oppure nel riconoscere gli smell e quindi è importante studiare molto bene questi argomenti prima di iniziare. </p> <p> Bisogna accettare anche il fatto che nel percorso dell'apprendimento si possa sbagliare e il dover rifare la stessa cosa più volte fino ad arrivare ad un risultato soddisfacente. </p> <p> E' possibile che per ottenere una barra verde del test appena codificato si debba scrivere molto codice, questo è un segno che si è fatto un passo troppo lungo. Una buona soluzione potrebbe essere quella di revertare il codice e riflettere su come fare un passo più piccolo per arrivare al risultato. Ricordiamoci inoltre di integrare dopo ogni refactoring successivo ad una barra verde per rendere l'operazione più veloce ed indolore possibile. </p> <p> La disciplina è un alleato potente perché, soprattutto all'inizio, la tendenza ad abbandonare la pratica è molto forte, in quanto cosa molta fatica e si ha la sensazione di perdere tempo e di andare lentamente. </p> <p> Partire da una codebase con molto codice legacy introduce un'ulteriore difficoltà, quindi all'inizio conviene provare ad implementare una feature da zero limitando il più possibile l'uso del codice esistente. </p> <p> Ricordiamoci infine che il <b>nostro obiettivo è rilsolvere problemi</b>. Un codice di qualità è il mezzo e le feature sono il risultato del nostro lavoro. Su questo punto consiglio la visione di del video <a href="http://blip.tv/clojure/hammock-driven-development-4475586">Hammock-driven Development</a> </p><img src="http://blogs.ugidotnet.org/AntonioGanci/aggbug/100641.aspx" width="1" height="1" /> Antonio Ganci http://blogs.ugidotnet.org/AntonioGanci/archive/2011/12/20/le-difficolta-nellapprendere-la-pratica-del-tdd.aspx Tue, 20 Dec 2011 22:42:32 GMT http://blogs.ugidotnet.org/AntonioGanci/archive/2011/12/20/le-difficolta-nellapprendere-la-pratica-del-tdd.aspx#feedback 2 http://blogs.ugidotnet.org/AntonioGanci/comments/commentRss/100641.aspx http://blogs.ugidotnet.org/AntonioGanci/services/trackbacks/100641.aspx Ridurre la complessità del sistema implementando un interfaccia in modo esplicito Tips http://blogs.ugidotnet.org/AntonioGanci/archive/2011/12/07/ridurre-la-complessita-del-sistema-implementando-un-interfaccia-privatamente.aspx <p> Un <a href="http://jfranzoi.wordpress.com/">collega</a> mi ha suggerito una tecnica interessante quando si è in presenza di codice legacy. </p> <p> Nella nostra codebase abbiamo creato l'astrazione ICommitCommand per modificare i dati delle risorse esterne nei setup dei un test di accettazione in cui utilizziamo i sistemi reali e non dei fake. Nel caso specifico la scrittura su un indice di Lucene e la modifica di alcuni dati nel db. </p> <pre style="color:#d1d1d1;background:#000000;"><span style="color:#e66170; font-weight:bold; ">interface</span> ICommitCommand <span style="color:#b060b0; ">{</span> <span style="color:#e66170; font-weight:bold; ">void</span> Execute<span style="color:#d2cd86; ">(</span><span style="color:#d2cd86; ">)</span><span style="color:#b060b0; ">;</span> <span style="color:#b060b0; ">}</span> </pre> <p> </p> <p> Inizialmente avevo creato l'oggetto: </p> <pre style="color:#d1d1d1;background:#000000;"><span style="color:#e66170; font-weight:bold; ">class</span> LuceneCommand <span style="color:#d2cd86; ">:</span> ICommitCommand <span style="color:#b060b0; ">{</span> LuceneClient _client<span style="color:#b060b0; ">;</span> <span style="color:#e66170; font-weight:bold; ">public</span> LuceneCommand<span style="color:#d2cd86; ">(</span>LuceneClient client<span style="color:#d2cd86; ">)</span> <span style="color:#b060b0; ">{</span> _client <span style="color:#d2cd86; ">=</span> client<span style="color:#b060b0; ">;</span> <span style="color:#b060b0; ">}</span> <span style="color:#e66170; font-weight:bold; ">public</span> <span style="color:#e66170; font-weight:bold; ">void</span> Execute<span style="color:#d2cd86; ">(</span><span style="color:#d2cd86; ">)</span> <span style="color:#b060b0; ">{</span> _client<span style="color:#d2cd86; ">.</span>Update<span style="color:#d2cd86; ">(</span><span style="color:#d2cd86; ">)</span><span style="color:#b060b0; ">;</span> <span style="color:#b060b0; ">}</span> <span style="color:#b060b0; ">}</span> </pre> <p> </p> <p> LuceneCommand è un adapter per l'interfaccia ICommitCommand. Il problema dell'oggetto è che soffre dello smell <a href="http://www.codinghorror.com/blog/2006/05/code-smells.html">Lazy Class</a> (cioè una classe che fa troppo poco). Un modo per risolverlo è quello di fare implementare l'interfaccia direttamente a LuceneClient. </p> <p> Purtroppo il metodo Execute non ha molto significato per LuceneClient. La soluzione che abbiamo adottato è quella di farlo implementare in modo esplicito: </p> <pre style="color:#d1d1d1;background:#000000;"><span style="color:#e66170; font-weight:bold; ">class</span> LuceneClient <span style="color:#d2cd86; ">:</span> ICommitCommand <span style="color:#b060b0; ">{</span> <span style="color:#d2cd86; ">.</span><span style="color:#d2cd86; ">.</span><span style="color:#d2cd86; ">.</span> <span style="color:#e66170; font-weight:bold; ">void</span> ICommitCommand<span style="color:#d2cd86; ">.</span>Execute<span style="color:#d2cd86; ">(</span><span style="color:#d2cd86; ">)</span> <span style="color:#b060b0; ">{</span> _client<span style="color:#d2cd86; ">.</span>Update<span style="color:#d2cd86; ">(</span><span style="color:#d2cd86; ">)</span><span style="color:#b060b0; ">;</span> <span style="color:#b060b0; ">}</span> <span style="color:#d2cd86; ">.</span><span style="color:#d2cd86; ">.</span><span style="color:#d2cd86; ">.</span> <span style="color:#b060b0; ">}</span> </pre> <p> </p> <p> In questo modo se utilizzo direttamente LuceneClient non posso chiamare il metodo Execute, mentre se ne ho un riferimento come ICommitCommand posso chiamare il metodo. </p> <p> Questa tecnica viene sfruttata anche nel .net framework per l'oggetto Dictionary che implementa il metodo Add(KeyValuePair) privatamente: </p> <pre style="color:#d1d1d1;background:#000000;">var dictionary <span style="color:#d2cd86; ">=</span> <span style="color:#e66170; font-weight:bold; ">new</span> Dictionary<span style="color:#d2cd86; ">&lt;</span><span style="color:#e66170; font-weight:bold; ">int</span><span style="color:#d2cd86; ">,</span> <span style="color:#e66170; font-weight:bold; ">string</span><span style="color:#d2cd86; ">&gt;</span><span style="color:#d2cd86; ">(</span><span style="color:#d2cd86; ">)</span><span style="color:#b060b0; ">;</span> dictionary<span style="color:#d2cd86; ">.</span>Add<span style="color:#d2cd86; ">(</span><span style="color:#e66170; font-weight:bold; ">new</span> KeyValuePair<span style="color:#d2cd86; ">&lt;</span><span style="color:#e66170; font-weight:bold; ">int</span><span style="color:#d2cd86; ">,</span> <span style="color:#e66170; font-weight:bold; ">string</span><span style="color:#d2cd86; ">&gt;</span><span style="color:#d2cd86; ">(</span><span style="color:#d2cd86; ">)</span><span style="color:#d2cd86; ">)</span><span style="color:#b060b0; ">;</span> <span style="color:#9999a9; ">// Error</span> var d <span style="color:#d2cd86; ">=</span> <span style="color:#d2cd86; ">(</span>IDictionary<span style="color:#d2cd86; ">&lt;</span><span style="color:#e66170; font-weight:bold; ">int</span><span style="color:#d2cd86; ">,</span> <span style="color:#e66170; font-weight:bold; ">string</span><span style="color:#d2cd86; ">&gt;</span><span style="color:#d2cd86; ">)</span> dictionary<span style="color:#b060b0; ">;</span> d<span style="color:#d2cd86; ">.</span>Add<span style="color:#d2cd86; ">(</span><span style="color:#e66170; font-weight:bold; ">new</span> KeyValuePair<span style="color:#d2cd86; ">&lt;</span><span style="color:#e66170; font-weight:bold; ">int</span><span style="color:#d2cd86; ">,</span> <span style="color:#e66170; font-weight:bold; ">string</span><span style="color:#d2cd86; ">&gt;</span><span style="color:#d2cd86; ">(</span><span style="color:#d2cd86; ">)</span><span style="color:#d2cd86; ">)</span><span style="color:#b060b0; ">;</span> <span style="color:#9999a9; ">// ok</span> </pre> <p> </p> <p> Il vantaggio di questa soluzione è che riduce la complessità del sistema, evitando il proliferare di adapter che non fanno altro che permettere ad una classe di implementare l'interfaccia desiderata. </p> <img src="http://blogs.ugidotnet.org/AntonioGanci/aggbug/100608.aspx" width="1" height="1" /> Antonio Ganci http://blogs.ugidotnet.org/AntonioGanci/archive/2011/12/07/ridurre-la-complessita-del-sistema-implementando-un-interfaccia-privatamente.aspx Wed, 07 Dec 2011 20:32:15 GMT http://blogs.ugidotnet.org/AntonioGanci/archive/2011/12/07/ridurre-la-complessita-del-sistema-implementando-un-interfaccia-privatamente.aspx#feedback 2 http://blogs.ugidotnet.org/AntonioGanci/comments/commentRss/100608.aspx http://blogs.ugidotnet.org/AntonioGanci/services/trackbacks/100608.aspx Mettere alla prova il design della propria codebase Extreme Programming http://blogs.ugidotnet.org/AntonioGanci/archive/2011/11/23/mettere-alla-prova-il-design-della-propria-codebase.aspx <p> Il <a href="http://varvello.blogspot.com/">coach</a> del mio <a href="http://teamnautilus.wordpress.com/">team</a> xp di nome Nautilus ci ha proposto un'interessante esercizio per mettere alla prova la qualità della nostra codebase. </p> <p> Scrivere il test dello scenario che si vuole sviluppare come lo vorremmo, ignorando l'attuale architettura, misurando il tempo impiegato. </p> <p> Provare poi a scriverlo usando i nostri oggetti misurando nuovamente il tempo impiegato. </p> <p> Nel caso specifico la coppia, in quanto sviluppiamo in pair, ha impiegato 2 minuti a scrivere il test per il primo caso e tre <a href="http://www.pomodorotechnique.com/">pomodori</a> (circa un ora e mezza) nel secondo caso. </p> <p> La differenza tra i due tempi indica quanto la nostra codebase è lontana dalla qualità che vorremmo ottenere. </p> <p> Questa è l'essenza del TDD, cioè usare il test per comunicare come ci aspettiamo di utilizzare i nostri oggetti ed è anche un indicatore di quale sia il debito tecnico attualmente presente. </p> <p> Non solo: ci suggerisce anche come rifattorizzare il codice per migliorarne la comunicatività e chiarezza. </p><img src="http://blogs.ugidotnet.org/AntonioGanci/aggbug/100549.aspx" width="1" height="1" /> Antonio Ganci http://blogs.ugidotnet.org/AntonioGanci/archive/2011/11/23/mettere-alla-prova-il-design-della-propria-codebase.aspx Wed, 23 Nov 2011 19:42:03 GMT http://blogs.ugidotnet.org/AntonioGanci/archive/2011/11/23/mettere-alla-prova-il-design-della-propria-codebase.aspx#feedback 9 http://blogs.ugidotnet.org/AntonioGanci/comments/commentRss/100549.aspx http://blogs.ugidotnet.org/AntonioGanci/services/trackbacks/100549.aspx La fabbrica delle giustificazioni http://blogs.ugidotnet.org/AntonioGanci/archive/2011/11/21/la-fabbrica-delle-giustificazioni.aspx <p> Recentemente ho letto un libro sulla dieta alimentare in cui c'è scritto che la mente umana è molto efficiente nel creare delle giustificazioni per non fare le cose che ci fanno bene. </p> <p> Il meccanismo è descritto bene in questo <a href="http://youarenotsosmart.com/2010/10/27/procrastination/">post</a> che spiega il problema del procrastinare. </p> <p> Guardando il <a href="http://www.livestream.com/italianagileday/video?clipId=pla_771449dc-380b-45f1-a6e2-cc156501daf1&amp;utm_source=lslibrary&amp;utm_medium=ui-thumb">video</a> <i>Is Software Evolution really Effective?</i> di Francesco Cirillo all'ultimo agile day, ci si rende conto che evoluzione e design emergente non hanno molto significato se non si conosce in quale direzione deve avvenire l'evoluzione o cosa deve emergere. </p> In particolare nello sviluppo software l'evoluzione deve portare ad un costo descrescente col passare del tempo nell'aggiungere feature al sistema. Se questo non avviene probabilmente nella nostra codebase stanno crescendo dei code monster (<a href="http://www.antiifcampaign.com/code-monster.html">qui</a> un esempio). <p> </p><p> Che cosa porta alla creazione di un code monster? </p> <p> Secondo me le cause possono essere solo due: </p> <ul> <li><b>Mancanza di volontà</b></li> <li><b>Mancanza di competenze</b></li> </ul> <p> Nel primo caso rientrano: la pigrizia, la stanchezza, poca disciplina. Mentre nella seconda semplicemente non si è studiato abbastanza. </p> <p> Un'obiezione che spesso sento è: non abbiamo abbastanza tempo. Ormai è appurato che il modo più produttivo per aggiungere una feature al nostro sistema è quello di non farsi sconti sulla qualità; quindi la mancanza di tempo è un motivo in più per non allevare code monster. </p> <p> Sulla competenza suggerisco un semplice esercizio. Scrivete a memoria tutti gli smell che conoscete, poi prendete il <a href="http://www.amazon.com/Refactoring-Improving-Design-Existing-Code/dp/0201485672">libro</a> del refactoring di Fowler e verificate se li avete elencati tutti correttamente, in caso contrario studiateli finché non li conoscete a memoria. </p> <p> Un altro esercizio è: scrivete, sempre a memoria, quali caratteristiche ha un <i>bad design</i> e confrontateli con questo <a href="http://www.objectmentor.com/resources/articles/dip.pdf">paper</a> di zio bob. </p> <p> Concludendo: entrambe le variabili per scrivere del buon codice sono completamente sotto il nostro controllo. Smettiamo di trovare scuse ed iniziamo a farlo ora senza procrastinare. I colleghi e i clienti ringrazieranno della vostra scelta. </p><img src="http://blogs.ugidotnet.org/AntonioGanci/aggbug/100545.aspx" width="1" height="1" /> Antonio Ganci http://blogs.ugidotnet.org/AntonioGanci/archive/2011/11/21/la-fabbrica-delle-giustificazioni.aspx Mon, 21 Nov 2011 22:13:59 GMT http://blogs.ugidotnet.org/AntonioGanci/archive/2011/11/21/la-fabbrica-delle-giustificazioni.aspx#feedback 8 http://blogs.ugidotnet.org/AntonioGanci/comments/commentRss/100545.aspx http://blogs.ugidotnet.org/AntonioGanci/services/trackbacks/100545.aspx Test automatico per verificare che l'html non contenga errori Tips http://blogs.ugidotnet.org/AntonioGanci/archive/2011/03/28/test-automatico-per-verificare-che-lhtml-non-contenga-errori.aspx <p> Dopo che ci è scappato un errore nell'html del sito su cui stiamo lavorando, abbiamo deciso di scrivere un test che validi l'html prodotto. </p> <p> Per raggiungere l'obiettivo utilizziamo l'utility Tidy che si puo' scaricare da <a href="http://tidy.sourceforge.net/#binaries">qui</a> </p> <p> È un piccolo eseguibile a cui si puo' passare un html e verificare che non contenga errori. </p> <p> Il codice del test è piuttosto semplice: </p> <pre style="color:#d1d1d1;background:#000000;"><span style="color:#d2cd86; ">[</span>Test<span style="color:#d2cd86; ">]</span> <span style="color:#e66170; font-weight:bold; ">public</span> <span style="color:#e66170; font-weight:bold; ">void</span> ValidateHtml<span style="color:#d2cd86; ">(</span><span style="color:#d2cd86; ">)</span> <span style="color:#b060b0; ">{</span> var html <span style="color:#d2cd86; ">=</span> <span style="color:#e66170; font-weight:bold; ">new</span> WebClient<span style="color:#d2cd86; ">(</span><span style="color:#d2cd86; ">)</span><span style="color:#d2cd86; ">.</span>DownloadString<span style="color:#d2cd86; ">(</span>@<span style="color:#02d045; ">"</span><span style="color:#00c4c4; ">http://someurl.com</span><span style="color:#02d045; ">"</span><span style="color:#d2cd86; ">)</span><span style="color:#b060b0; ">;</span> process <span style="color:#d2cd86; ">=</span> <span style="color:#e66170; font-weight:bold; ">new</span> Process<span style="color:#d2cd86; ">(</span><span style="color:#d2cd86; ">)</span><span style="color:#b060b0; ">;</span> process<span style="color:#d2cd86; ">.</span>StartInfo<span style="color:#d2cd86; ">.</span>FileName <span style="color:#d2cd86; ">=</span> <span style="color:#02d045; ">"</span><span style="color:#00c4c4; ">tidy.exe</span><span style="color:#02d045; ">"</span><span style="color:#b060b0; ">;</span> process<span style="color:#d2cd86; ">.</span>StartInfo<span style="color:#d2cd86; ">.</span>Arguments <span style="color:#d2cd86; ">=</span> <span style="color:#02d045; ">"</span><span style="color:#00c4c4; ">-e</span><span style="color:#02d045; ">"</span><span style="color:#b060b0; ">;</span> process<span style="color:#d2cd86; ">.</span>StartInfo<span style="color:#d2cd86; ">.</span>UseShellExecute <span style="color:#d2cd86; ">=</span> <span style="color:#e66170; font-weight:bold; ">false</span><span style="color:#b060b0; ">;</span> process<span style="color:#d2cd86; ">.</span>StartInfo<span style="color:#d2cd86; ">.</span>CreateNoWindow <span style="color:#d2cd86; ">=</span> <span style="color:#e66170; font-weight:bold; ">true</span><span style="color:#b060b0; ">;</span> process<span style="color:#d2cd86; ">.</span>StartInfo<span style="color:#d2cd86; ">.</span>RedirectStandardError <span style="color:#d2cd86; ">=</span> <span style="color:#e66170; font-weight:bold; ">true</span><span style="color:#b060b0; ">;</span> process<span style="color:#d2cd86; ">.</span>StartInfo<span style="color:#d2cd86; ">.</span>RedirectStandardInput <span style="color:#d2cd86; ">=</span> <span style="color:#e66170; font-weight:bold; ">true</span><span style="color:#b060b0; ">;</span> process<span style="color:#d2cd86; ">.</span>Start<span style="color:#d2cd86; ">(</span><span style="color:#d2cd86; ">)</span><span style="color:#b060b0; ">;</span> process<span style="color:#d2cd86; ">.</span>StandardInput<span style="color:#d2cd86; ">.</span>Write<span style="color:#d2cd86; ">(</span>html<span style="color:#d2cd86; ">)</span><span style="color:#b060b0; ">;</span> process<span style="color:#d2cd86; ">.</span>StandardInput<span style="color:#d2cd86; ">.</span>Close<span style="color:#d2cd86; ">(</span><span style="color:#d2cd86; ">)</span><span style="color:#b060b0; ">;</span> process<span style="color:#d2cd86; ">.</span>WaitForExit<span style="color:#d2cd86; ">(</span><span style="color:#d2cd86; ">)</span><span style="color:#b060b0; ">;</span> Assert<span style="color:#d2cd86; ">.</span>That<span style="color:#d2cd86; ">(</span>_process<span style="color:#d2cd86; ">.</span>ExitCode<span style="color:#d2cd86; ">,</span> Is<span style="color:#d2cd86; ">.</span>EqualTo<span style="color:#d2cd86; ">(</span><span style="color:#008c00; ">0</span><span style="color:#d2cd86; ">)</span><span style="color:#d2cd86; ">,</span> _process<span style="color:#d2cd86; ">.</span>StandardError<span style="color:#d2cd86; ">.</span>ReadToEnd<span style="color:#d2cd86; ">(</span><span style="color:#d2cd86; ">)</span><span style="color:#d2cd86; ">)</span><span style="color:#b060b0; ">;</span> <span style="color:#b060b0; ">}</span> </pre> <p>   </p> <p> Il processo viene creato redirigendo lo standard input e lo standard error, il primo usato per inviare l'html, mentre il secondo come messaggio di errore nel caso l'Assert fallisca. L'output di tidy è piuttosto esplicativo e ci permette di correggere velocemente gli errori individuati. </p> <p> l'opzione -e indica di mostrare solo gli errori, altrimenti tidy puo' anche provare a correggerli, opzione che non utilizziamo. </p> <p> La documentazione sulle opzioni supportate da tidy la trovate <a href="http://tidy.sourceforge.net/docs/tidy_man.html">qui</a>. </p><img src="http://blogs.ugidotnet.org/AntonioGanci/aggbug/99884.aspx" width="1" height="1" /> Antonio Ganci http://blogs.ugidotnet.org/AntonioGanci/archive/2011/03/28/test-automatico-per-verificare-che-lhtml-non-contenga-errori.aspx Mon, 28 Mar 2011 15:53:18 GMT http://blogs.ugidotnet.org/AntonioGanci/archive/2011/03/28/test-automatico-per-verificare-che-lhtml-non-contenga-errori.aspx#feedback 1 http://blogs.ugidotnet.org/AntonioGanci/comments/commentRss/99884.aspx http://blogs.ugidotnet.org/AntonioGanci/services/trackbacks/99884.aspx Accedere ad un field pubblico da un metodo privato in Javascript Tips http://blogs.ugidotnet.org/AntonioGanci/archive/2011/02/14/accedere-ad-un-field-pubblico-da-un-metodo-privato-in.aspx <p> Oggi mi sono imbattuto in un problema imprevisto e voglio condividerlo perché potrebbe tornare utile a chi non padroneggia Javascript. </p> <p>Supponiamo di avere un oggetto definito come segue:</p> <pre style="color:#d1d1d1;background:#000000;"><span style="color:#e66170; font-weight:bold; ">function</span> AnObject<span style="color:#d2cd86; ">(</span><span style="color:#d2cd86; ">)</span> <span style="color:#b060b0; ">{</span> <span style="color:#e66170; font-weight:bold; ">this</span><span style="color:#d2cd86; ">.</span>value <span style="color:#d2cd86; ">=</span> <span style="color:#008c00; ">1000</span><span style="color:#b060b0; ">;</span> <span style="color:#e66170; font-weight:bold; ">var</span> set_value <span style="color:#d2cd86; ">=</span> <span style="color:#e66170; font-weight:bold; ">function</span><span style="color:#d2cd86; ">(</span>new_value<span style="color:#d2cd86; ">)</span> <span style="color:#b060b0; ">{</span> <span style="color:#e66170; font-weight:bold; ">this</span><span style="color:#d2cd86; ">.</span>value <span style="color:#d2cd86; ">=</span> new_value<span style="color:#b060b0; ">;</span> <span style="color:#b060b0; ">}</span><span style="color:#b060b0; ">;</span> <span style="color:#e66170; font-weight:bold; ">this</span><span style="color:#d2cd86; ">.</span>start <span style="color:#d2cd86; ">=</span> <span style="color:#e66170; font-weight:bold; ">function</span><span style="color:#d2cd86; ">(</span><span style="color:#d2cd86; ">)</span> <span style="color:#b060b0; ">{</span> set_value<span style="color:#d2cd86; ">(</span><span style="color:#008c00; ">5</span><span style="color:#d2cd86; ">)</span><span style="color:#b060b0; ">;</span> <span style="color:#b060b0; ">}</span> <span style="color:#b060b0; ">}</span> </pre> <p> L'oggetto ha un field pubblico chiamato value, un metodo pubblico chiamato start ed un metodo privato chiamato set_value. Supponiamo ora che vogliamo testarlo ed il test sia il seguente: </p> <pre style="color:#d1d1d1;background:#000000;"><span style="color:#e66170; font-weight:bold; ">function</span> an_object_test<span style="color:#d2cd86; ">(</span><span style="color:#d2cd86; ">)</span> <span style="color:#b060b0; ">{</span> <span style="color:#e66170; font-weight:bold; ">test</span><span style="color:#d2cd86; ">(</span><span style="color:#00c4c4; ">"an object"</span><span style="color:#d2cd86; ">,</span> <span style="color:#e66170; font-weight:bold; ">function</span><span style="color:#d2cd86; ">(</span><span style="color:#d2cd86; ">)</span> <span style="color:#b060b0; ">{</span> <span style="color:#e66170; font-weight:bold; ">var</span> obj <span style="color:#d2cd86; ">=</span> <span style="color:#e66170; font-weight:bold; ">new</span> AnObject<span style="color:#d2cd86; ">(</span><span style="color:#d2cd86; ">)</span><span style="color:#b060b0; ">;</span> obj<span style="color:#d2cd86; ">.</span>start<span style="color:#d2cd86; ">(</span><span style="color:#d2cd86; ">)</span><span style="color:#b060b0; ">;</span> equal<span style="color:#d2cd86; ">(</span>obj<span style="color:#d2cd86; ">.</span>value<span style="color:#d2cd86; ">,</span> <span style="color:#008c00; ">5</span><span style="color:#d2cd86; ">)</span><span style="color:#b060b0; ">;</span> <span style="color:#b060b0; ">}</span><span style="color:#d2cd86; ">)</span><span style="color:#b060b0; ">;</span> <span style="color:#b060b0; ">}</span> </pre> <p> Il test sarà passerà o fallirà? Se lo eseguiamo otterremo una soprendente barra rossa, con il messaggio: <i>Expected 5 but was 1000</i>, come se il metodo privato non fosse stato eseguito. Per quale motivo? </p> <p> <b>Il this nel metodo privato non si riferisce all'oggetto AnObject, piuttosto all'oggetto globale del browser window</b>. Questo problema è spiegato nel post <a href="http://www.crockford.com/javascript/private.html">Private Members in JavaScript</a> di Douglas Crockford. In particolare la soluzione proposta è: </p> <pre style="color:#d1d1d1;background:#000000;"><span style="color:#e66170; font-weight:bold; ">function</span> AnObject<span style="color:#d2cd86; ">(</span><span style="color:#d2cd86; ">)</span> <span style="color:#b060b0; ">{</span> <span style="color:#e66170; font-weight:bold; ">this</span><span style="color:#d2cd86; ">.</span>value <span style="color:#d2cd86; ">=</span> <span style="color:#008c00; ">1000</span><span style="color:#b060b0; ">;</span> <span style="color:#e66170; font-weight:bold; ">var</span> that <span style="color:#d2cd86; ">=</span> <span style="color:#e66170; font-weight:bold; ">this</span><span style="color:#b060b0; ">;</span> <span style="color:#e66170; font-weight:bold; ">var</span> set_value <span style="color:#d2cd86; ">=</span> <span style="color:#e66170; font-weight:bold; ">function</span><span style="color:#d2cd86; ">(</span>new_value<span style="color:#d2cd86; ">)</span> <span style="color:#b060b0; ">{</span> that<span style="color:#d2cd86; ">.</span>value <span style="color:#d2cd86; ">=</span> new_value<span style="color:#b060b0; ">;</span> <span style="color:#b060b0; ">}</span><span style="color:#b060b0; ">;</span> <span style="color:#e66170; font-weight:bold; ">this</span><span style="color:#d2cd86; ">.</span>start <span style="color:#d2cd86; ">=</span> <span style="color:#e66170; font-weight:bold; ">function</span><span style="color:#d2cd86; ">(</span><span style="color:#d2cd86; ">)</span> <span style="color:#b060b0; ">{</span> set_value<span style="color:#d2cd86; ">(</span><span style="color:#008c00; ">5</span><span style="color:#d2cd86; ">)</span><span style="color:#b060b0; ">;</span> <span style="color:#b060b0; ">}</span> <span style="color:#b060b0; ">}</span> </pre> <p> Il motivo del field that è spiegato nel post: </p> <cite> By convention, we make a private that variable. This is used to make the object available to the private methods. This is a workaround for an error in the ECMAScript Language Specification which causes this to be set incorrectly for inner functions. </cite> <p> Tenetelo presente quando lavorate in Javascript perché potrebbe riservare spiacevoli sorprese. </p> <img src="http://blogs.ugidotnet.org/AntonioGanci/aggbug/99721.aspx" width="1" height="1" /> Antonio Ganci http://blogs.ugidotnet.org/AntonioGanci/archive/2011/02/14/accedere-ad-un-field-pubblico-da-un-metodo-privato-in.aspx Mon, 14 Feb 2011 15:48:41 GMT http://blogs.ugidotnet.org/AntonioGanci/archive/2011/02/14/accedere-ad-un-field-pubblico-da-un-metodo-privato-in.aspx#feedback 6 http://blogs.ugidotnet.org/AntonioGanci/comments/commentRss/99721.aspx http://blogs.ugidotnet.org/AntonioGanci/services/trackbacks/99721.aspx