Archive for March, 2010

Answering Luca’s comment

Saturday, March 20th, 2010

Luca Minudel commented on my previous post. My answer has got so long that it became a full post.

Hi Luca,

I’m a fan of the Growing Object-Oriented Software book, but I haven’t adopted the mockist style yet. I know that I have seen lots of instances of mock misuse, leading to unreadable and brittle tests. So I’m afraid it depends a lot on who’s doing the training :-) It’s true that the GOOS book promotes good object-orientation.

My point in my previous post was not advocating a particular style of training. It is simply to answer a common question. “If we work incrementally without design upfront, as all the books on TDD advocate, is there a risk of getting in a situation where adding some features becomes unreasonably expensive?” This fear is often related to non-functional requirements.

I think this fear has merit, and it’s too easy for new converts to TDD (including me) to confidently say “we have the tests, we can refactor the code to make it do whatever is needed.” The bug in this reasoning is that we should not code with the expectation to do (what often amounts to) major refactoring. We should code with the objective of producing a system where implementing new stuff is so easy that it feels like composing Lego bricks, or like putting the last piece of a puzzle, when it slides comfortably in its place.

Getting to a design that is this good is the real goal of TDD and XP. I can’t say in all honesty that I can achieve this level of goodness in major applications. But I’m beginning to see how one could do that.

So the point of my post is that you can afford to work in a totally incremental way, only if you are dead serious about keeping your code squeaky clean. Which is not easy to do, given the time pressures we always have. But then again, this is nothing new, this is what the XP books have been saying from the beginning, isn’t it? Only it is surprising to discover how really clean your code should be.

Coming back to your comment, it seems you are concerned with ways to help a team to do the right thing and produce good code. My experience is that the first step is to know your material well. So if you’re accomplished producing good code in the mockist style, more power to you! Your team will pick it up from you.

It’s interesting that you found it easier to communicate good style using the mockist approach rather than teaching principles like OCP and Demeter. I’ll have to think about it.

Dear reader: if you haven’t read Growing Object-Oriented Software yet, I invite you to do so. It’s not a book about “mocks” simply. It’s a book about a style of software development, deeply and beautifully object-oriented. For a taste of the authors’ style, I suggest you to read their paper Mock Roles, Not Objects (pdf).

A frequently asked TDD question

Thursday, March 18th, 2010

Today I and Tommaso facilitated the kickoff of a new project for a new team. One question that came up was:

We know that before the project is finished, we will have to profile all buttons and links so that users will not see options they are not authorized to use. Should we keep this in mind as we write the code today? Or should we rigidly adhere to YAGNI and defer all work on profiling until the profiling story is chosen by our customer?

This question comes up quite often. An answer that is often heard by agilists is

Never! Today you should only work for today’s story! The profiling story might never be chosen, after all, and even if it is chosen, you will refactor your code to accomodate the new functionality. YAGNI, my friend!

Tommaso rightly objected that this point of view is wrong. When the moment of link profilation comes up, the application is usually at a late stage of development. Refactoring all links and buttons to include profilation takes a lot of work. And we knew this functionality was coming, so we can’t even invoke the “customer changing their mind” excuse.

Agile development can only work if we can keep down the cost of adding functionality even late in the development cycle. This should apply to unforeseen changes, and even more so to features that we always knew were needed. If a change requires major reworking, then we clearly did something wrong.

What do I suggest then? Should we build in infrastructure right at the beginning for all major features? Should we do design upfront to protect us from this sort of mistakes?

Well, there is not a clear-cut answer. Naive reading of the TDD book will lead you to believe that just applying the TDD mantra

  1. Red—Write a little test that doesn’t work, and perhaps doesn’t even compile at first.
  2. Green—Make the test work quickly, committing whatever sins necessary in the process.
  3. Refactor—Eliminate all of the duplication created in merely getting the test to work.

Kent Beck, Test Driven Development by Example

will lead you slowly but surely, almost automatically, to a well-written system that makes it easy to add changes at all times. Well, there is a huge misunderstanding here. There is nothing “almost automatic” in this process. If you read carefully the book, it will also say things like “Our designs must consist of many highly cohesive, loosely coupled components”.

Just how highly cohesive and how loosely coupled our systems must be, is something that is left to the judgment of the reader. Which in most cases is not skilled enough to imagine just how cohesive and decoupled people like Kent Beck think when they say “cohesive and decoupled”. Most people don’t understand how serious people like Kent Beck are when they say “eliminate all of the duplication”.

Because if you’re not fanatical about removing duplication, about striving for code that is highly cohesive and decoupled, there is little chance of achieving code that is easy to change over time.

My answer is that if I am serious about removing duplication, then I will *not* have code like <a href='foo'>bar</a> written in more than one place; let alone in hundreds of places. I will have a single function, a single method, a single place where the html link is generated. Then when the time comes to add profilation, or HTTPS, or Ajax, or anything else that affects how my links should work, then I will have a *single* place to change. The change will not be too expensive.

If I don’t think I can work with the level of discipline it takes to really remove duplication, then perhaps I’ll be better off stopping pretending I’m really doing TDD, and start doing some design upfront.

