Archive for the ‘Object Oriented Design’ Category.

Agile Day 2011

Anche quest'anno eccomi a stilare il mio personalissimo resoconto dell'Agile Day.
In primo luogo vorrei ringraziare gli organizzatori, che hanno svolto un lavoro perfetto. Se non ci siamo "accorti" di voi è perché tutto ha funzionato al meglio: bravi!
Ed ora mia una interpretazione delle sessioni a cui ho partecipato.

Back to basics: OOP and design

Il senso dell'intervento di Paolo Polce sta tutto nel titolo: dopo anni spesi a concentrarsi sul processo, abbiamo forse perso di vista i problemi tecnici, quasi fossero semplici dettagli implementativi. Scrum masters, sprints, story points, sì, vabbè, ma il codice? Beh, al codice ci penseranno le "risorse"... :-)
E' tempo di tornare a focalizzarsi sulle "risorse", ovvero sui programmatori, e sulle loro competenze, che devono costantemente essere allenate, come i muscoli di un atleta.
Come ottenere lo scopo? Con buone letture, buoni strumenti, ed un continuo esercizio volto a creare design realmente ad oggetti. Una buona architettura Object Oriented modularizza i problemi tramite gli oggetti, ed evita quindi classi "Star gate" (spesso incarnate da dei Singleton), che leggono attraverso una pioggia di getter le informazioni più disparate, collassando al loro interno l'intera logica applicativa. Occorre quindi evitare i getter, scrivendo sempre più metodi che restituiscono void. Ma come testare queste architetture? La chiave consiste nel passare da test sullo stato degli oggetti, a test che ne verificano le interazioni.

Codice legacy: usciamo dal pantano!

Bel workshop di Stefano Leli e Simone Casciaroli. I partecipanti sono stati invitati a fare refactoring su un piccolo progetto, che nella gerarchia Bird-Duck-Chicken mostra un caratteristico caso di violazione del Principio di sostituzione di Liskov, il complesso edipico irrisolto della programmazione ad oggetti.
La sessione, terminata con la presentazione della soluzione dei relatori, è stata interessante, anche se avrebbe richiesto sicuramente almeno un'altra ora per riuscire al meglio.

Lean, A3 e kaizen

Claudio Perrone nel suo intervento ha illustrato i i Kaizen Memo ed il medoto A3.
I Kaizen Memo sono piccoli fogli di carta da appendere su una parete per dare evidenza ai miglioramenti raggiunti nel processo produttivo. Dovrebbero riportare il problema affrontato, la misura intrapresa per risolverlo e le conseguenze ottenute.
Il metodo A3 prevede di utilizzare un modulo di carta, solitamente di dimensione appunto A3, sul quale presentare in modo oggettivo:

  • la situazione corrente;
  • l'obiettivo da raggiungere (ciò definisce il problema come differenza tra situazione corrente ed obiettivo da realizzare);
  • l'analisi delle cause del problema;
  • l'elenco delle contromisure da adottare;
  • una matrice what-who-where-how per realizzare le contromisure;
  • un elenco di azioni supplementari (follow-up) da intreprendere in caso di problemi.

L'intervento è proseguito definendo la figura del manager ideale, che non dovrebbe essere né un poliziotto che punisce chi si comporta male, né una mamma che coccola i suoi figli, e neppure una figura assente. Il vero manager dovrebbe invece essere una persona che si occupa di eliminare i problemi che ostacolano il processo produttivo. La domanda che un manager dovrebbe rivolgere ai suoi sottoposti non è "cosa hai prodotto ieri", ma "quali problemi hai avuto".
Claudio Perrone ha concluso dando una bella definizione dei metodi lean/agili: strumenti per fare soldi attraverso la crescita delle persone.

Back to basics hands-on

Antonio Carpentieri e Paolo Polce hanno condotto un efficace workshop sul design ad oggetti. Utilizzando come esempio il gioco del monopoli, hanno mostrato nella pratica come realizzare software ad oggetti senza abusare di getters e favorendo composizione, basso accoppiamento ed alta coesione.
Molto importante la sottolineatura finale di Antonio Carpentieri che ha ripreso il keynote di Paolo Polce: un programmatore non può crescere lavorando solo su codice di produzione. Come un atleta non migliora solo con le partite, ma soprattutto con gli allenamenti, anche chi sviluppa software non può non allenarsi praticando i kata.

Unit Tests VS End to End Tests

Probabilmente il mio giudizio su questo intervento è falsato dalla fatica accumulata alla fine di una giornata così intensa, ma dalla presentazione di Domenico Musto non sono riuscito a trarre nessuna informazione interessante. Chiedo venia.

Conclusioni

Anche questa edizione dell'Agile Day è stata all'altezza delle aspettative. Mi è piaciuta molto l'enfasi sul codice, dopo troppo tempo speso sui problemi di processo. Grazie ancora agli organizzatori ed arrivederci al 2013!

L’apostata del TDD

Ho seguito con molto interesse la discusione generata da un post che vuole essere iconoclasta già nel titolo: l'apostata del TDD. Vorrei sottoporvi le mie annotazioni.

Perché il post mi pare interessante

