A day strolling in town

ottobre 29, 2009

First and foremost :
it is very likely that all of my posts from now on will be in English.

During the last year or so, I’ve felt that during conversations, both face-to-face and online, I needed to point to one of the posts on this blog. I think this is very natural, as I’ve kept adding bits of reasoning to this blog for many years now and, even though my views change and shift, I do happen to repeat myself (far more frequently than anyone would like).

This is all good and nice, except that my Italian-based conversations are just a share of the whole and, while I might expect for an Italian fellow to be able to read English, I can’t really confide for the opposite to be true.

Hence, from now on, I’ll stick to English.

Curiously, this post is something I’ll hardly refer to in a technical context, but I’ll nonetheless write it in English.

It is now 14:45. I’m sitting on a bench in Lausanne’s Riponne plaza.

I’ve been out and about since this morning, 8:30 am.

I hardly ever quit my routine : work, go home and code/watch movies/talk with gentle wife/stay put. I rarely spend more than a couple hours outdoors and when I do it is usually in the mountains or other very secluded places.

I was astonished at the number of things which happened around me by spending a significant amount of time in a town like this.

First I looked for a parking near the city centre. The concept of a centre in Lausanne is murky. The town stands on multiple hills (pretty steep hills if I may say) on the north shore of Lake Geneva. The morphology has not helped and it took me a while to sort out which was the real city centre.

Anyway, I finally decided that the Riponne parking lot was fine enough for my goals.

Riponne

First of all, I break my fast with a tea and a croissant. Fascinating how a mediocre tea is 3.50 CHF and an excellent croissant is just 1.20.

Then I continued my quest for a pair of good clip-on headphones. Since I’ll be living in Lausanne from now on, while my wife will stay back at home, I’ll have to spend long hours in a train heading back home in the week-ends. This is why I sorely need headphones, you wouldn’t expect me to bother the whole train with a TechQ presentation on domain driven design.
The problem is I hate intra-aural earbuds and almost any full headset which I cared to test would cause long-lasting pain in my ears after a few minutes of use. It is related to the ears being pinched between the two phones. I thought I had found an headset which was gentle enough, but after buying it and using it for more than half-an-hour my ears started aching badly and it lasted for hours after I removed it. So I gifted it to my wife’s brother.

So now I’m looking for clip-on headphones, much like these.

I left the patisserie where I had my breakfast and begun by entering a Sony shop. No luck, the Sony guy was astonished I was looking for such a bizarre apparel and mentioned that while he had seen some in the -past- (with the tone you would expect of an elder grandpa talking about the war) he was pretty sure they did not exist anymore, in Switzerland at least.

Then I spotted Fnac, which was cozy and well-appointed as usual, with a vast choice of headsets and earbuds, but no clip-ons.

Anyways, from the top of Fnac I had a commanding view of Flon, it is a former industrial area which sits in between two of Lausanne’s steep hills. It has now been restructured and a number of shops have opened down there.
Most importantly I spotted a Pathé! I love the pathé theatres.

After Fnac I tried three different InterDiscounts, MediaMarkt, Bang and Olufssen (yes, they do have 245 CHF earbuds and a 1250 CHF cordless phone, but no clip-ons), the Audio-Center, and the Auditory Area, which turned out to be a clinic specialized in hard of hearing old fellows with a large budget, think Amplifon for rich guys. In there they -did- have clip on headsets, just not the kind which you can jack to a computer.
Finally I went to a nokia shop, where the guy looked at me with an hint of irony and said : “you know, you should look in shops where they sell computer stuff, did you check Fnac?”
I answered positively and fell back out in good order.

Thanks to the above-mentioned morphology this search was tantamount to hiking.

Then I visited Lausanne’s Cathedral. Which, of course, stands on the peak of the tallest hill. In there I found a little presentation on John Calvin, who appears to be the local super-hero when it comes to religion.
There’s also a medieval building hosting a lycée in the Cathedral Citadel. Full of teenagers of course. The turds did not deserve such a fascinating school building.

I climbed down the citadel just to the bottom, heaven to hell, in Flon, where I bought a couple of ham-filled croissants for five francs.

As I was sitting on a bench eating my croissants a lady approached me and told me she was from Yugoslavia and without a work permit. I gave her ten francs. So she sat beside me and told me about her husband back in Belgium who beat her, and how she was in Switzerland since three weeks, with her little sister and two daughters.

Good lord. I gave her 20 more francs before I could finish my lunch. She was good conversation, except for the repeated petitions for more money, or for work. I very much wished to have a need for an house-cleaner, as she claimed to be quite good at it, having worked in hotels in Belgium.

One of the best moments was when she told me that she earned 1000 euros per month in Belgium, working as a room-cleaner in hotels. I chuckled and I suggested her to not try her luck in Italy, as 1000 euros is standard fare for young developers.
She looked surprised.

After leaving her I asked a nice grandma where was the train station, she told me to take the Metro and showed me to it, just to be sure I would not get lost.
She told me I did not sound like an Italian. I was not surprised, for some reason I don’t have an Italian accent when I speak French. Years ago I was told I sound Canadian, so I asked her how I did sound to her, and she said she was sure I was from the UK. I thought that, since Canadians can be defined as a mix of french and englishmen, she was not far from the spot, so I told her I agreed with her interpretation and we parted in friendship.

And yes, Lausanne has got two Metro lines. Fascinating. Since the tickets are time-based and allow you to use the metro for half an hour, no matter how many rides you take, it is perfectly wasteful to buy two tickets if you can get to the train station, buy a ticket back to Lugano for your wife and return in less than thirty minutes.

Thus, when I arrived at the train station I was looking for a reason to waste some time and justify my second ticket for the metro.

In the train station there was a pretty complex queue system and a dark-colored fellow asked me how it did work. I told him that I presumed he had picked the wrong queue and that he should be in mine. Then I suggested him to take my place in the queue, since he had arrived before me and, were it not for his mistake, he would be before me.
I stepped back at the beginning of the queue.

But it was of no use, a Swiss queue is often a quick queue, and I had to wait just three more minutes before being able to buy the ticket.
Stupid efficient Swiss cashiers.

I found out that the metro would bring me just where I had parked the car, so I was spared yet another climb up the hill.

So now I’m back here, I went to the car, took the laptop and the umts key and came to sit on this bench.

Of course it took me some time to write this post, it took even longer than expected because a little pest decided to come by and type all over my keyboard, the mother is still explaining him he should not do that :

