From Latex to Html

I always loved latex for generating documents. It’s such an elegant way for a developer to “develop” documents!

Then I wanted to produce posts from the latex source I had. This is text manipulation, so I picked ruby and started writing a parser. Then I stopped.

How many times did I write a parser? Probably half a dozen times, for different reasons, but nonetheless it always started with text and ended with nodes.

This time I looked around and found treetop, which lets you write grammars to parse languages into trees and then associate operations to nodes (like converting the node to html).

Of course I could have looked around for a latex-to-html converter or an existing treetop latex grammar, but I wouldn’t have learnt treetop itself.

I just committed the grammar, the ruby script that generates html from nodes and the ruby script that I used for developing it and that reads a .tex file and converts it to html.

git://github.com/inverno/Treetop-Latex-Grammar.git

The grammar is very limited, basically just what I need for my own paper, but, who knows, someone might enjoy playing with it.

Web Apps in TDD, Part 1

What’s this?

This is the beginning of the paper I was writing when discussing TDD with Matteo before he kindly invited me to the Italian Agile Day 2010.
After the talk, and in the days since, I was asked many times to provide more details and the source code.
The first request is certainly best served by publishing the aforementioned paper : it is not complete, so far it is 20 pages, which were enough for my talk, but I think it will take roughly twice that to describe TDD, the way I do it for web applications.
Nonetheless I’ll start posting the paper as it is right now, and more, as I continue the development and the paper itself.

I’ll abide to the second request once the full paper is complete by releasing the full sources along with the pdf version.

So, without further ado, here’s part one : page 1 to page 4.

The context

Here I mean to explain how I use test driven development to help me craft web applications. This is my way of doing it, as it stands now, having evolved during the years through the various systems I had the pleasure to create.

Since I’ve long wished to create a gta-like web game I’ll use it as an example for a new web application.
The game name is “Boss” and it should be played over a browser with a point-and-click interface.
When Boss is called by http it should offer a bird view of a set of city blocks, with the main character standing in the middle of the map. Each city block should be composed of multiple rectangles representing the various buildings.
The main character, a colored dot, should move in the direction clicked by the user’s mouse on the map.

An unusual first step

I’ll start with the first feature : when Boss is called by http it should offer a bird view of a set of city blocks, with the main character standing in the middle of the map.

Well, that’s certainly a lot of stuff to implement and I strongly doubt I’ll be able to implement it within a few minutes, so I’ll try to trim down the problem to be able to write the first test and its solution quickly.

With my first test I’ll just make sure that Boss answers to an http call succesfully. For the sake of brevity I’ll skip a couple loops and presume that a class “Boss” should exist, instead of refactoring it out of the test itself. So, my first test looks like this :


public class BossBehavior {

    @Test
    public void shouldAnswerHttpCall() throws IOException {
        new Boss(8080);
        WebClient client = new WebClient();
        Page page = client.getPage("http://localhost:8080");
        assertThat(page.getWebResponse().getStatusCode(), is(200));
    }

}

WebClient comes with the htmlunit framework, which turns out to be a quick way to invoke an http endpoint.

Of course this fails, as expected.

So I’ll try to make it pass. I don’t plan to re-implement the http protocol, so I’ll go shopping for a nice http server. In the past I used Jetty, but this time I’ll try Grizzly.

After a brief tour on the web I try this :


public class Boss {
    
    public Boss(int port) throws IOException, InstantiationException {
        SelectorThread selector = new SelectorThread();
        selector.setPort(port);
        selector.listen();
    }

}

This returns a nice null pointer exception. To be specific I see this line :


java.lang.NullPointerException
	at com.sun.grizzly.http.ProcessorTask.invokeAdapter(ProcessorTask.java:824)

Hm, well, I didn’t pass an Adapter to the SelectorThread. Some more reading and I get this :


public class Boss {
    
    public Boss(int port) throws IOException, InstantiationException {
        SelectorThread selector = new SelectorThread();
        selector.setPort(port);
        selector.setAdapter(new AlwaysReturn200Ok());
        selector.listen();
    }