Perché il post mi pare interessante? Perché tocca le corde della mia esperienza personale: anche io, come l'autore, ho provato curiosità nel notare di aver sviluppato a volte del buon codice senza l'uso del TDD e del pessimo codice con il TDD. Posto che è plausibile che problema risieda in me e non nel metodo, mi pare lecito comunque chiedersi se anche il metodo stesso non abbia qualche pecca. Provo infatti un certo fastidio quando, durante l'analisi di fallimenti del TDD (e mi pare che comunque ve ne siano), si escluda dogmaticamente che lo strumento possa avere qualche difetto. Tutto questo mi ricorda le critiche che (inutilmente) qualcuno negli anni 70 muoveva a psicanalisi e marxismo: ci si chiedeva infatti se fosse possibile che queste dottrine fossero di per sè corrette, mentre ogni loro clamorosa debacle si dovesse addebitare sempre ad una loro incorretta realizzazione, pienamente giustificabile ed interpretabile all'interno delle dottrine stesse.

Cosa non funziona nel TDD?

Ma allora cosa ci sarebbe di sbagliato nel TDD? Non so se vi sia qualcosa di "sbagliato", sicuramente indagherei su questi punti.

La visione d'insieme

Riprendendo quanto detto da Carlo Bottiglieri sulla lista extremeprogramming-it, il TDD potrebbe far perdere la visione d'insieme del problema, o anche problematiche trasversali all'intero sistema.

Cicli troppo stretti

Il TDD si basa sul "mantra" "red-green-refactor", che però, nella sua definizione, prevede di essere un ciclo di breve durata, per consentire un riscontro immediato. Ciò a mio avviso implica che la fase di refactor non possa spostare di molto l'"inerzia" del sistema: ciclo breve, refactoring breve, quindi spesso indirizzato a piccoli obiettivi. Il refactoring, inoltre, nascendo come "cura" per le puzze del codice, a risulta uno strumento di ottimizzazione locale: diminuisco la lunghezza dei metodi ed il numero di parametri, creo classi disaccoppiate, ottimizzo gli indicatori "locali" di qualità, ma la struttura generale è comprensibile e riutilizzabile?

Coesione vs accoppiamento

Durante un suo corso, Francesco Cirillo mi ha fatto riflettere su questo concetto: del buon codice deve essere ad alta coesione e a basso accoppiamento, ma vi è una tensione tra i due aspetti. Il mio dubbio è: il TDD tende a sistemi a basso accoppiamento, ma forse anche a bassa coesione?

No Big Upfront Design?

Il TDD ha viaggiato a braccetto con il concetto di "No Big Upfront Design", anche nella sua variante "non facciamo design prima di scrivere il codice, ma solo scrivendolo". Ma siamo proprio sicuri che il codice sia il l'unco luogo, o comunque quello ideale, dove disegnare il codice stesso?

Il lato oscuro dei test

Non dobbiamo dimenticare quello che Matteo Vaccari chiama "il lato oscuro dei test": paradossalmente un sistema copero al 100% da test potrebbe invitarci a scrivere codice "peggiore", in quanto, qualsiasi schifezza volessimo introdurre, avremmo sempre la certezza di non rompere nulla.

Sono anch'io un apostata?

Non so se dirmi apostata anch'io: forse non posso, non essendo mai stato un fedele praticante. ;-)
Sicuramente diffido di chi ha fatto del TDD una religione, o meglio un feticcio.
Forse, riprendendo la bella analogia di Jacopo Romei, sono nella fase "Ha – Vìola la regola" del ciclo "Shu-Ha-Ri": sto cercando di mettermi in opposizione al TDD, al fine di capirlo meglio.
Certamente vorrei saper usare il TDD come Carlo, ma a volte mi chiedo se questo non sia un tipo di programmazione che solo dei grandi virtuosi sono in grado di svolgere.
O forse sto ancora ricercando la mia via e sono ancora molto lontano anche dalla fase "Shu"...

Italian Agile Day 2010

Anche l'Italian Agile Day del 2010 è stato un bellissimo evento, e vorrei darne qui il mio personalissimo resoconto.

Keynote

Paolo Perrotta ha condotto con brio ed intelligenza un bellissimo escursus su come, nel corso del tempo, sia stato affrontato il problema di ridurre i fallimenti nei progetti software.
Un primo tentativo si è basato su un mito: i progetti falliscono perché gli strumenti di programmazione sono troppo complessi, tant'è che richiedono degli specialisti come i programmatori per essere realizzati. Se solo potessimo eliminare i programmatori...:-) Si cerca così soppressione dei programmatori tramite strategie che si chiamano di volta in volta SOA, UML, CASE; persino il Cobol è nato per scrivere programmi senza avere programmatori! Tutti questi tentativi si sono però scontrati contro un medesimo scoglio: scrivere algoritmi che vengano eseguiti è qualcosa di intrinsecamente complesso.
Si è anche pensato di controllare il fallimento eliminando la componente di errore umano. Nascono quindi i metodi formali di verifica di correttezza del software, che comunque non sembrano aver avuto molto successo.
Si è quindi pensato di eliminare la variabilità dei progetti irregimentando lo sviluppo all'interno di procedure ben determinate. Ecco allora nascere metodi di lavoro come il Waterfall, che conteneva alle sue origini idee apprezzabili come la valorizzazione delle persone e l'enfasi sul test anche automatizzato del codice. Waterfall, come molte altro processi di sviluppo, si sono nel tempo "distorti" nel loro divenire strumenti di successo. Anche "Agile" subirà la stessa fine? Forse sì, ma sicuramente lascerà qualcosa di buono alle sue spalle. Il seme "Agile" consiste nell'idea non eliminare, ma di accettare la variabilità dei progetti, scomponendoli in piccole parti, ognuna delle quali attraversa tre fasi (il corsivo indica mie ipotesi)

  1. Osservazioni (user stories)
  2. Ipotesi (codice)
  3. Verifica sperimentale (test)