The Little Pest and His Mother

It took so long that I had the time to notice a peculiar phenomenon. Over the hours (it is now 4 pm) that I’ve been sitting on this bench in Riponne plaza a lot of people with laptops have come to sit beside me on this same bench or the next one.

We are now at my third computer-assisted guest, and I could not spare to take a photo, as sitting by a Tibetan monk with an HP laptop on a bench in Lausanne is something that is worth a photo. See the azure area? That’s me, and that’s the monk.

Seven Years in Lausanne

Most notable is also that the monk was the only one who talked to me :

It seems he could not find Lausanne’s Wifi. I told him I doubt there is one, as I don’t get any reading on my Wifi and I’m connected through umts instead.

He was disappointed and left a few minutes after.

This might explain why many people chose to sit next to me and each one left after a while.

I must look like I’m sitting in a hotspot.

Time to leave and go collect my wife, she must be almost to the end, where they hang the company owners because they caused the death of a dozen miners.

I suppose.


Bikkey

settembre 25, 2009

Negli ultimi due o tre anni ci siamo messi in tre a creare un sito di ricette.
Ci abbiamo potuto lavorare sporadicamente, quando la voglia e l’energia permettevano, e il creeping featurism ci ha davvero messo in difficolta’ per lunghi periodi.
Anche grazie ai suoi lunghi iati e’ stato il banco di prova per una serie di tecnologie e soluzioni architetturali che, nel tempo, sono filtrate in tre diversi progetti che ho seguito per lavoro, e intanto lui strisciava piano piano avanti.
Ad ogni modo, era ben ora che ne rilasciassimo la prima versione e siamo davvero contenti.

Quindi, se vi capita di voler cucinare qualcosa con quello che avete in frigo, fateci un salto, il nome e’ bikkey.


Finally here we are, and it is called… CSD

settembre 13, 2009

(this one in english, for the usual reasons)

A few days ago Ron Jeffries made an announcement on the XP mailing list as well as on his blog:
prompted by the Scrum Alliance, Ron, along with other Agile methods gurus, is working on an agile developer certification.

I’ve seen many XP certifications proposals appear on the XP list over the years, to see them disappear shortly after, and never felt sorry for it.

Now this one sounds a lot like an XP certification, or, anyways, very close to it.

On the part of Ron, the main reason for the decision to join in the effort is :

For me, my thought is that if certification is to happen, I’d like to try to guide it to be as good and as smart as possible.

I fully agree with the pragmatic value of this position. Yet I’m somehow sad.

This said, the team is indeed promising and I’m ready to get positively surprised, so I joined the list where the new certification is being discussed.

The second draft proposal by Chet Hendrickson is promising.

Other topics currently being discussed on the list less so. For instance I’m troubled by some suggestions that the certification be open for graduates only. It has also been suggested that the exact kind of degree would not matter, just a degree, be it in electronics or physics.

Hopefully this sort of bizarre discrimination will not get far. An agile developer certification is difficult enough to get right without presuming that degrees are an indication and a requisite of a dedicated professional.

Charming times to live indeed, critical times.


Mostri sacri che sanno fare dell’autocritica

luglio 21, 2009

Questa e’ una delle caratteristiche che amo tra i veri grandi. La capacita’ di criticare le proprie azioni e il proprio pensiero, o anche cestinare per intero un sogno, con semplicita’, senza maschere.
Spesso capita di assistere a lunghe autocritiche psicologiche, un po’ new-age, che in verita’ sono solo apologie prive di costrutto.

Tom De Marco (che ha scritto Peopleware, un libro brillante) ha recentemente criticato con grande franchezza l’approccio “misura-e-controlla” nell’ingegneria del software, da lui stesso promosso vigorosamente per molti anni. Merita leggerlo, come ogni autocritica vera, non si nasconde dietro a un atteggiamento colpevole, ma un sincero “A non era giusto per questo motivo, B invece era giusto per quest’altro motivo, in fine ormai sono convinto di C”.

Lo stesso si puo’ dire dell’analisi di Kent Beck sulla sua scelta di smettere lo sviluppo di JUnit Max che io personalmente non condivido, ma lui ha sicuramente il punto di vista piu’ completo della situazione.
In particolare ammiro come, dopo aver rinunciato a quello che lui stesso definisce un sogno, ancora caldo di questo “fallimento”, dopo che gli e’ stato fatto osservare che forse non aveva spinto correttamente sul marketing del prodotto, non ha indugiato a spiegare come no, il marketing non era debole, era ben calibrato : ha sbagliato a pensare che JUnit Max potesse avere una solida base di utenti, e l’ha detto, sul marketing non ha sbagliato, e gli andra’ meglio con un altro progetto.

Punto.

Questa e’ l’autocritica : si riconoscono gli errori di fondo e li si spiega, perche’ chi ha fatto l’errore e’ la persona piu’ indicata a identificarlo e spiegarlo.

Spesso noi comuni mortali interpretiamo l’analisi e la spiegazione dell’errore come una specie di giustificazione : “Guardalo li’, sempre a giustificarsi”.

Questo e’ dovuto al fatto che noi comuni mortali siamo abituati all’autocritica di scusa, quella con cui ci autoaccusiamo di quanto accaduto sperando di alleviarne il senso di colpa e in cui non cerchiamo con pensiero limpido le cause prime, cerchiamo piuttosto il solievo della confessione. Non c’e’ crescita nell’autoflagellazione, soltanto l’acquietarsi della propria coscienza, non per niente questo genere di confessione tende a ripetersi errore dopo errore.

In particolare la meccanica a cui siamo piu’ abituati e’ : io che sono in una posizione di debolezza e sbaglio devo confessarmi per rappacificare me e gli altri, chi e’ in posizione di forza, secondo questo criterio, non ha bisogno di alcuna confessione. Per questo, quando i grandi non si scusano, bensi’ si spiegano e fanno un altro passo in avanti, lo confondiamo per orgoglio.

Dovremmo invece tenerci in tasca i rimorsi di coscienza, per quanto scomodi siano, e cercare con tranquillita’ le cause prime e spiegarle con la maggiore precisione possibile, senza alcun fine di scusa. L’autoflagellazione e’ una forma di snobbismo : ci chiudiamo all’analisi e ci poniamo sul piedistallo del peccatore.