    private static class AlwaysReturn200Ok implements Adapter {
        public void service(Request request, Response response) throws Exception {
            response.setStatus(200);
        }

        public void afterService(Request request, Response response) throws Exception {}
    }
}

It works fine, the test is green.
Now I’ll proceed to some refactoring, but first, a brief note : is this a unit test?

Actually, I don’t care. The only thing which I care about is that this test is quick, repeatable, short, simple and it will work everywhere I have port 8080 available.

In fact, port 8080 is quite used nowadays (default tomcat servers for development purposes and so on…), let’s change that to 11111 from now on. Just to stay safe.

And now some refactoring

First the test, when I switched to port 11111 I forgot to update the url on which WebClient was performing the call, a nice reminder of that clumsy duplication I introduced.
Also, the test is a bit too involved in the details of WebClient, let me fix this before moving to refactoring Boss itself.

I stop when I get to this :


public class BossBehavior {
    private static final int OK = 200;
    private static final int PORT = 11111;

    @Test
    public void shouldAnswerHttpCall() throws Exception {
        new Boss(PORT);
        assertThat(Http.callOn(PORT), is(OK));
    }
}

Http contains little special, just the call to WebClient and the extraction of the status code.

Now I’ll move to Boss. Currently Boss is just a tiny http server which always answers 200 OK. From a responsibility point of view there’s little to do, but I definitely don’t like that “200” which appears both in the test and the solution.

In the context of my application the code 200 is just a way to say the answer is positive. I don’t like using primitives to represent high-level concepts, such as “positive answer” and I certainly don’t like duplicated primitive values.


public class HttpAnswer {

    private final int statusCode;
       
    public static HttpAnswer ok() {
        return new HttpAnswer(200);
    }

    public HttpAnswer(int statusCode) {
        this.statusCode = statusCode;
    }

    public void writeTo(Response response) {
        response.setStatus(statusCode);
    }
...
}

While a bit verbose, this class removes the status 200 duplication in test and solution code and it slims down both, while letting me express the intent more clearly. Here’s the current situation for both test and solution :


public class BossBehavior {
    
    private static final int PORT = 11111;

    @Test
    public void shouldAnswerHttpCall() throws Exception {
        new Boss(PORT);
        assertThat(Http.callOn(PORT), is(HttpAnswer.ok()));
    }
}

public class Boss {
    
    public Boss(int port) throws IOException, InstantiationException {
        SelectorThread selector = new SelectorThread();
        selector.setPort(port);
        selector.setAdapter(new AlwaysReturn(HttpAnswer.ok()));
        selector.listen();
    }

}

To make the tests assertions work and to get nice messages in the future I’ll implement equals, hashcode and toString for HttpAnswer. I use the excellent EqualsBuilder, HashcodeBuilder and ToStringBuilder classes from apache.


public class HttpAnswer {
...
    @Override
    public boolean equals(Object other) {
        return EqualsBuilder.reflectionEquals(this, other);
    }

    @Override
    public int hashCode() {
        return HashCodeBuilder.reflectionHashCode(this);
    }

    @Override
    public String toString() {
        return ToStringBuilder.reflectionToString(this);
    }
}

The Software Craftsman’s Guide to the World

A few weeks ago I started this map after a discussion on the Software Craftsmanship list.

The idea is simple : there are developers looking forward to meet others for a discussion or a bit of pairing, there are companies looking forward to welcome people to work with them for a while and share ideas, there are houses which may offer hospitality to fellow developers, so why not putting them all on a map with contact information?

I mentioned this idea at the Italian Agile Day 2010 and a few people have been asking me for more information, so here it is :

The Software Craftsman’s Guide to the World

On prefixes and suffixes

Lately I’m doing a bit of C# programming, as I’m having fun with the Unity game engine and suite (and boy, it is cool!). Unity allows you to write game logic in C#, JavaScript and Boo.
I started with JavaScript, but then I switched to C#, just for the sake of it.

There I had quite a surprise. C# base libraries (and thus, I would expect, most of C# code out there) prefix interfaces with “I”!!


IList, IDictionary, IWhatever.