Questo è il cuore dei "Metodi agili", che è destinato a rimanere perché non è altro che il cuore del metodo scientifico.

Affiliamo i nostri strumenti: un test driver fatto in casa

In questa interessante sessione Jacopo Franzoi ha illustrato la sua esperienza nell'introdurre in un progetto reale i test unitari anche in quel regno dimenticato costituito dalle interfacce web.
Jacopo è infatti riuscito a creare una mini libreria per testare le pagine generate tramite FreeMarker.
Il messaggio è stato chiaro: anche in ambienti apparentemente ostili, come lo sviluppo di pagine web, è possibile crearsi strumenti che consentano di testare le nostre applicazioni. La sovrabbondanza di dettagli implementativi, che probabilmente sono sfuggiti a chi non ha mai utilizzato il particolare strumento di template in esame, è forse stato l'unico piccolo neo nella presentazione.

Code Kata Live

Una brillante presentazione di Gabriele Lana sui code Kata ha introdotto la perfomance di Giordano Scalzo e Tonino Lucca.
Tesi centrale dell'esposizione di Gabriele: il talento non è (solo) innato, bensì sgorga da un esercizio costante. Perché l'esercizio giunga a dei risultati occorre che:

  1. sia sfidante: ogni prova deve essere leggermente più difficile delle precedenti, senza però essere frustrante;
  2. sia ripetuto;
  3. abbia un riscontro da parte di altri, sia da persone più esperte, che sappiano dare suggerimenti, sia da persone meno esperte, che possano dare opinioni non convenzionali.

Ripetere incessantemente buoni esempi ci consente di passare dal codice "quick and dirty" al codice "quick and clean". Quando le nostre abilità sono limitate, il codice "dirty" ci risulta "quick" perché non sappiamo fare altro. Al crescere delle nostre competenze invece, il codice "clean" ci dovrebbe risultare più "quick", cioè più veloce e naturale da scrivere di quello "dirty".

Guelfi versus Ghibellini


"Noi tutti dobbiamo essere animati da un grande desiderio di competere fra noi per sapere cosa sia il vero e cosa il falso sull'argomento che stiamo trattando; è infatti comune interesse che ci sia chiarezza su questo punto.
Mi accingo ad esporre il mio pensiero; se a qualcuno di voi sembra che io ammetta cose non vere, costui dovrà interrompermi e confutarmi. Del resto io non dico le cose che dico forte di una verità di cui sono sicuro, ma ricerco assieme a voi; pertanto, qualora il mio oppositore mi paia avere ragione, sarò io il primo a riconoscermi d'accordo con lui."

Questo passo del Gorgia di Platone è perfetto per descrivere il messaggio che Sergio Berisso, coaudiuvato da Tonino Lucca, ha voluto indicare nella sua presentazione interattiva. Occorre affrontare le retrospettive, ed in genere tutti i momenti di riflessione e confronto dei gruppi di sviluppo, con questo spirito costruttivo, cercando di trovare i punti di sintesi comuni tra visioni discordanti.

Open space sul Kata "Sasso-forbici-carta" svolto secondo le regole "Aperto-Chiuso"

In un angolino molto defilato, io e l'amico Marco Testa dell'XP User Group di Bergamo abbiamo provato a rifare il Kata "Sasso-forbici-carta" seguendo le regole "Aperto-chiuso" suggerite da Matteo Vaccari. Il pubblico non era certo numeroso...ehm...ehm...vabbe', se vi interessa qui sono le slides e questo è il codice.

TDD per le viste

Questa è stata sicuramente la presentazione più interessante fra quelle da me seguite nella giornata: valeva la pena di partecipare all'Agile Day solo per sentire Matteo Vaccari e Carlo Bottiglieri tenere questa lectio magistralis sul TDD.
TDD spinto sino alle estreme conseguenze: Matteo ha infatti mostrato come gestire con questa tecnica anche la produzione di interfacce HTML, mentre Carlo ha dato un esempio di come costruire partendo dalle fondamenta dei test ogni singolo aspetto dell'architettura di un'applicazione, inclusa l'interfaccia Javascript e l'ambiente di esecuzione dell'application server. Geniale l'idea di Carlo di simulare in un test l'occhio dell'utente che guarda la videata! Non so se questa visione radicale del TDD sia realmente applicabile da noi comuni mortali, ma sono certo che il suo fascino mi rimarrà impresso a lungo.
Ecco il link alle slides di Matteo, mentre rimango in attesa spasmodica di quelle di Carlo.

Conclusioni

Ancora una volta l'Italian Agile Day si è dimostrato un evento eccezionale: complimenti agli organizzatori e arrivederci alla prossima edizione! (A Roma? Io, voto per un Genova-bis! Ma a Milano proprio no???)

P.S. Ricevo da Carlo il link alle sue slides. Ragazzi, non perdetevele!!!

Unit testing with the Saff Squeeze

Yesterday I read an interesting post of Kent Beck about a testing technique called Saff Squeeze. The idea is that, when you have to fix a bug in your code, first of all you need to write an "high level" test (hit the bug high) that shows the problem, then, instead of stepping in your debugger looking for the bug, you try to write a test which goes deeper and deeper in the code, in-lining method calls, until you get to the root of the problem (hit the bug low). It's like the Tai Otoshi Judo throw.