Di solito quando l’autocritica e’ una forma di confessione mascherata si capisce abbastanza facilmente : la confessione identifica rapidamente il problema nella persona.
-Mi sono distratto, devo stare piu’ attento-
-Non sono abbastanza bravo-
-Dovevo lavorare di piu’-

Quando il problema identificato risiede nella persona allora l’autocritica (o la critica) mi puzza di flagellazione e buoni propositi.
Darsi la colpa e’ solo una varianzione sul tema di dare la colpa a qualcunaltro, serve solo a convincerci di aver “fatto qualcosa” per rimediare al problema, senza essersi veramente dati la pena di cercare il problema. Una persona puo’ fare un errore, o molti, ma, se abbiamo fiducia in quella persona e’ molto piu’ interessante scoprire cosa ha causato quell’errore, veramente. Cercando la causa prima, senza distribuire colpe inutilmente, per poi lavorare per costruire un contesto che minimizzi tali cause d’errore o che le renda ininfluenti.

Dopo esserci dimenticati di aggiungere una variabile al lancio di uno script che ha mandato all’aria un giorno di lavoro dovremmo essere molto piu’ interessati a spiegare come togliere quella variabile e rendere l’errore impossibile, mentre invece ci concentriamo sul dettaglio morboso delle dinamiche che ci hanno portato alla fatale distrazione.

I grandi che hanno timore di essere giudicati si comportano come noi comuni mortali : si autoflagellano quando devono e si negano quando possono. I grandi, quelli veri, mettono in discussione gli assunti che li hanno portati a sbagliare, il piu’ possibile dritti al punto, senza timori.

Mi piacerebbe imparare ad analizzare il fallimento di un mio sogno con la tranquillita’ intellettuale di Kent che abbandona JUnit Max, senza cercare la mia colpa, ma solo cercando l’errore, ovunque sia, senza scuse, con sincerita’ scientifica.


Degenerazioni

luglio 3, 2009

Come, spingendo sui patterns e sui principi object-oriented si giunge a costruire del codice perfettamente procedurale.

Forse un anno fa sulla lista di xp-it qualcuno aveva scritto un post che diceva piu’ o meno cosi’ :
“Nel sistema che stiamo sviluppando ci sono voluti giorni interi per identificare quale interfaccia implementare per passare ad avere una diversa gestione delle sessioni, ma poi sono bastati cinque minuti a scrivere l’implementazione, senza dover modificare niente altro…”

Ricordo che ai tempi osservai qualcosa di questo genere “Ho idea che si sia fatto un gran lavoro di isolamento dei concerns, ma che non si sia costruita una metafora del sistema”. Questo genere di situazione lo vedo nascere quando, invece di concentrarsi sull’esplicitare i concetti del dominio del problema si ci concentra sull’applicazione di patterns e principi di design da un punto di vista puramente “meccanico”.

Che cosa intendo per approccio “meccanico”?

Intendo il fenomeno per il quale, identificata della logica condizionale nel codice la prima cosa che si fa e’ iniziare a riflettere su come eliminarlo utilizzando uno dei meccanismi messi a disposizione dai linguaggi OO.
Ad esempio, questo :

for(String name : names) {
Account account = retrieveAccountByName(name);
account.fooTheBars();
}

Diventa subito questo :

names.forEach(new FooTheAccountBars());

Questo :

if(type == "CREDIT") {
sendMailTo("pippo@pippo.com");
debitAmount = 0;
}
if(type == "DEBIT") {
debitAmount = amount;
}

Si trasforma in questo :

accountType.perform();

E cosi’ via.
Queste trasformazioni tendono a rispecchiare dei patterns conosciuti (una caramella a chi riconosce il pattern del primo esempio) e a seguire i valori di modularita’, sostituibilita’ e isolamento tanto cari al design object oriented (e non solo). Lo dimostrano le metriche, che saranno certamente migliori di quelle del codice originale, anzi, potranno giungere ad essere davvero ottime : “Guarda mamma, senza if!”

Software costruito in questo modo avra’ molte o tutte le caratteristiche meccaniche di un sistema object oriented, ma gli manchera’ il bagaglio informativo.

Trovo che gli elementi che nascono da un tale design non descrivano il dominio del problema da risolvere, piuttosto rappresentano, ad oggetti, la soluzione procedurale al problema.

Faccio un altro esempio (non lontano da codice che ho scritto io allegramente) :

Door door = new Door("123019");
....
RequestReceiver receiver = new StreamLineSplittingReceiver(new XmlParsingReceiver(new FilteringReceiver("comment"), new DoorRequestReceiver(door))));
.....
DoorStatus currentStatus = receiver.receive(xmlStream);

Questo codice descrive chiaramente la soluzione procedurale : quando ricevo una richiesta per una serratura, prima estraggo l’xml dallo stream, poi lo parso, poi filtro via i commenti e infine reagisco alla richiesta.

Fallisce miseramente invece nel descrivere i concetti di base del sistema.