When C# first came out and later on as new versions appeared I glanced at the language features and I liked what I saw, especially since C# seemed far bolder than Java in updating its syntax to new features, and doing it well (my feelings where kind of confirmed when Neal Gafter moved over to Microsoft to work on .NET).

That said, finding this naming convention so deeply rooted in C# culture pains me to no end.

I’ve had a look around and I saw quite a few blogs criticizing it, yet the real point about why the “I” for Interface is not a good idea didn’t appear very often, and when it did, it seemed like an afterthought.

I will express this point with a question : “Why would a client ever need to know that some type it is using is an interface?”.

“Client” here means any bit of code using some other bit of code :


oneMethod() {
IList list = new ArrayList();

In this exemple “oneMethod” is the client of the list.


anotherMethod(IList list) {
list.doSomething();
}

Here again, another method is a client of the list.

For the purpose of expressing a problem’s domain and the logic for solving it, advertising the fact that IList is an interface is uninteresting.
The client code using an interface has no need to know about it, nor the developer reading that code!

What is even more important is that prefixing the interface shows that the interface is considered just a technical “trick”, a convenient, but meaningless literal which happens to be part of the language.

Interfaces must always represent the core roles of a system, the main actors on stage. They must do so crisply and unambiguously, as those are the actors we will spend most of our time looking at.

If my system sends payments over the network I do expect that the main roles get first-class names : Payment, Connection, Customer.
If some of these happen to be interfaces I do expect their implementations to get second-class, specific names, since I won’t look at them often, unless I need to delve one step lower in the details : DirectPayment, DelayedPayment, TCPConnection, BankCustomer, InsuranceCustomer…

When observing “I” infested code I notice that the first-class name (Customer, Connection..) is given to the main implementation of the interface, or, worse, the sole implementation of the interface. In this case the interface is perceived as boilerplate (and it is likely so) : I need to have an interface, so let’s extract it and put a convenient prefix before it.

Other times the use of prefixes seems to arise from having apparently expended all “good” names. I stress the “apparently” : I’ve yet to find a case where it is impossible to give both a meaningful name to the interface, representing the overall concept for the system, and to the implementations, representing the details.

Provided that one stops to think long enough.

Finding good names needs time. A serious naming effort is often the beginning of a new understanding; usually that’s the understanding that our roles are wrong and we should look for better ones, which leads to further costs.

By using plenty of prefixes and suffixes instead (I, A, Manager, Processor, Decorator, Impl, Service, Factory, Bean…), we can write code much faster, it spares us much of the thinking, in fact, most of the time we can just stop thinking about names, almost anything can be forced to fall within the range of a random combination of prefixes and suffixes :


ITransferManager, ProcessorService, ServiceFactory, ProcessorDecoratorImpl

and, of course, DecoratorProcessorImpl !

While here is a sample of what we might be missing (traslating 1 on 1 to meaningful names) :


PostOffice, MailBox, MailAccount, RemoteMailBox, UnsortedMail

By using prefixes and suffixes we are truly wasting the semantic potential of our code.

It’s the same kind of waste that we could obtain by naming functions after the number of their parameters : setString1(“”), setString2(8,””).

We wouldn’t dream of not naming the second setString as what it actually is : setSubstring.
Yet we do so all the time with classes.

Often we do this for the sake of “standardization”. This a classic of groups where a chief developer puts down the architecture and then enforces a set of rules for class names : “And thou shall call ye spring initialised objects “Beans”, and those which are not shall be “Factories”…”.

Standardization is nice, and it is perhaps the only positive point I see in pattern-based prefixes and suffixes, but the standardization effort happens long before the real domain of the system is clear and has slowed down evolving; this leaves the standardization authority with pretty few clues on proper names and so it falls back to enforcing technical roles. The developers behind the lead will have one less reason to look for good names : they are not expected to do so.

So, to sum it all up, when prefixes and suffixes see large use, the favoured programming habit is often “write fast, read slow”. This is the recipe for huge, bloated code, where technical details get advertised everywhere and arise to prominence in spite of the problem domain. And I don’t like it.

I’m looking at you, Controller.

A day strolling in town

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

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

(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

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

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.