Waterfall

A real world example

As I had to find a bug in my code, I decided to try this technique.

I'm working at an ERP that exports a list of tasks to Microsoft Project. If the user chooses to create a plan scheduled from the finish date, that date has to be the maximum value of the deadlines of each task. Unfortunately there was a bug in this piece of code, so I wrote this test. (Note that, for compatibility issues, I use Java 1.4 and JUnit 3 for the project.)

 
  protected void setUp() throws Exception {
    converter = new XMLConverter();
    projectBean = new ProjectBean();
  }   
 
  public void testIfScheduleFromFinishProjectFinishDateIsTheMaximumValueOfTasksDeadlines() {
    MyDate maxDeadline = new MyDate();
 
    ProjectTaskBean task1 = createTask(1);
    task1.setDeadline(maxDeadline.addDays(-1));
    projectBean.addTask(task1);   
 
    ProjectTaskBean task2 = createTask(2);
    task2.setDeadline(maxDeadline);
    projectBean.addTask(task2);   
 
    ProjectTaskBean task3 = createTask(3);
    task3.setDeadline(maxDeadline.addDays(-2));
    projectBean.addTask(task3);   
 
    projectBean.setScheduleFromStart(false);
 
    String xml = converter.toXML(projectBean);
    TestUtils.assertContains(
		xml,
        "<FinishDate>" +
			new DateProjectConverter().toString(maxDeadline) +
        "</FinishDate>"); //Fails
  }
 

This was my "high-hit" test. As converter.toXML is a full tested method that simply creates an XML from objects via reflection, I supposed that the problem was in projectBean.setScheduleFromStart, so I wrote this new test.

 
  public void testSaffSqueezeExample() {
    MyDate maxDeadline = new MyDate();
 
    ProjectTaskBean task1 = createTask(1);
    task1.setDeadline(maxDeadline.addDays(-1));
    projectBean.addTask(task1);   
 
    ProjectTaskBean task2 = createTask(2);
    task2.setDeadline(maxDeadline);
    projectBean.addTask(task2);   
 
    ProjectTaskBean task3 = createTask(3);
    task3.setDeadline(maxDeadline.addDays(-2));
    projectBean.addTask(task3);   
 
    projectBean.setScheduleFromStart(false);
 
    //projectBean.finishDate is now public for testing purposes
    assertEquals(maxDeadline, projectBean.finishDate);   //Fails
  }
 

The test failed: I was right. Then I tried to modify the test in-lining the code of the failing method.

 
  public void testSaffSqueezeExample() {
    MyDate maxDeadline = new MyDate();
 
    ProjectTaskBean task1 = createTask(1);
    task1.setDeadline(maxDeadline.addDays(-1));
    projectBean.addTask(task1);   
 
    ProjectTaskBean task2 = createTask(2);
    task2.setDeadline(maxDeadline);
    projectBean.addTask(task2);   
 
    ProjectTaskBean task3 = createTask(3);
    task3.setDeadline(maxDeadline.addDays(-2));
    projectBean.addTask(task3);   
 
    //projectBean.scheduleFromStart is now public for testing purposes,
    //and the setScheduleFromStart method is inlined
    projectBean.scheduleFromStart = false;
    if (projectBean.scheduleFromStart) {
      projectBean.finishDate = null;
    } else {
      //projectBean.maxDeadline() is now public for testing purposes
      projectBean.finishDate = projectBean.maxDeadline();
    }
 
    //projectBean.finishDate is now public for testing purposes
    assertEquals(maxDeadline, projectBean.finishDate);   //Fails
  }
 

Then I simplified the test.

 
  public void testSaffSqueezeExample() {
    MyDate maxDeadline = new MyDate();
 
    ProjectTaskBean task1 = createTask(1);
    task1.setDeadline(maxDeadline.addDays(-1));
    projectBean.addTask(task1);   
 
    ProjectTaskBean task2 = createTask(2);
    task2.setDeadline(maxDeadline);
    projectBean.addTask(task2);   
 
    ProjectTaskBean task3 = createTask(3);
    task3.setDeadline(maxDeadline.addDays(-2));
    projectBean.addTask(task3);   
 
    //projectBean.finishDate is set to private again
    assertEquals(maxDeadline, projectBean.maxDeadline());   //Fails
  }
 

So this was time to inline the projectBean.maxDeadline() method.

 
  public void testSaffSqueezeExample() {
    MyDate maxDeadline = new MyDate();
 
    ProjectTaskBean task1 = createTask(1);
    task1.setDeadline(maxDeadline.addDays(-1));
    projectBean.addTask(task1);   
 
    ProjectTaskBean task2 = createTask(2);
    task2.setDeadline(maxDeadline);
    projectBean.addTask(task2);   
 
    ProjectTaskBean task3 = createTask(3);
    task3.setDeadline(maxDeadline.addDays(-2));
    projectBean.addTask(task3);   
 
	//projectBean.tasks is set to public
	ProjectTaskBean maxDeadlineTask =
      (ProjectTaskBean) Collections.max(projectBean.tasks, new DeadlineComparator());
 
    //projectBean.maxDeadline is set to private again
    assertEquals(maxDeadline, maxDeadlineTask.getDeadline());   //Fails
  }
 