Lazy proxy in Ruby

Thursday, March 11th, 2010

I’m a total newbie when it comes to Ruby evaluation tricks, so when I learned this today I felt it was a good thing to share :-)

The problem: speeding up a Rails application. When all is said and done, you need to cache page fragments in order to speed up an application significantly. For instance: you start with

class ProductsController < ApplicationController
  def category
    @products = Product.find_by_category(params[:id])
  end
end

...

<div id="products">
  <% for product in @products do %>
    <!-- some complicated html code -->
  <% end %>
</div>

and then add fragment caching in the view with

<% cache "category-#{params[:id]}" do %>
  <div id="products">
    <% for product in @products do %>
      <!-- some complicated html code -->
    <% end %>
  </div>
<% end %>

OK, this speeds up view rendering. But we are still executing the query in the controller, to obtain a list of products we are not even using. The standard Rails solution to this is

  class ProductsController < ApplicationController
    def category
      unless fragment_exist? "category-#{params[:id]}"
        @products = Product.find_by_category(params[:id])
      end
    end
  end

This is nice enough. But one things is worrying me, is there might be a race condition between the “unless fragment_exists?” test and the call to “cache” in the view. If the cron job that cleans the cache directory executes between the two, the user will see an error.

I thought to myself, wouldn’t it be nice to give the view a lazy proxy in place of the array of results? The lazy proxy will only execute the query if it is needed. The controller becomes:

class ProductsController < ApplicationController
  def category
    @products = LazyProxy.new do
      Product.find_by_category(params[:id])
    end
  end
end

The LazyProxy magic is surprisingly simple:

class LazyProxy < Delegator
  def initialize(&block)
    @block = block
  end

  def __getobj__
    @delegate ||= @block.call
  end
end  

The block given to the constructor is saved, and not used immediately. The Delegator class from the standard library delegates all calls to the object returned by the __getobj__ method. The “||=” trick makes sure that the result of @block.call will be saved in an instance variable, so that the query is executed at most once.

So the idea is that the view will be given a lazy proxy for a query. If the fragment exists, the view code will not be evaluated and the proxy will not be used. No query. If the fragment does not exist, the lazy proxy is used and a query is executed. There is no race condition, for there is no test to see if the fragment exists.

What do you think?

Update One additional advantage of the lazy proxy is that you no longer need to make sure that the fragment key is the same on both view and controller.

Prima lezione del corso di Tecnologia e Applicazioni Internet

Sunday, March 7th, 2010

Summary: first lesson with my new class. Teaching TDD, letting the students get a glimpse of how skilled they are in programming; which is unfortunately not much.

Per il secondo anno insegno Tecnologia e Applicazioni Internet all’Insubria. Il mio obiettivo per questo corso è di insegnare come sviluppare applicazioni web, applicando le pratiche tecniche di Extreme Programming. In particolare, vorrei insegnare Test-Driven Development e i principi di Object-Oriented Design, per come li capisco. Il mio meta-obiettivo per questo corso è fare in modo che lo studente diventi il doppio più bravo a programmare.

Per questo corso uso Java e non Rails. Il motivo di questa scelta è che Rails, per quanto sia una spanna sopra a tutti i web framework in Java, è purtuttavia un framework e in quanto tale è una stampella, una gruccia, che ti permette di stare in piedi ma certo non ti aiuta quando vuoi imparare a camminare da solo, men che meno a correre. Per imparare a camminare da soli bisogna imparare a programmare a oggetti.

In Aula

Per la prima lezione ho spiegato il TDD da solo, senza la complicazione delle servlet. Mi sono sforzato di pensare a un esempio che fosse piccolo a sufficienza per fare una demo di fronte agli studenti, in un pomodoro o poco più. Ho deciso di fare un “calcolatore a riga di comando”, ovvero un programma che presa una stringa come “2 + 3” come argomento sulla riga di comando, stampi “5.0” su standard output.

Il primo test che ho scritto:

@Test
public void twoAndThreeIsFive() throws Exception {
	Calculator calculator = new Calculator();
	double result = calculator.add(2, 3);
	assertEquals(5.0, result, EPSILON);
}  

Abbastanza semplice da far passare. Ma non era sufficiente, perché dalla riga di comando gli argomenti arrivano come stringhe e non come interi già parsati. Per cui ho scritto un secondo test che ha fatto emergere una classe Parser

@Test
public void willParseTwoAndFive() throws Exception {
	Calculator calculator = new Calculator();
	String result = new Parser(calculator).calculate("2 + 5");
	assertEquals("7.0", result);
}  

Perché creare una seconda classe a questo punto? Non sarebbe bastato mettere il metodo “parse” nella classe Calculator? Avrei potuto, però in questo modo il metodo “add” sarebbe diventato un metodo ad uso interno della classe. Come avrei fatto a testarlo? Avrei dovuto buttare via il test su add, oppure tenere add come “public” anche se in realtà serve solo internamente. Oppure usare qualche brutto trucco come dare ad “add” visibilità protected oppure package.

