Se devi duplicare il codice almeno non duplicare i test

4 October, 2008 (10:55) | design, programming, test

Ci sono volte in cui è veramente difficile evitare di duplicare un pezzo di codice, tipicamente quando devi rappresentare lo stesso concetto in contesti differenti all’interno della stessa architettura. Il software è per sua natura estremamente flessibile ed è quindi sempre possibile inventarsi qualcosa, infatti nel passato mi sono sempre sforzato tantissimo per trovare soluzioni “creative” per evitare questo tipo di duplicazione, in retrospettiva posso dire che tutte queste soluzioni sono risultate un po’ “tirate”, artefatte, soluzioni che non mi davano quel senso di affidabilità che voglio dal mio codice e che mi fa dormire bene la notte.

Ultimamente ho dovuto affontare uno di questi problemi: in YouRank abbiamo una definizione di domain che consente data un’url di ricavare quello che noi consideriamo essere il dominio di quell’url. Quello che facciamo è eliminare il protocollo, generalmente “http://” e la parte iniziale dell’url se e solo se questa corrisponde a “[wW]{3}[^.]+\.”. Quindi l’url “http://www.gabrielelana.it” avrebbe come identificativo di dominio “gabrielelana.it”

Questo tipo di operazione (estrazione dell’identificativo univoco del dominio di un’url) deve essere eseguita in contesti differenti: sia durante l’elaborazione dei dati di navigazione grezzi (quindi in javascript), sia durante l’esecuzione di query sul database (banalmente per raggruppare i risultati per dominio). Inizialmente, proprio per evitare di duplicare il codice, ho optato per un’implementazione in javascript “yr.uri.Http#domainWithoutPrefix” (metodo domainWithoutPrefix della classe yr.uri.Http), che richiamavo all’interno delle query di sqlite “JS_CALL(“DOMAIN_WITHOUT_PREFIX”, urlOfDomain)” [1], per ogni record del result set dovevo creare un oggetto “yr.uri.Http” solo per poter utilizzare il metodo “domainWithoutPrefix, questo unito al costo del marshalling fra sqlite e javascript, si è rivelato essere superiore al budget :-)

I miei sensi di ragno mi facevano venire la nausea tutte le volte che pensavo all’ovvia soluzione del problema: implementare in C la funzione “DOMAIN_WITHOUT_PREFIX” da richiamare direttamente in sqlite. Ho passato giorni a tentare di immaginarmi soluzioni alternative al problema senza trovare niente. Alla fine ho mollato, ho iniziato a scrivere il primo test automatico e subito ho capito

Stavo sostanzialmente riscrivendo i test che a suo tempo scrissi per “yr.uri.Http#domainWithoutPrefix”, questo si che sarebbe stato veramente sbagliato! Potevo ancora conservare in un’unico punto autorevole la definizione del concetto di identificato di dominio: nei test. In pseudo codice

assertDomainWithoutPrefixIs("gabrielelana.it", "http://www.gabrielelana.it")
assertDomainWithoutPrefixIs("blog.yourank.com", "http://blog.yourank.com")
assertDomainWithoutPrefixIs("example.com", "http://www1.example.com")
assertDomainWithoutPrefixIs("example.com", "http://www123.example.com")
assertDomainWithoutPrefixIs("w12.example.com", "http://w12.example.com")
...

dove

assertDomainWithoutPrefixIs = function(expected, given) {
    assertEquals(expected, storage.call("DOMAIN_WITHOUT_PREFIX", given));
    assertEquals(expected, yr.uri.Http(given).domainWithoutPrefix);
}

Quindi, la lezione che ho imparato è: “Se non è possibile mantenere la definizione di un concetto in un unico punto all’interno del codice, testa tutte le implementazioni esistenti con un unico test automatico, in modo da far diventare il test quell’unico punto”

Link of the week
Quote of the week

No problem. “Easy” in the developer sense, of course, which translates in real life to “theoretically possible and I have a vague plan”

[1] Abbiamo implementato un meccanismo attraverso il quale è possibile invocare delle funzioni javascript (previo setup) da delle query sqlite, niente di esoterico (anche il wrapper a sqlite di mozilla implementa lo stesso meccanismo) solo una precisazione nel caso qualcuno se lo fosse chiesto

Comments

Comment from jacopo
Date: October 6, 2008, 1:21 pm

post davvero interessante gabriele. anche perchè un po’ cerca di spostare il focus di un test DA la singola classe A una singola regola di dominio. un po’ di Behaviour-DD in più e un pizzico di Test-DD in meno.

il compromeso da pagare è l’avere funzionalità che si rompono avendo una barra rossa su test apparentemente scorrelati. è importante mantenere in uno stesso processo di build tutte le “implementazioni” della regola testata.

Write a comment