Well, at this point I saw that the problem should be in the DeadlineComparator class, so I could get rid of the intermediate tests, rollback the changes to the ProjectTaskBean class and write a test against the buggy class (my "high-low" test).

 
  public void testDeadlineComparatorFindsMaxDeadline() {
    MyDate maxDeadline = new MyDate();
 
	Collection tasks = new ArrayList();
 
    ProjectTaskBean task1 = createTask(1);
    task1.setDeadline(maxDeadline.addDays(-1));
    tasks.add(task1);   
 
    ProjectTaskBean task2 = createTask(2);
    task2.setDeadline(maxDeadline);
    tasks.add(task2);   
 
    ProjectTaskBean task3 = createTask(3);
    task3.setDeadline(maxDeadline.addDays(-2));
    tasks.add(task3);   
 
	ProjectTaskBean maxDeadlineTask =
      (ProjectTaskBean) Collections.max(tasks, new DeadlineComparator());	
 
	//All fields and methods in projectBean are set to their original visibility
	assertEquals(maxDeadline, maxDeadlineTask.getDeadline());   //Fails
  }
 

So this was time to fix-up my code! ;-)

Conclusion

Kent Beck says: "Squeezing encourages good design. If inlining creates too big a mess, back up, clean up the called method, and inline again. Even if I received no other benefits from squeezing, the design improvement would be worth it."

Well, if it's definitely true that you need a good design (or, at least, a not so bad one) for squeezing, I think that it could be difficult to refactor your code when you're doing it: after all, you have a red bar.

Anyway, it seems a nice technique to explore your code without digging in the debugger too much and, this time, it worked fine. :-)

A TDD side effect

All you know that TDD has god side effects. One of them is testing your application :-) Another one is to force you to write less verbose code.
Sometimes (only sometimes ;-) ) when you write production code not writing tests (oh, well I do not do that, ehm) you accept that the code is not as concise and "speaking" as it should be: after all you are writing code that does its dirty work (maybe), that's enough!!! But when you write tests, you know that the goal of test code is to speak to other people. In other words, my attitude when I write production code is to write code that speaks to the machine, while when I write test code I'm trying to speak to people, and you know, when you're speaking to human beings you can't bore them. So your writing must be clear and concise. In order to do that, sometimes you're forced to write some helper classes that, after a short while, you'll find useful on the production side too.

Italian Agile Day 2009 - Le mie impressioni

Un altro Agile Day passato ed eccomi nuovamente a scrivere un sommario della mia esperienza.

Peter Stevens - Fixed Price Projects With Agile It can be done!

Possiamo stimare a priori tempi e costi di un progetto agile? Possiamo applicare i metodi agili quando il costo ed il tempo sono scolpiti nella pietra? Certo, sarebbe bello poter vivere in un mondo in cui tutti i contratti fossero tagliati sul concetto di iterazione, di sviluppo incrementale. Purtroppo ci sono occasioni nelle quali dobbiamo stimare i costi, nei quali dobbiamo sapere se riusciremo a rilasciare entro una certa data, magari remota. Chi, ad esempio, sviluppa il software per gestire grandi eventi come i mondiali di calcio non pu chiedere di spostare la data della finale perch lavora in un team agile e ha bisogno di una nuova iterazione per completare le storie!

Peter Stevens ritiene che lo sviluppo agile si possa adattare a queste situazioni, anzi che sia il miglior metodo da adottare. Questo perch l'unico sistema per valutare in corso d'opera la velocit alla quale lo sviluppo si sta svolgendo.


Waterfall

Per affrontare progetti di questo tipo occorre per:

  • un cliente del quale fidarsi;
  • una pianificazione che lasci "cuscinetti" liberi nei quali compensare eventuali ritardi;
  • criteri certi (e automatizzabili) per determinare quando una funzionalit conclusa;
  • criteri per stabilire l'importanza delle varie funzionalit per realizzare prima le storie pi importanti e consegnare alla fine del progetto, quando la pressione maggiore e le energie si esauriscono, le funzioni di minor rilievo;
  • un team esperto.
  • Maggiori dettagli sulla presentazione si trovano qui.

Alberto Brandolini - Possiamo fare di meglio

La presentazione mattutina di Alberto Brandolini partita da una serie di provocazioni ad effetto sui seguenti temi.

  • Spesso si rompe il rapporto di fiducia tra il software e chi lo usa, sia egli un utente finale o chi fa parte dello stesso team di sviluppo. Scatta allora il meccanismo della "complessit compensativa", cio degli strani trucchi per aggirare i comportamenti errati dei sistemi.
  • A volte gli sviluppatori accettano passivamente i requisiti che sono dati loro: ma chi d questi requisiti il vero esperto del problema, o, se lo veramente, ha avuto modo di pensare ai requisiti in maniera critica? I requisiti non sono in alcuni casi semplicemente la mummificazione di un processo che potrebbe essere invece migliorato?
  • Nei progetti software pu nascere quello che stato definito "technical debt". Brandolini suggerisce una metafora pi calzante per questa progressiva deriva nella qualit del codice: inquinamento, ovverosia un processo estremamente dannoso, difficilmente reversibile e con un tempo di riparazione incalcolabile.
  • A volte lo sviluppatore non ha abbastanza umilt per capire di dover approfondire il dominio da un punto di vista non semplicemente informatico.

Dopo aver introdotto questi spunti di discussione, Brandolni ha lasciato la parola all'uditorio. L'esito di questo esperimento di "terapia di gruppo" a mio avviso non per stato brillantissimo: purtroppo non emerso molto di interessante, se non una collezione di aneddoti sul nostro lavoro.

Pietro Brambati - ASP.NET MVC: Programming & Testing