Invece, tenendo il Calculator come classe a sè che si occupa solo di fare conti, mentre Parser si occupa di leggere e scrivere stringhe, posso tenere “add” come metodo pubblico di Calculator. Martin direbbe che ho applicato il “Single Responsibility Principle.” Per me è stato decisivo pensare “se no mi tocca testare un metodo privato”.

Poi non ero ancora soddisfatto. Nel TDD quello che facciamo è sviluppare un isola felice di codice a oggetti, che però a un certo punto si deve scontrare con la realtà procedurale del mondo esterno. In questo caso il “mondo esterno” è il main, che deve creare e invocare i nostri oggetti. Per me è fondamentale che il main non contenga nessuna logica, ma soltanto la creazione di un certo numero di oggetti, collegati insieme. Se faccio restituire il risultato a Parser#calculate, poi al main resta la responsabilità di invocare System.out.println() per stampare.

Il mio obiettivo è ridurre al minimo la logica nel main, in modo che il main, che è per sua natura più difficile da testare unitariamente, sia così semplice da risultare ovviamente corretto. O comunque, per essere sicuro che il main se fallisce, fallisce sempre, e se funziona, funziona sempre. In questo modo posso essere ragionevolmente certo che se il mio main contiene un errore, me ne accorgerò. Gli errori di cablaggio, come li chiama Hevery, sono facili da trovare.

Allora ho applicato il principio “Tell, don’t Ask,” e ho passato l’OutputStream come collaboratore alla Parser#calculate.

@Test
public void willParseTwoAndFive() throws Exception {
	Calculator calculator = new Calculator();
	OutputStream stream = new ByteArrayOutputStream();
	new Parser(calculator, stream).calculate("2 + 5");
	assertEquals("7.0\n", stream.toString());
}  

In questo modo è come se dicessi a Parser, “questa è la tua stringa da calcolare, questo è lo stream dove devi scrivere il risultato, adesso arrangiati, non ne voglio sapere nulla.”

Un pattern che si può riconoscere in questo design è una versione embrionale di collecting parameter. In generale cerco di evitare di avere metodi che restituiscono dati. Di solito è più efficace dire agli oggetti di fare cose, piuttosto che chiedere dati. Questo è il principio “tell, don’t ask“.

Possiamo anche vedere l’oggetto Parser come un adapter: adatta l’interfaccia del Calculator, basata su numeri, alle necessità di main, che lavora con stringhe.

Tutto ciò, beninteso, non significa che per programmare bisogna ad ogni piè sospinto cercare nel manualone dei pattern uno o più pattern da ficcare dentro al nostro codice. Al contrario, quello che ho fatto io è stato di scrivere il codice che mi sembrava più appropriato per risolvere il mio problema, e poi, ragionandoci sopra, ho riconosciuto dei pattern in quello che avevo scritto.

In laboratorio

La seconda parte della lezione si è svolta in laboratorio. Ho proposto un semplice esercizio, di scrivere un programma che concatena le righe di due file a una a una, un po’ come fa il comando paste(1) di Unix. Ho visto subito che per la maggior parte degli studenti questo esercizio era troppo difficile, per cui sono subito passato a suggerire come primo test una versione semplificata del problema.

@Test
public void pasteLinesFromArrays() throws Exception {
	List a = Arrays.asList("aa", "bb");
	List b = Arrays.asList("xx", "zz");
	List result = new ArrayList();
	
	Concatenator concatenator = new Concatenator();
	concatenator.concatenate(result, a, b);
	
	assertEquals(Arrays.asList("aaxx", "bbzz"), result);
}  

I miei studenti sono al terzo anno di Informatica triennale. Nel nostro corso di laurea, il linguaggio di programmazione di riferimento è Java. Purtroppo, ho dovuto osservare che per la grande maggioranza dei miei circa 40 studenti, scrivere il codice che fa passare questo esercizio è un problema difficile. E nessuno (mi pare) è stato in grado di estendere il codice per fare passare anche il secondo test:

@Test
public void listsCanBeOfDifferentLength() throws Exception {
	List a = Arrays.asList("a");
	List b = Arrays.asList("b", "c");		
	List result = new ArrayList();
	
	Concatenator concatenator = new Concatenator();
	concatenator.concatenate(result, a, b);
	
	assertEquals(Arrays.asList("ab", "c"), result);
}  

Non so che cosa pensare. Questi esercizi mi sembrano di un livello di difficoltà paragonabile al famoso “problema” FizzBuzz, che viene usato nei colloqui di lavoro per scremare quelli che non sanno programmare per niente da quelli che forse sono capaci di fare qualcosa. Al terzo anno mi aspetterei qualche cosa di più. Sto cercando di ricordare me stesso al terzo anno di università. Sono sicuro che sarei riuscito a risolvere questo problema.

Ma non importa. Venerdì prossimo continuerò con esercizi di questo tipo. Piano piano miglioreremo. Sono sicuro che, alla fine del corso, gli studenti che avranno continuato a frequentare raggiungeranno l’obiettivo di diventare (almeno) il doppio più bravi a programmare.