Door door = new Door("1230401");
....
KeyOperationBuilder builder = new XmlKeyOperationBuilder(new CommentsFilter("comment));
XmlSource xmlSource = new MultilineXmlSource(stream);
....
....
String xml = xmlSource.nextXml();
KeyOperation keyOperation = builder.buildKeyOperationFrom(xml);
keyOperation.operateOn(door);
DoorStatus currentStatus = door.status();

Questo secondo codice non utilizza meccanismi OO per comporre la procedura; usa gli oggetti per rappresentare i concetti e una procedura per rappresentare la loro interazione.

La catena di decorazioni di prima e’ quello che sto giungendo a considerare un virtuosismo, nel senso negativo del termine : un’ostentazione fine a se stessa. Usare la composizione di molti oggetti per rappresentare una sequenza di chiamate qualunque non porta a una migliore esplicitazione del dominio del problema e quindi non porta un vero vantaggio di semplificazione concettuale.

Sostituire un if con una strategia non porta necessariamente alla costruzione di un’astrazione significativa per il nostro dominio e lo stesso si puo’ dire di moltissime trasformazioni che, per quanto migliorino le metriche, sono solo virtuosismi meccanici.

Trovo che proprio nel refactoring di codice legacy o nell’esecuzione in tdd di uno nuovo sviluppo sia facile cadere in questo genere di virtuosismi. Personalmente mi piace -non- pensare mentre scrivo la soluzione a un test rosso. Buona parte del pensiero avviene mentre scrivo il test. Il guaio e’ che si puo’ cominciare a non pensare anche mentre si rifattorizza.

Una volta che si e’ praticato il refactoring abbastanza a lungo si puo’ giungere ad applicarlo automaticamente, come riflesso condizionato. Di fatto il pensiero si ferma a : c’e’ un if -> rimuovo l’if con… e le mani partono da sole a lavorare.

Questa e’ una degenerazione della pratica del refactoring e degli strumenti che il paradigma ad oggetti offre. All’identificazione di uno smell si ci dovrebbe interrogare sulle sue cause prime, in particolare se per caso quello smell non nasca dalla necessita’ di approfondire la nostra rappresentazione del problema con nuovi e diversi concetti.

La verita’ e’ che buona parte dei difetti meccanici (e quindi identificabili tramite delle metriche) del codice procedurale sono risolvibili costruendo con gli oggetti delle funzioni di ordine maggiore.

Quasi ogni variazione del comportamento durante il processo di sviluppo del software e’ gestibile con un altro strato di indirezione.

In questo modo pero’, quello che avviene e’ che si reifica la procedura, non il dominio del problema.

Sono i concetti latenti dietro una soluzione (gia’ implementata e in corso di rifattorizzazione, o solo disegnata sulla lavagna o nella mente di qualcuno) che hanno bisogno di essere resi espliciti e concreti nella forma di un oggetto.

Ho scritto migliaia di linee di codice che rispecchiassero al meglio incapsulamento, sostituibilita’, segregazione e compagnia bella, ottenendo risultati non esplosivi che hanno permesso al sistema di procedere sotto controllo, ma le uniche occasioni in cui ho potuto riprendere in mano del codice sentendo di poterlo portare a un nuovo livello di funzionalita’ senza alcuno sforzo e’ stato quando quel codice rappresentava delle storie : nel codice che amo davvero ci sono figli che raccolgono l’eredita’ dei padri (addebiti diretti bancari con possibilita’ di rifiuto dell’addebito anche dopo mesi), conversazioni che si compongono di altre conversazioni (IO di un sistema di pagamenti), dottori con le loro sonde (diagnostica) e cosi’ via.

I nomi non devono essere necessariamente fuori dal contesto per dimostrare la presenza di una metafora forte; anzi, i nomi evocativi spesso sono solo un modo per mascherare la debolezza del modello che si e’ scelto.
Cio’ che conta e’ come la metafora dia significato alla distribuzione delle responsabilita’, e’ come il dominio fornisca livelli sempre piu’ alti di astrazione del problema (e non parlo di classi astratte). Di solito, trovato il modello che meglio descrive il problema si ha la strana impressione di aver perso un sacco di tempo nell’arrovellarsi per trovare una soluzione che era evidente sin da subito. Mio nonno in carriola. La soluzione finale dell’esempio del bancomat della Wirfs-Brock parla di tastiere, scontrini e schermi, ma non per questo basta parlare da subito di tastiere, scontrini e schermi per ottenere un buon design.

Parlare del problema usando gli oggetti che veramente lo definiscono e semplificano, scoprire queste storie dietro a un problema che percepiamo come una sequenza di operazioni, e’ sempre difficile; e’ qualcosa che mi riesce saltuariamente, ma che trovo valga la pena cercare con costanza.

Questa ricerca virtuosa, a cui e’ dedicato DDD e esemplificata in questo post di Matteo, e’ l’estremo opposto del fenomeno pernicioso che ho descritto in questo post, che porta a usare degli oggetti e interi patterns per descrivere delle procedure invece che il contrario.
L’ho osservato per molto tempo, notando il degenerare dell’uso degli oggetti mano a mano che si cessava di cercare il significato e si ci concentrava solo nel gestire l’espandersi degli assi di variazione del sistema e l’ho discusso veramente per la prima volta con un collega in cui riflettevamo su come si possano usare i patterns basati sulla composizione per descrivere un algoritmo arbitrario e di quanto questo sia dannoso.

Concludo chiedendomi se, immaginando di trovare con affidabilita’ il giusto modello di ogni problema, potremmo davvero fare a meno di interrogarci su tutti i temi che, nell’ingegneria del software, in particolare la rottura delle dipendenze, ossessionano i principi di design a oggetti.


E’ una questione di assenza di stile

aprile 18, 2009

Qualche giorno fa si parlava dello stile del software davanti a una birra. In particolare la questione era la facilita’ con cui si fa nascere un’interfaccia : c’e’ chi prima di tutto scrive l’interfaccia del componente da implementare, poi scrive l’implementazione, c’e’ chi scrive l’implementazione e appena ha finito ne estrare l’interfaccia, c’e’ chi scrive l’implementazione, usa l’implementazione, vede che tutto funziona e poi estrae l’interfaccia sostituendola all’implementazione per ogni uso; in fine c’e’ chi scrive l’implementazione, la usa, non estrae l’interfaccia, scrive un’altra implementazione per tutt’altra faccenda e si accorge che si puo’ identificare un contratto comune tra i due componenti implementati e a quel punto estrae l’interfaccia per poi procedere alla sostituzione negli usi.
(Una piccola nota di colore : in questo periodo mi trovo a lavorare un sacco su carta. Le stesse sfumature nell’approccio si applicano alla carta cosi’ come ai sorgenti, cambia solo la rappresentazione, basta usare il termine “scrive” con “disegna” e il resto e’ uguale)

Nello scambio di battute ci siamo trovati a identificare gli stili con un paio di maestri : Eric Gamma e Robert Martin. In particolare, guardando Fitnesse e la predilezione per la concretezza delle classi, io parlavo dello “stile di Martin” come quello che fa uscire le interfacce tardi, solo se strettamente necessarie; guardando invece i sorgenti di Eclipse, in cui praticamente ogni concetto viene esposto tramite un’interfaccia ben separata dall’implementazione, mi veniva da parlare dello “stile di Gamma” come quello che definisce l’interfaccia a priori.

Ci ho ripensato un paio di giorni fa.

Quello che stavamo facendo era parlare di diverse sfumature nel processo di creazione del software caratterizzandole con i nomi di creatori di software di cui noi osserviamo soltanto il prodotto finito.

Stupido, stupido, stupido!

Era come se avessi dimenticato di chi stavo parlando. Pensare che uno qualsiasi di questi due maestri lasci trasparire il suo processo di lavoro nel prodotto finito al punto da poter dire “in Eclipse ci sono interfacce ovunque, quindi Gamma scrive subito l’interfaccia” e’ come aspettarsi di capire, guardando la nave completa, come abbia lavorato lo studio di progettazione, con quali modelli, se fisici o simulati, o entrambi, e quanto di frequente.

Cosi’ come i colpi di scalpello dati al modellino in legno non compaiono e non devono comparire nella carena del vascello, pur essendo stati strumentali a crearla, un professionista non puo’ includere nella sua definizione di “finito” nulla che non riguardi strettamente le caratteristiche del sistema richiesto. Se c’e’ una cosa sicura e’ che la sequenza dei singoli passi usati per arrivare alla versione rilasciabile, le caratteristiche del metodo di progettazione, comunque si vogliano chiamare, non hanno nulla da spartire con le caratteristiche richieste dal cliente.

Perche’ Fitnesse e’ molto concreto? Perche’ Fitnesse deve fornire funzionalita’ rapidamente a chi lo usa, la comodita’ d’uso si manifesta quasi unicamente nella velocita’ con cui si riesce a far fare a Fitnesse quello che desideriamo usando il nostro codice. Perche’ Eclipse ha un sacco di interfacce? Perche’ Eclipse e’ una piattaforma che deve garantire miriadi di punti d’accesso che restino, con affidabilita’, uguali a se stessi. Questo non e’ design anticipatorio, tutte quelle interfacce rispettano una necessita’ molto attuale di Eclipse : la possibilita’ per delle terze parti di investire nello sviluppo di prodotti finiti, anche di elevato valore, senza trovarsi a lavorare direttamente con degli “internals” passibili di cambiamento repentino da una minor release all’altra.

Un processo di sviluppo ha un solo modo di fallire : non rispondere alle necessita’ degli utilizzatori; siano questi gli sviluppatori che si trovano a lavorare con i suoi sorgenti o siano gli utenti della sua interfaccia grafica. In nessuno dei due casi la sequenza con cui e’ stato creato il suo progetto puo’ giustificare l’inadempienza. Quindi, per forza di cose, un professionista non puo’ manifestare il suo “stile” nel prodotto finito (che sia una singola storia o un’intera major release di Eclipse), puo’ solo manifestare quanto il suo stile gli dia la capacita’ di rispondere alle esigenze degli utilizzatori (interni ed esterni). Quindi non e’ lo stile che posso identificare, ma la qualita’ esibita (o la sua assenza).

Fitnesse nell’essere concreto sta esibendo qualita’, Eclipse nell’essere disperatamente indiretto esibisce, del pari, qualita’.

Quindi, in via puramente teorica, se lo sviluppatore mira alla perfetta aderenza alle necessita’ del sistema e dei suoi utilizzatori finali, capisce di esservi giunto proprio quando riconosce che lo “stile” e’ svanito, ed ogni idioma, ogni scelta implementativa, ogni nome, e’ riconducibile alla dedizione nel rispondere a queste necessita’, non alle meccaniche usate per giungere a rispondervi.


Cicli di Vita

dicembre 28, 2008

E’ un po’ di tempo che mi trovo spesso a parlare di cicli di vita degli oggetti. Il ciclo di vita e la sua massimizzazione e’ un criterio che ho sempre dato per scontato, seguendolo quasi per senso estetico, e mi viene naturale usarlo per motivare certe scelte.

Visto che il natale a casa dei miei presenta molto tempo libero e pochi computer ho pensato di sfruttare l’occasione per buttare giu’ qualche linea esplicativa del problema dei cicli di vita cosi’ come lo vedo io. Se non altro questo post mi permettera’ di far finta di non aver perso un sacco di tempo lontano dal computer e davanti alla tv.

(Riguardo alla tv, ho visto per la prima volta Piccolo Lord, bellissimo)

Immagino di avere un’applicazione che viene lanciata e rimane in ascolto di richieste di qualche tipo, la classe centrale a questo software avanzatissimo si chiama A, se non altro perche’ non ho idea di quello che il sistema debba fare di queste richieste, so solo che a un certo punto verranno stampate, quindi il nome A va bene come un altro :

one1DoSomething e’ il metodo che viene invocato a ogni richiesta e di questa richiesta riceve un valore molto importante “K”.

Il metodo e’ chiaramente separato in tre parti :

- La configurazione, con le new del Chooser e del Printer

- La logica, vedi l’IF

- L’output, con la Choice che si esegue e si stampa tramite il printer

Una sequenza classica.

Dovendo identificare la distribuzione di responsabilita’ tra gli oggetti non ci troveremmo molto di male, ci sono un sacco di oggetti, praticamente uno per linea, il printer ha la responsabilita’ di stampare, il chooser di scegliere, le choice 1 e 2 di eseguire quello che devono eseguire. Volendo fare i pignoli potremmo dire che la responsabilita’ di fare una scelta e’ distribuita tra il Chooser e A. Si perche’ il Chooser dice se K ha cosato i cosi oppure no, ma e’ A che decide che se K ha cosato i cosi allora bisogna usare Choice1, altrimenti Choice2.

Esporre l’associazione tra il valore ritornato dal Chooser e la Choice concreta non e’ bello, potremmo invece nasconderla tutta dentro al Chooser, che sembra avere ottime ragioni di contenerla (Tell, don’t ask per dirne una).

Eppure questo codice, per quanto faccia uso di un sacco di oggetti e contenga forse solo un punto veramente negativo non e’ affatto estensibile. Anzi, qualunque modifica richiedera’ di infilare le mani dentro ad A. Bisogna stampare su un printer diverso? Via a pacioccare. Bisogna cambiare la Choice quando K == Pippo? Via a pacioccare, dentro ad A o dentro a Chooser, poco importa.

Tutti questi oggetti e non ho nessun vantaggio.

La cosa da fare mi e’ sempre parsa ovvia, ma ho visto talmente tanto codice di questo tipo, con tutte le responsabilita’ belle divise nei vari oggetti, ma con tutti gli oggetti creati al volo, che credo valga la pena di non dare nulla per scontato.

Inizio con un primo esempio di quello che intendo con “massimizzazione del ciclo di vita”. Il diagramma che ho immaginato per caratterizzare i cicli di vita degli oggetti e’ un po’ uno spettrogramma, all’estrema sinistra dell’asse si trovano gli oggetti con un periodo di vita piu’ lungo, mentre andando verso destra i periodi di vita si accorciano e quindi, sempre rimanendo nella metafora spettrale, le frequenze di creazione e distruzione aumentano verso destra.

Ecco come si piazzano gli oggetti sullo spettro :

one-phase

Il ciclo di vita piu’ lungo e’ quello della init dell’applicazione e li’ si trova solo A, poi ci sono gli oggetti che nascono e muoiono ad ogni request : Chooser e Printer. Infine ci sono Choice1 e Choice2 che compaiono solo in uno specifico branch dell’IF.

Volendo posso evidenziare con simpatici colori pastello le aree delle tre frequenze che si manifestano nel codice. Verde e’ la frequenza di inizializzazione dell’applicazione, giallo quella del flusso delle request e rosso quella dell’IF :

one-colors

Ora, se si guarda Printer si vede che non c’e’ nulla che impedisca di inizializzarlo assieme ad A invece che ad ogni richiesta.

C’e’ pero’ anche il problema delle Choice1 e 2 gestite da A invece che dal Chooser. Quindi passo ad applicare entrambe le modifiche.

two-a1

Questa e’ la classe A modificata, l’if e’ finito nel Chooser, la responsabilita’ di scegliere l’azione da eseguire in funzione di K e’ ben incapsulata nel Chooser e ad A rimane il puro coordinamento.

Sicuramente un miglioramento netto, almeno, a guardarlo. All’atto pratico il codice non e’ piu’ chiuso al cambiamento di prima. La differenza forse e’ che dovro’ mettere le mani in pasta in Chooser se voglio cambiare l’associazione K -> Choice, piuttosto che in A.

Infatti la posizione dell’IF e’ un’altra, ma Choice1 e 2 ricadono sempre nella stessa banda di frequenza, nascono nell’IF :

two-chooser

Dal punto di vista della chiusura al cambiamento e apertura all’estensione l’unico miglioramento reale e’ dato dallo spostamento di printer. Effettivamente ora se bisogna cambiare la strategia di printing non e’ piu’ necessario toccare A.

Sullo spettrogramma e’ cambiato qualcosa :

two-phase

Il Printer ora nasce e muore con l’applicazione, possiamo immaginare che diventi configurabile anche senza ricompilare, ad esempio se l’inizializzazione avviene con Spring, ma non e’ necessario spingersi fin li’, il vantaggio e’ gia’ evidente se pensiamo che ora possiamo avere differenti main nella nostra applicazione, con A che gestisce richieste che vengono stampate in un modo o nell’altro semplicemente scegliendo il main da lanciare.

Sarebbe bello poter configurare ogni aspetto del nostro server, non solo il modo in cui stampa, ma al momento siamo lontani. L’obiettivo pero’ dovrebbe essere chiaro a questo punto, fare uscire il maggior numero di oggetti possibili e farli passare alla banda piu’ bassa, la init. La banda di base ha il pregio di essere un punto in cui la composizione degli oggetti si trasforma immediatamente in configurabilita’ del sistema intero.

Tornando al Chooser, e’ immediatamente evidente che le due Choice non hanno bisogno di nascere nell’IF, non necessitano di K per esistere, anzi, a K non sono per niente interessate. Sempre con l’idea di massimizzare il ciclo di vita degli oggetti possiamo tirare fuori le new delle choice dall’if e farci passare le choice nel costruttore per poi usarle come variabili d’istanza. A questo punto il polimorfismo che l’interfaccia Choice ci permette torna utile anche a Chooser, non solo ad A :

three-chooser

Piu’ in “alto” si riesce a far galleggiare un’interfaccia piu’ saranno i vantaggi ottenuti, spostare le new, col fatto che sono estremamente concrete, aiuta ad estendere l’applicazione dell’interfaccia e ridurre le dipendenze concrete. In effetti questa stessa mossa, che presento sulla base del ciclo di vita, ha la sua motivazione nel principio di inversione delle dipendenze : meglio non avere qualcosa di concreto (Chooser) che dipende da qualcos’altro di concreto (Choice1 e Choice2).

A dire il vero tutto quello che riguarda il ciclo di vita degli oggetti puo’ essere descritto e motivato da SRP (una responsabilita’ e’ la configurazione, un’altra la logica di esecuzione) e da DIP, l’obiettivo raggiunto in fine (la composizione) puo’ essere descritto in termini di OCP, come avevo gia’ accennato sopra. Puntare l’occhio sul ciclo di vita per me e’ un comodo cambio di paradigma che mi permette di vedere le forze messe in campo da questi tre principi come un unico criterio, dall’applicabilita’ certamente ridotta, ma molto limpida. Almeno per me!

Quando all’inizio ho detto che quel codice non aveva particolari debolezze di design non era vero, in verita’ ogni new rappresentava una responsabilita’ di troppo, per quanto le responsabilita’ esecutive fossero delegate agli oggetti, A aveva un sacco di responsabilita’ di configurazione che non doveva avere. Allo stesso tempo A era una grossa classe concreta che dipendeva da un sacco di classi concrete. Volendo uscire dai principi di design raccolti da Martin avevo gia’ citato Tell don’t Ask, ma si puo’ anche fare entrare in campo responsabilita’-collaborazione, con l’ambiguita’ del ruolo di A e di Chooser.

Insomma, era un gran guazzabuglio. Eppure chissa’ perche’ e’ un guazzabuglio che risulta poco evidente, altrimenti non mi spiegerei perche’ vedo cosi’ spesso delle new sparse in giro quando il loro ciclo di vita dovrebbe portarle a galleggiare verso l’alto e verso le basse frequenze.

Tornando allo spettrogramma ecco come si presenta ora :

three-phase

A questo punto l’ultimo passo e’ facile, ne’ Chooser ne’ le due Choice hanno bisogno di K per esistere e quindi le si puo’ far saltare nella frequenza piu’ bassa :

four-a

Cosi’ alla fine, se guardo le frequenze degli oggetti del sistema ho questo diagramma :

four-phase

Questo diagramma significa che la init ora potra’ avere questo aspetto :

four-init

La parte dichiarativa del nostro sistema adesso e’ ricca, mentre il flusso appare semplificato. Volendo togliere l’IF l’avrei potuto fare subito sostituendolo ad esempio con una mappa che associasse i valori possibili di K con una Choice particolare, ma per come era distribuita la costruzione degli oggetti mi sarei trovato a riempire una mappa dalla vita effimera, dentro a doSomething. Ridicolo. Ora invece e’ legittimo immaginare di avere un Chooser a cui vengono fatte delle chooser.set(“K1″,new Choice1()) etc. etc. Sempre nella Init, ovviamente.

Poteva anche andare peggio, il salto sulle basse frequenze e’ possibile solo se K lo concede, in caso K fosse stato un parametro necessario alla costruzione delle Choice queste sarebbero rimaste inchiodate sul rosso.

In quel caso si sarebbero forse usate delle factories per fare un ponte verso le basse frequenze : Choice1 nasce nel rosso, ma la decisione che e’ Choice1 a nascere, piuttosto che Choice2, viene fatta nel verde sfruttando una factory : chooser.set(“K1″,new Choice1Factory());

Credo pero’ che il factory pattern possa spesso essere evitato riflettendo sulle interfacce : il vantaggio di avere un parametro nel costruttore e’ enorme, perche’ permette di avere un’interfaccia che non dipende da quel medesimo parametro (il metodo non espone alcun argomento e quindi alcuna dipendenza), ma non sempre questo grado di incapsulamento e’ necessario. A volte si possono evitare catene di factories che sono li’ solo per permettere di avere configurabilita’ attraverso tre bande di frequenze diverse semplicemente ammettendo di servire queste tre frequenze con dei parametri nei metodi dell’interfaccia.

In breve avrei potuto riassumere tutto con un : ma insomma, quando fai la fatica di definire una nuova classe e dargli una responsabilita devi portare l’inizializzazione dell’oggeto il piu’ in alto possibile, se no non te ne fai niente. Ma visto quanto e’ comune il non portarlo su ho pensato che il mio piccolo modello frequenziale potesse spiegare bene l’evidenza.

Prima di un altro post del genere credo che dovro’ aspettare pasqua.


Eccezionale

luglio 14, 2008

Non so da dove sia venuto fuori, non so chi lo abbia fatto, ci sto ancora girando dentro, ma sono gia’ stupefatto da questo sito :

http://sourcemaking.com/

E’ stato prima citato sul Jug Roma, poi ribaltato sul Jug Torino, dove finalmente ha attirato la mia attenzione tra un pomodoro e l’altro.

Bello da vedere, comodo, chiaro e, da quello che ho potuto vedere in questi minuti, rischia di essere una delle risorse online piu’ complete per quello che concerne patterns e refactoring.


Artefatti

luglio 10, 2008

Una degli eventi migliori della mia settimana e’ stato cadere sull’ultimo articolo del blog di Ivar Jacobson.

Questo articolo di fatto conferma la tesi di Larman su RUP e conferma quello che ho sempre pensato : nessun metodologo con intenti onesti puo’ proporre un quantita’ di artefatti senza che questi siano funzionali alla buona riuscita. In particolare ho sempre odiato quella documentazione che viene richiesta “perche’ e’ necessaria”. Necessaria a cosa?

Prima vediamo a cosa serve e come sara’ usata, poi capiamo se sia necessaria.

Altrimenti diventa quella che Jutta Eckstein chiama “documentazione write-only”.

Io preferisco di solito tenermi lontano da disquisizioni metodologiche, preferisco concentrarmi sul mio lavoro e sul creare software non troppo imbarazzante, e’ pero’ inevitabile trovarsi a mettere in discussione delle richieste che fanno arenare lo sviluppo effettivo di un prodotto e che sembrano (o sono) ingiustificate. Non a caso mi e’ capitato in passato di dover buttare giornate e contestare la richiesta di un documento gia’ condannato al write-only solo per poter evitare di buttare molte piu’ giornate a redigerlo.

Penso che sia un dovere del tecnico proteggere la produttivita’ del proprio tempo di lavoro.

In questo contesto ho trovato rinfrescante come il guru di RUP (un processo spesso accusato di essere molto artifact-intensive) pone la questione :

Organizations fail their people when they require artifacts without explaining why they are needed, or helping them to understand if they are needed, or helping them to improve their skills doing the real work that the artifacts merely document.

Amen padre, amen!


Infrastruttura, approccio greedy e qualita’

maggio 4, 2008

Sulla mailing list di xp e’ stata sollevata la questione dell’approccio all’architettura in XP. Io non ho la presunzione di parlare per conto di alcuna metodologia, ma tendo ad apprezzare molto i risultati che ottengo quando riesco a impormi di non fare scelte in anticipo.

Riporto qui la mia posizione sull’architettura e sul ruolo dell’architetto, come espressa sulla ML, con piccole modifiche per evitare riferimenti esterni, e che non vuole essere altro se non la mia attuale percezione del problema :

Se vediamo l’architettura come l’insieme di quelle decisioni che sarebbero troppo costose da cambiare ex-post (non ricordavo chi lo diceva, ma mi e’ stato fatto notare che probabilmente mi arriva da Fowler) io credo che le capacita’ architetturali debbano manifestarsi proprio nel disinnescare quelle decisioni e renderle inoffensive per il futuro, questo per me passa dalle spike, per affrontare le incognite tecnologiche, come suggeriva Uberto, e dal tdd, per garantire un design disaccoppiato e coeso.

L’obiettivo e’ che ogni modifica sia localizzata, anche modifiche che in altri sistemi sembrerebbero inesorabilmente “strutturali” (che e’ un altro modo per dire “architetturali”, che e’ un altro modo di dire “costa troppo per cambiarlo”).

Ecco, per me e’ questo che dovrebbe fare un architetto. Che e’ poi quello che dovrebbe fare uno sviluppatore; se poi si lo si vuole chiamare “architetto” a me va benissimo, basta che passi piu’ tempo a programmare e condividere la sua conoscienza di quanto ne passi a diagrammare.

Anche dopo solo due storie di solito la scelta del framework dovrebbe avere piu’ elementi che se fatta in partenza. Il meccanismo per me rimane lo stesso anche in seguito, entrando in questioni come le transazioni, la scalabilita’ e via discorrendo.

Ammetto che per poter scegliere le cose all’ultimo bisogna aver fiducia nelle capacita’ degli sviluppatori, avere fiducia che creino del software sufficientemente malleabile. Per non fare “l’architetto”, e quindi non fare scelte a priori, devi avere degli sviluppatori che siano in grado di disinnescare quelle scelte che altrimenti sono critiche.

Premesso che gli sviluppatori siano in grado di farlo, magari concedendo un 40% di “junior”, non di piu’, io fino ad oggi credo che il maggior guadagno lo si ottenga programmando con il resto del team, a prescindere dalla propria esperienza, quindi mirando a rendere non critiche le scelte critiche e formando, dove serve, i “junior”.

In un team del genere non penso davvero sia necessario fare alcuna scelta strutturale a priori, nemmeno per quel che concerne la persistenza o il framework web. In un team diverso forse si dovrebbe davvero ricadere all’architetto vecchio stile. Argomento ricco.

Detto questo c’e’ la questione di come seguire una tattica greedy come quella del “fai solo quello che serve”, mi permetto di sintetizzare il discorso con l’affermazione : e se la tua soluzione ottima localmente si dimostrasse un cul-de-sac quando si manifestano necessita’ strutturali nuove che la tua implementazione minimalista non solo non e’ adatta a supportare, ma che di fatto ostacola con la sua sola presenza?

Per illustrare la mia idea al riguardo ho rispolverato photoshop e ho fatto qualche disegnino… l’architettura e’ chiamata infrastruttura di proposito, non rappresenta la qualita’ di design del codice, e potrebbe essere richiesta per motivi che esulano dallo sviluppo dell’applicazione in se’. In ML si parlava di reporting, tanto per dire.

La tonalita’ di grigio rappresenta il costo/difficolta’ per spostarsi in una qualunque direzione.

Quindi, senza ulteriori indugi, ecco il panorama che spesso si ci trova a considerare :

Se immaginiamo un approccio YAGNI ecco cosa succede : partiamo con un’infrastruttura minima per avere un senso nel contesto dello sviluppo (tanto per dire, la piattaforma software, il modello generale, client-server, solo client, cose cosi’) e partiamo a sviluppare features senza troppa fatica


A questo punto notiamo, ad esempio, che se ci appoggiassimo a un database e magari a un framework di persistenza le prossime features ci costeranno meno :

A questo punto siamo in un minimo locale, siamo molto contenti, ma ci fanno notare che la prossima iterazione ci sara’ da buttare dentro il reporting, o magari bisognera’ far scalare e parallelizzare. Siamo in una conca e abbiamo due alternative, distruggere quel poco di design che abbiamo inserito e iniziare a spingere su per la collina, con costi in continua crescita, l’affidabilita’ che cala e sempre meno strada fatta a ogni iterazione, la marcia della morte :

Altrimenti possiamo riconoscere che la qualita’ della nostra applicazione non ci permette di inserire a basso costo una funzionalita’ trasversale come la scalabilita’ e che dobbiamo appuggiarci a un’infrastruttura molto piu’ complessa, ma ormai e’ tardi, possiamo solo scegliere se tornare in dietro (sull’asse delle features), riscrivere tutto o quasi tutto con un’infrastruttura molto piu’ complessa (in giallo), o tentare un “porting” sulla nuova infrastruttura (in rosso), in entrambi i casi il cliente sara’ molto scontento, nel peggiore dei casi ci troveremo a dover aggiungere features in un sistema in grande transizione per “tener buono” il cliente :

A questo punto vediamo che in fin dei conti si poteva architettare tutto prima e spingere da subito verso “la valle” invece che la conca.
Se tutte le previsioni dell’architetto -qui una figura isolata, che guarda lontano, prima ancora che il cliente chieda lui scruta l’organizzazione in cui il prodotto andra’ a inserirsi, che prevede ben altro che le necessita’ tecniche, ma anche gli incerti del cliente- dovessero avverarsi si finisce nella valle, dove il lavoro puo’ iniziare con le migliori premesse. Se niente cambia si puo’ procedere e chiudere il progetto.

Cosa succede se invece l’architetto non c’e', ma abbiamo un numero sufficiente di sviluppatori esperti nel far emergere l’architettura a ogni passo e tengono il sistema veramente disaccoppiato?
Nella mia umile opinione non si velocizza tanto il lavoro in se’, ma cambiano le curve dell’equazione, il sistema si piega bene a quello che vogliamo fare, quindi la valle e’ piu’ vicina, non c’e’ una grande collina tra la conca e la valle, piuttosto mi immagino che ogni aggiunta in features si trovera’ (se la modularita’ e’ veramente e intimamente tale) davanti a un panorama che si ripete, con caratteristiche geografiche piu’ piccole, piu’ facilmente percepibili anche da chi si trova a lavorare ogni giorno dentro al codice.

Mantenendo alta la qualita’ credo che possiamo mirare ad aggiungere features senza preoccuparci di pensare a priori piu’ di quanto non serva per evitare di andare in una direzione evidentemente sbagliata. Piu’ siamo in grado di fare evolvere l’architettura piu’ la parte grigio chiaro sara’ ampia, le propaggini delle colline saranno piu’ piccole, perche’ aggiungere infrastruttura non ci costera’ troppo, purche’ non si esageri (a destra) al punto che questa vada a intaccare il design e aumentare i costi di sviluppo.

Se ci chiedono di aggiungere infrastruttura a fini di integrazione col resto della piattaforma saremo in grado di aggiungerla senza pagare il prezzo di una ristrutturazione che diventa sempre piu’ difficile.

Ad ogni modo aggiungeremo infrastruttura gradualmente, la cosa che pero’ mi preme sottolineare e’ come, con del software molto malleabile, le conseguenze delle scelte sono piu’ visibili, sono piu’ “vicine” ed e’ piu’ semplice individuare la strada e questa strada sara’ probabilmente sempre rivolta verso l’aggiunta progressiva di nuove features, senza grandi balzi di fede o sforzi di ristrutturazione.

Io credo che questo profilo geografico si ottenga solo se l’architetto e’ lo sviluppatore e viceversa, altrimenti il codice si muovera’ su tutta un’altra geografia. Basta anche solo che la duplicazione cresca un minimo perche’ la “lumaca” ricompaia, le scelte diventino di piu’ lungo periodo e i rischi di queste scelte aumentino, basta che per modificare la gestione dell’accesso al database si debba andare a toccare piu’ di un singolo punto perche’ questa diventi ristrutturazione e la collina avanzi per bloccarci nei nostri movimenti a destra.

L’approccio greedy (fai solo quello che serve, la cosa piu’ semplice etc.) funziona solo se ogni giorno ridimensioniamo la geografia del nostro progetto mantenendolo snello a prescindere.