Dato che prima del pranzo non mi sembrava vi fossero relazioni degne d'interesse, mi sono infilato nell'auletta dedicata alla presentazione dell'ambiente di test creato per .NET MVC. Io odio gli strumenti di sviluppo Microsoft!!! Questo mio sentimento nacque anni fa quando Visual Basic 6, con un fantastico "Il controllo OCX non registrato correttamente", mi fece affogare in un oceano marrone nel bel mezzo di una demo ad un centinaio di persone. Nonostante questo, mi sembrato che il supporto di Microsoft ai test unitari sia discreto e che l'oratore, molto preparato, sia riuscito a dare a i colleghi della sponda Microsoft un buon numero di informazioni utili su come scrivere codice in modo pi efficace. L'impressione comunque che con questo prodotto Microsoft stia svolgendo un diligente compitino per conquistarsi la medaglietta "agile" e la relativa fetta di sviluppatori.

Alberto Quario - Scenario testing

Questo forse stato l'intervento pi interessante della giornata. All'Agile Day si molto parlato di processi, ma ci si un poco scordati del codice. Alberto Quario ci ha riportati nel cuore del problema, citando le parole di Gerard Meszaros: I test possono diventare il collo di bottiglia dei processi agili. (Ma allora non le sparavo cos grosse quando parlavo dei test come palle al piede!). Uno dei principi da seguire per evitare che i nostri test divengano dei mostri incomprensibili, difficili da scrivere, leggere e manutenere il seguente: nel corpo del test deve andare tutto e solo quanto strettamente necessario per la sua comprensione.

Alcuni consigli sono quindi:

  • radunare in metodi dal nome esplicito (operational methods) i dettagli di inizializzazione dello scenario del test
  • se il test prevede, come nel caso si utilizzi DBUnit l'uso di file di inizializzazione, magari in XML, parametrizzarne la creazione rendendone chiaro l'intento all'interno del test

Francesco Mondora: vivere in un angolo proattivo

Francesco Mondora nel corso della sua presentazione ha detto di apprezzare eventuali riscontri da parte del pubblico. Ecco quindi il mio, che purtroppo negativo. Il tema trattato mi apparso fumoso, ed il tono ieratico utilizzato era probabilmente fuori luogo. Ma forse il problema solo mio che non sono riuscito a capire cosa si volesse comunicare...

Alberto Brandolini - Introduzione al Domain Driven Design

Ecco un'altra gran bella sessione, nella quale Brandolini ha descritto con abilit e preparazione i principi del Domain Driven Design.

Entrare nel dettaglio di quanto visto molto difficile, data la mole di informazioni trasmesse. Mi piacerebbe comunque segnalare il concetto di Bounded context, ossia il limite entro il quale il significato di un'astrazione del dominio non ambigua, o, per usare una visione pi orientata al codice, il limite di applicabilit di un gruppo di classi del sistema. Mi sono imbattuto in questo problema quando, nella mia presentazione su Scala, ho parlato di oggetti che ingrassano a dismisura. Da quanto ho capito, anche nel DDD ci si occupa di questo problema, ma da una prospettiva "sistemica": occorre definire l'ambito entro il quale opportuno riutilizzare il codice che definisce un'astrazione. All'esterno di tale ambito meno costoso riscrivere parte delle astrazioni ed accettare una certa duplicazione nei sistemi. Il tema, interessante e complesso, alla base del fallimento di grandi utopie Object Oriented come il progetto San Francisco di IBM. Anzi, a mio avviso mette in discussione tutti i miti dell'Object Orientation a partire dalla riusabilit, ma forse converr parlarne in un'altra occasione.

Conclusioni

Anche quest'anno l'Italian Agile Day non ha deluso le aspettative: relazioni quasi tutte di altissimo livello, con l'apprezzabile idea di aprire a contributi internazionali. Se proprio si vuole fare un piccolo appunto, si dovrebbe parlare di un'eccessiva enfasi posta sugli aspetti di processo a scapito delle sessioni "pratiche", anche se, come avete potuto leggere, i "puri" sviluppatori come me non hanno avuto occasione di annoiarsi.

Grazie a Marco Abis ed ai ragazzi dell'XPUG Bologna per l'enorme e riuscitissimo sforzo organizzativo.
(Ah, avete gi donato qualcosa all'Agile Day? ;-) )

Functional setter Java idiom

The way of organizing the code I will show in this post is very common, but, perhaps, it's useful to give it a name, and I will call it the "functional setter java idiom". Let's see.

In java there are no named parameters, i.e. parameters that I can pass to a method in the order I like calling them with their name. For example in Visual Basic for Applications we can sort some Excel cells this way:

 
SelectedSheets.PrintOut Copies:=1, _
    Preview:=True, _
    PrintToFile:=True, _
    Collate:= True
 

Note that the order in which I set the parameters is arbitrary, and that some parameters can be omitted, having it assigned with default values.

Now let's suppose we need to create an object with a long series of parameters (OK, I know, it's a code smell, but, please, close your nose for a while):

 
PrintType printType = new PrintType(1, true, true, true);
 

Well, not a good piece of code! Especially the sequence of boolean parameters is a mess. Moreover, sometimes I'd like to create my object with less parameters, having the others set with default values. I could create many constructors, but this would increase the complexity of my program.

I could solve the problem using some setters:

 
PrintType printType = new PrintType();
printType.setCopies(1);
printType.setPreview(true);
printType.setPrintToFile(true);
printType.setCollate(true);
 

Uhmm, better enough, but what if I need to assign my object to a constant, i.e. a final static field? I should write:

 
public final static PrintType DEFAULT_PRINT = new PrintType();
 
static {
	DEFAULT_PRINT.setCopies(1);
	DEFAULT_PRINT.setPreview(true);
	DEFAULT_PRINT.setPrintToFile(true);
	DEFAULT_PRINT.setCollate(true);
}
 

Mamma mia, this code is ugly! Maybe I could improve it just a bit using some functional setters, i.e. setters that have a return value, as a function. In the PrintType class I should write:

 
public PrintType setCopies(int copies) {
	this.copies = copies;
	return this;
}
 
public PrintType setPreview(boolean value) {
	this.preview = value;
	return this;
}
 
public PrintType setPrintToFile(boolean value) {
	this.printToFile = value;
	return this;
}
 
public PrintType setCollate(boolean value) {
	this.collate = value;
	return this;
}
 

Now the initialization of my static field becomes:

 
public final static PrintType DEFAULT_PRINT = new PrintType()
	.setCopies(1)
	.setPreview(true)
	.setPrintToFile(true)
	.setCollate(true);
 

This is not so bad, don't you think?

RDS Kata

In questo post mostrer la mia discutibilissima soluzione allRDS Kata proposto sul blog di SI-Agile, il vivace gruppo che raccoglie gli agilisti della Svizzera Italiana. Il codice presente in questo file zip, spero a breve di creare un progetto su Google Code per ulteriori sviluppi.

Funzioni di utilit

Partiamo subito con la prima sequenza di test.
Leggendo tutti i requisiti del Kata, ho pensato fosse necessario avere in primo luogo una funzione che centrasse le stringhe secondo le specifiche. Ho pertanto creato dei test per un metodo statico center da inserire nella mitica classe di utilit StringUtils, che non pu mancare in qualsiasi progetto Java. Il primo banale test, testCenterDoesNotChangeTooLongStrings, mi servito per disegnare linterfaccia del metodo. Per scrivere i test successivi mi sorta la necessit di avere una funzione blanks, che, guarda caso, mi poi tornata utile anche nel codice di produzione. Ho deciso di non scrivere un test specifico per blanks, avendo fiducia che, una volta creata correttamente la funzione stringOf, la sua specializzazione che creasse stringhe di spazi fosse banale.
Uso qui volutamente il termine di funzione, in quanto questi metodi hanno la propriet di trasparenza referenziale, ovvero restituiscono sempre gli stessi valori a fronte dei medesimi ingressi, indipendentemente da un qualsiasi concetto di stato del sistema; inoltre non hanno alcun effetto collaterale. Se ci fosse la possibilit di utilizzare i metodi statici come parametri di altre funzioni ;-)
Concludendo le divagazioni, vorrei solo annotare che, per migliorare la leggibilit del codice e ridurre le duplicazioni, ho fatto un po di refactoring sui test estraendo il metodo assertCenterReturnsAStringOfFixedLength.

Le classi principali

Sono poi passato al disegno principale della mini applicazione tramite i test di RDSGeneratorTest che ho cercato di rendere indipendenti dal numero di caratteri del display.
Leggendo le specifiche del Kata ho cercato di elaborare una metafora: le varie parti da mostrare sul display (autore, data, titolo) sono gruppi distinti di parole, ovvero delle frasi. Ho quindi stilato i test di RDSSentenceTest, facendo anche in questo caso attenzione a rendermi indipendente dalla lunghezza del display. La prima stesura della classe RDSSentence, che comunque supera tutti i test, stata la seguente:

 
public class RDSSentence {
 
  private final String sentence;
  private final int displaySize;
 
  public RDSSentence(String sentence, int displaySize) {
    this.sentence = sentence;
    this.displaySize = displaySize;
  }
 
  public String[] tokens() {
    if ("".equals(sentence.trim())) {
      return new String[]{};
    }
 
    String[] tokens = sentence.trim().split("\\s+");
    if (tokens.length == 0) {
      return new String[]{};
    }
 
    Collection<String> result = new ArrayList<String>();
    StringBuffer accumulator = new StringBuffer();
    for (int i = 0; i < tokens.length; i++) {
       if (accumulator.length() + tokens[i].length() + 1 <= displaySize) {
         if (accumulator.length() > 0)  {
           accumulator.append(" ");
         }
         accumulator.append(tokens[i]);
       } else {
         if (accumulator.length() > 0) {
           result.add(accumulator.toString());
         }
         accumulator = new StringBuffer(tokens[i]);
       }
       if (i == tokens.length -1) {
         result.add(accumulator.toString());
       }
    }
 
    return result.toArray(new String[]{});
  }
 
}
 

Come potete vedere, il codice troppo complesso, con un numero ciclomatico molto elevato. Per un buon refactoring occorreva unaltra metafora: il display che accumula parole fino ad una certa lunghezza pu essere appunto visto come un accumulatore elettrico, o, se vogliamo, idraulico che, raggiunta la capienza, si svuota in un tubo di scarico. Sono nate cos le classi Accumulator e StringWharehouse, che non hanno test autonomi, ma vengono esercitate indirettamente dai test di RDSSentenceTest. La classe StringWharehouse, con una leggera modifica, mi poi stata utile per migliorare il MockRadioStation, che in un primo tempo accumulava i dati in un semplice StringBuffer.

Conclusioni

Cosa ho cercato di esercitare con questo Kata?

Sicuramente non ho raggiunto completamente i miei obiettivi, spero comunque di aver fatto un piccolo passo in questa direzione.

I test unitari sono una palla al piede (se non li sappiamo scrivere)

Troppo spesso i sostenitori delle metodologie agili si fanno trasportare dall'entusiasmo, e, quando cercano di convincere qualche collega ad abbracciare l'agilismo, si lasciano scappare frasi come Quando inizierai a fare i test unitari vedrai che la tua produttività aumenterà. Niente di più falso: iniziare a scrivere i test unitari abbassa drammaticamente la produttività! Per quale motivo? Ho vissuto l'esperienza sulla mia pelle, ma la chiara consapevolezza delle ragioni del fenomeno mi è arrivata quando ho collaborato alla revisione di un ottimo volume pubblicato da Manning: The art of unit testing. Questo è il primo libro che abbia letto a mettere in evidenza un fatto spesso taciuto: i test unitari hanno un costo enorme, specialmente se non vengono scritti nel modo corretto.
Il costo dei test non risiede solamente nel tempo speso per la loro scrittura, ma, come per qualsiasi pezzo di software, soprattutto nello sforzo necessario per la loro manutenzione. Vi è inoltre un'altro aspetto da considerare nell'introduzione dei test unitari: il codice deve essere scritto in modo differente, secondo un design che consenta la testabilità. Questo, però, porta generalmente ad un miglioramento netto della qualità del software, anche se potrebbe indurre qualche programmatore maldestro in inutili complicazioni.
Dunque, perché i test unitari possono divenire una palla al piede? Perchè il neofita generalmente non è in grado di scrivere test che abbiano le seguenti caratteristiche:

Affidabilità

Come dicevo, i test unitari, anche se scritti bene, anche se generati automaticamente, costano. Quelli scritti male costano enormemente di più, ma tutti hanno in ogni caso un costo, quello della loro manutenzione. Siamo comunque invogliati a pagare un prezzo anche salato quando riceviamo in cambio un beneficio maggiore. Il beneficio dei test, oltre al già citato obbligo ad elaborare un design più efficiente, consiste nella loro affidabilità, che dovrebbe rispecchiare l'affidabilità generale del nostro software. Un test dovrebbe fallire se, E SOLO SE, esiste un errore nel software di produzione. Se il test fallisce anche per altre ragioni (un baco nel test, il DB che non è stato inizializzato opportunamente, il fatto che il test funzioni solo sul sitema operativo della mia macchina e non su quello che usano i miei colleghi), allora stiamo buttando dei soldi dalla finestra. Inoltre il test dovrebbe fallire in caso di errori. E' ovviamente impossibile riuscire a scrivere un test per tutti i possibili errori, ma questo dovrebbe essere il nostro obiettivo. Scrivere il test prima del codice, per poterlo vederlo fallire, è una tecnica che ci aiuta in questo senso.

Manutenibilità

Questa è la bestia nera dei test unitari. In molti casi è già un affare raggiungere l'affidabilità, la manutenibilità è in molti casi una chimera. Si dice spesso, a ragione, che dei buoni test aiutano il cambiamento del software. Test scritti male possono essere invece un ostacolo all'evoulzione del nostro programma. Quante volte ho visto andare in barra rossa decine di test per una piccola modifica nel protocollo di comunicazione con un oggetto! Come poter raggiungere questo obiettivo?

In primo luogo con il refactoring accurato del codice di test. Rimuovere duplicazioni dai test è fondamentale per non dover cambiare manualmente tonnellate di codice alla prima modifica nel nostro design.
Un altro punto chiave è quello di cercare di non testare lo stato privato di un oggetto, ma di verificarne il funzionamento in relazione ai suoi collaboratori (trasformati in opportuni Stub o Mock). Se questo non è possibile, allora potrebbe valere la pena di estrarre il comportamento nascosto in oggetti da testare separatamente.
Si deve inoltre fare attenzione a non testare più di quanto sia necessario: l'uso eccessivo di Mock quando degli Stub potrebbero essere sufficienti può farci incorrere in questo problema.

Leggibilità

La leggibilità dei test è fondamentale. Quando va in barra rossa un test illeggibile è come quando si accende una spia sconosciuta sul cruscotto di una macchina di cui non avete il libretto di manutenzione: o andate nel panico, o fate finta di nulla incrociando le dita e sperando che tutto vada bene.
Occorre curare i nomi dei test, senza aver paura di scrivere troppe lettere. testCarrello non significa nulla, testSeAggiungoUnProdottoAlCarrelloAumentaIlTotale indica chiaramente l'intento del test. Altri accorgimenti sono estrarre fasi di inizializzazione in medodi di servizio con nomi espressivi, definire il metodo toString in modo tale che mostri valori significativi in caso di fallimento, evitare di inserire magic numbers e, anche in questo caso, refactoring, refactoring, refactoring!

Conclusioni

Quindi non dobbiamo scrivere test, dobbiamo abbandonare il Test Driven Development (TDD)? No, al contrario, dobbiamo scrivere test con sempre maggiore cura, avendo ben chiaro che i test sono come i figli: non basta farli, poi bisogna anche mantenerli!

Italian Agile Day 2009


Italian Agile Day 2009

E' stata annunciata la data per lo svolgimento del sesto Italian Agile Day: si terr il 20 novembre 2009 a Bologna. Come sempre la conferenza si annuncia interessantissima: vi dar aggiornamenti nei prossimi giorni.