Archive for October, 2006

Troppo pigro per scrivere qualcosa di mio…

Tuesday, October 24th, 2006

Summary: nice exchange on the TDD list

Phlip:

Change your code to meet these ideals, in this order:

  • 0. matches your community agreements on style
  • 1. passes all tests
  • 2. clear and expressive code
  • 3. no duplication of _behavior_
  • 4. minimal classes, lines, and methods

Item 0 goes before 1 because you can’t TDD good style. Things like
when to use a reference or pointer, when to capitalize, etc. This is
too low-level to TDD, so just write it.

Item 1 is TDD. Do this before Refactoring, which is 2., 3., and 4.

Item 2 is before item 3 because for some languages (such as C++) if
you squeeze out the last drop of duplication, you will have unreadable
code. Only remove duplication in ways that improve the style.

And 4 is your “simplify” thing. Balance out the classes and levelize
your packages.

Jeffries:

I personally refactor for all the purposes you list, and perhaps more. Removing duplication, for me, is the first thing I look for, and still carries much of the weight, especially as I learn new ways of recognizing duplication. It’s a good first step to better code.

Phlip:

To teach us to improve things, we spread the definition of “duplication” as wide as possible, beyond mere code cloning. For example, the numbers 4 and 6 may, in context, actually represent 5-1 and 5+1. Remove optimizations to inspect latent underlying concepts.

When we refactor 4 and 6 into their actual behaviors, 5-1 and 5+1, we are increasing the amount of duplication on purpose, to then merge it. The only difference between those expressions is the – and +.

In general, if you have two situations that look generally the same, you should should refactor them, separately, until they are more similar. Then you might merge them together. Put another way, don’t merge them together until you first prove they are equivalent.

Jeff L:

As fasr as why “only” emphasize eliminating duplication: first, the
presumption is that we’re doing TDD, otherwise we don’t have the
confidence to do much of anything with the code. Doing just TDD should
already give us a significantly better design, because of its impacts
on coupling and correctness.

If we just did TDD and eliminated all duplication, our system would be
of significantly higher quality than 99.9% of all other systems out
there. Maybe that’s all we need.

Lezioni di design da Zio Bob

Sunday, October 22nd, 2006

Summary: cool simple program design lesson on Uncle Bob’s blog

Uncle Bob scrive:

In my previous blog (RubarianNotation) I had posted this little code snippet from a Mad Libs program:

  def translate(text)
    questions_and_text = split_questions_from_text(text)
    answers_and_text = replace_questions_with_answers(questions_and_text)
    answers_and_text.join
  end

The variable questions_and_text held on to a list of strings which alternated between questions and text. The question strings looked like this ((an adjective)), and the text was just raw text. So, for example, if my original document looked liks this

((name of someone in room)) took a ((a noun)) today and ((a past-tense verb)) his back.

We would expect the questions_and_text variable to look like this:

["((name of someone in room))",
" took a ",
"((a noun))",
" today and ",
"((a past-tense verb))",
" his back."]

So this variable holds a list of strings of alternating questions and answers.

I did not find the name questions_and_answers satisfying, and started to think that it would be better to use a name more like list_of_strings_of_alternating_questions_and_answers. This variable name is long, so I thought it might be better to create a set of standard abbreviations like ls_alternating_questions_and_answers. And then I stopped myself and realized that I was just reinventing the horror of Hungarian notation. I took this to mean that my program had a design flaw.

So I refactored the program to improve the design. Here’s the impact of that refactoring on the previous snippet of code:

  def translate(document)
    game = make_game(document)
    game.play(GameContext.new(@asker))
  end

What a difference! Remarkably, the first line of both snippets parses the incoming text into a convenient form. The second line of both processes that convenient form, asking the approriate questions and replacing the questions with the answers. And yet the implication of the names between the two snippets is remarkably different. In the first case they are rife with implementation detail. In the second, they tell you whats going on at an abstract level.

There is a more important difference between the two snippets. In the first we are operating on data structures, which is why we want to identify the structure of those data structures. In the second we are telling objects what to do, which is why we don’t care about the structure of the objects and can focus on their intent instead.

Of course this is just good old OO. But for an old C++/Java/C#-head, like me, this is something of an eye-opener. Ruby has very rich primitive types like lists and maps. You can use them to create lists of lists and maps of lists and lots of other deep and convoluted structures. Indeed, that’s what I had done in the first snippet. I had created a semantically rich data structure composed of a list of strings that alternated between raw text and questions. What I have come to realize is that although slinging these rich data structures around is fun, it’s also bad.

As I said in the previous post, we want our variables to hold objects that we can tell what to do, we don’t want our variables holding data structures that we operate on. If we use the former strategy, then the variable names don’t have to encode the structure of the data. Rather they, coupled with the methods that are invoked against them, let us know what we expect the object to do.

Questo articoletto insegna una cosa preziosa: evitare di passare in giro array e liste. In Java, per esempio, spesso uno si chiede se un dato metodo debba restituire un array, oppure una lista:

  List employees();           // meglio questo
  Employee[] employees();     // oppure questo?
  List<Employee> employees(); // o magari questo?

In molti casi la risposta potrebbe essere nessuno dei tre. Meglio restituire una classe ad hoc:

  Employees employees();

Nel primo caso, il codice per iterare sulla collezione dipende da che tipo di collezione ho scelto.

  // caso array
  Employee[] e = employees();
  for (int i=0; i<e.length; i++) {
    e[i].printSlip();
  }
  // caso lista
  List e = employees();
  for (Iterator i=e.iterator(); i.hasNext(); ) {
    ((Employee) i.next()).printSlip();
  }

Potrei addirittura essere tentato di codificare il tipo della variabile “e” nel nome: empList, empArray. Brutto no? Usando la classe ad hoc invece abbiamo:

  Employees e = employees();
  e.each(printSlip);

o addirittura

  employees().each(printSlip);

dove “printSlip” è un oggetto di un’altra classe ad hoc. (Scuse a Francesco Cirillo per avere copiato il suo esempio!)

Questo principio di design è un caso particolare di un principio più generale che consiglia di evitare setters and getters. Ad esempio è brutto

  return rectangle.width() * rectangle.height();

Molto meglio mettere dentro la classe Rectangle un metodo per calcolare l’area:

  return rectangle.area();

In questo modo il nostro codice non si interessa più alle viscere dell’oggetto che riceviamo, ma delega il comportamento all’oggetto stesso. Questo codice continuerà a funzionare anche se gli passiamo un oggetto che rappresenta un cerchio, purché quest’oggetto risponda al messaggio “area”.

Il duo pragmatico ha coniato questo slogan: Tell, Don’t Ask. Non chiedere a un oggetto cosa contiene. Digli di eseguire la sua operazione.

Terza riunione varese-xpug

Tuesday, October 17th, 2006

Summary: third meeting of the Varese XP User Group today. The topic: agile planning

Terza riunione del neonato Varese XP User Group. Presenti in 9; argomento: pianificare l’applicazione Examinando.

Dopo la lezione di Applicazioni Web, ci siamo trovati in un’aula prestata dall’Insubria. Abbiamo fatto uno stand-up meeting facilitato da Piero; poi Federico ha ricapitolato che cosa deve fare Examinando. Si tratta di una semplice applicazione per la prenotazione delle date degli appelli, per i docenti dell’Insubria. Quindi ci siamo riuniti intorno a un tavolo e abbiamo scritto le carte. Queste ultime due attività hanno richiesto un pomodoro (gergo per un periodo di 25 minuti).

Dopo la pausa canonica di 5 minuti, abbiamo stimato la difficoltà delle storie. Abbiamo usato il metodo di Pascal, che è poi quello dell’XP Game: prima ordiniamo tutte le carte per difficoltà. Abbiamo ottenuto 4 cluster di carte. Poi abbiamo scritto “2” sulle carte più facili, e via via abbiamo assegnato un numero alle altre. A questo punto tocca al cliente, nella persona di Federico, prioritizzare le storie.

Qui ci siamo scontrati con diverse difficoltà. Non abbiamo molto tempo per lo sviluppo (probabilmente due ore ogni due settimane.) Non abbiamo mai lavorato insieme. La maggior parte di noi non ha confidenza con la tecnologia che useremo (ovviamente Rails.) Tutto ciò rende estremamente difficile parlare di “iterazione”. Sono poi gli stessi identici problemi che abbiamo affrontato con lo user group di Milano.

Allora abbiamo semplicemente chiesto al cliente di scegliere storie per 8 punti; queste sono quelle che per lui sono assolutamente importanti. Senza promettere date, ci siamo impegnati a farle. Prima o poi :-P

In tutto il planning ha richiesto meno di due pomodori. Abbiamo fissato la prossima riunione per mercoledì 1 novembre, ore 11:00 o 11:30.

Aggiornamento: ovviamente il primo di novembre è festa :) La riunione è spostata al 31 ottobre, ore 12, aula 2.06 in Via Ravasi

Predicati con stile

Thursday, October 12th, 2006

Summary: with careful refactoring you get concision and clarity.

Questo è un frammento di codice di una famosa applicazione open source:

  public boolean isTitleValid() {
    if((title==null) || "".equals(title)) {
    return false;
    }
    return true;
  }

Brutto vero? Perché scomodare un if-then-else? Un valore booleano può essere restituito direttamente. Prima facciamo un passo di refactoring:

  public boolean isTitleValid() {
    if (! ((title==null) || "".equals(title))) {
      return true;
    }
    return false;
  }

Ora possiamo eliminare l’if-then-else.

  public boolean isTitleValid() {
    return (! ((title==null) || "".equals(title)));
  }

E così risparmiamo tre righe su sei: 50%. Eliminiamo tutte le parentesi inutili, per capirci meglio:

  public boolean isTitleValid() {
    return ! (title==null || "".equals(title));
  }

Applichiamo De Morgan per portare la negazione all’interno:

  public boolean isTitleValid() {
    return title != null && !"".equals(title);
  }

E non è finita; eliminiamo una delle negazioni:

  public boolean isTitleValid() {
    return title != null && title.length() > 0;
  }

Ora questo codice è 50% più corto, e molto più “parlante”: l’intento è evidente, tanto che si può leggere “il titolo è valido se non è null e la sua lunghezza è maggiore di zero.”

Visto quanta cura si può impiegare utilmente per poche righe di codice? Il bravo Steve McConnell ha impiegato 900 pagine di dettagli sull’arte della codifica, nel suo Code Complete, seconda edizione.

L’annuale if-comp è partita

Saturday, October 7th, 2006

Summary: voting for the interactive-fiction competition has started

Le avventure testuali sono vive e più che mai vitali! Su http://ifcomp.org/ si possono scaricare i giochi che concorrono all’undicesima competition annuale. Se non sai che cosa sia, provane qualcuno e preparati a qualche sorpresa… se pensavi che le avventure testuali fossero morte e sepolte negli anni ottanta, sbagli! Sono probabilmente più vive ora di allora.

Il ritorno del linguaggio naturale: Inform

Saturday, October 7th, 2006

Summary: natural language processing is coming back, as seen in free-format input in popular web apps, in the Inform programming language, or in the Ruby on Rails framework

Il linguaggio naturale per l’input è un trend che si comincia a notare: le applicazioni web più cool accettano input in formato naturale. Google Calendar accetta “15:00 dentista” senza bisogno di un box separato per l’ora e uno per il nome dell’evento. Basecamp va oltre (http://backpackit.com/calendar):

Type like you think:
“6pm Dinner” or “Doctor Wednesday 3pm” or “Call Jim tomorrow”.

L’ultima revisione di Inform, il linguaggio per avventure testuali, è radicalmente innovativo rispetto alle versioni precedenti, e anche rispetto a tutti gli altri sistemi analoghi.

Enfasi data al test: molti autori di narrativa interattiva iniziano a lavorare da uno scritto di interazione, da una lista di comandi e risposte che il gioco dovrebbe produrre una volta funzionante. Inform 7 conserva queste tracce di interazione, e permette di rilevare automaticamente quando il programma da noi realizzato riesce finalmente a rispondere all’interazione nella maniera desiderata. Questo riecheggia meravigliosamente con Kent Beck: prima scrivi l’output atteso, poi modifica il programma fino a che l’output del programma non sia uguale a quello atteso.

L’uso del linguaggio naturale per l’input. Lo so che questo chiama alla mente obbrobri di linguaggi di programmazione cammuffati da linguaggio naturale, come AppleScript o Cobol. Ma Inform 7 è un po’ più raffinato di così. Consideriamo questo frammento da The Reliques of Tolti-Aph di G. Nelson:

Chapter 1 – Fundamentals

Section 1(a) – Substance

A material is a kind of value. The materials are stone, wood, paper, magic-imbued wood, metal, clay, flesh, sustenance and air. A thing has a material. Things are usually stone. People are usually flesh.

Questo è il vero e proprio codice sorgente di un gioco. E a leggerlo sembra un moderno De Rerum Natura. “Things are usually stone. People are usually flesh.” è poesia.

L’adozione di uno stile di programmazione “per relazioni” piuttosto che ad oggetti. Da anni tenevo la mia copia del Clocksin & Mellish in cantina e sono andato a riprenderla. Mi sono ritrovato a pensare al tema del mio esame di Prolog di tanti anni fa. Siamo abituati a pensare ad oggetti da tanto tempo che ci sembra l’unica maniera naturale di programmare. Mi è tornato in mente che la programmazione logica alla Prolog permette di scrivere certi tipi di programmi in maniera estremamente concisa. E la concisione è potere.

Giocare con I7 mi ha riportato alle radici della fantascienza che amavo da bambino. Un programma che capisce le mie istruzioni in inglese! E chi se ne importa se “capisce” solo un epsilon della complessità del linguaggio naturale. E’ più sofisticato di qualsiasi altro sistema abbia mai usato. E’ sufficiente per scrivere programmi. Scusate se è poco.

I7 è un domain-specific language per realizzare narrativa interattiva. Il problema di “comprendere il linguaggio naturale”, che è di una complessità tale da sfuggire di gran lunga alle nostre capacità di programmazione, diventa gestibile quando la comprensione viene limitata a un dominio specifico, quale nel nostro caso è la scrittura di avventure testuali.

Mi sono divertito a scrivere codice Inform 7 che fa semplici ragionamenti geometrici

A geometric shape is a kind of thing.

A triangle is a kind of geometric shape. It has a number called side A. It has a number called side B. It has a number called side C. After printing the name of a triangle: say “, with sides ([side A],[side B],[side C])”.

To decide whether (x – a number) equals (y – a number) and (z – a number):
if x is y and y is z, decide yes;
otherwise decide no.

Definition: A triangle is equilateral if its side A equals its side B and its side C.

The blue triangle is a triangle with side A 10, side B 10, and side C 10.

The green triangle is a triangle with side A 5, side B 5, and side C 10.

The pink triangle is a triangle with side A 3, side B 4, and side C 5.

The Geometry lab is a room. “You are in a weird lab.” The green triangle, the pink triangle and the blue triangle are in the lab.

A tester is a kind of container. They are always fixed in place.

The equilateral box is a tester. It is in the lab. “A large box is here; gold letters on it say ‘drop equilateral triangles here.'”

Instead of inserting something (called the supposed equilateral) into the equilateral box:
if the supposed equilateral is not an equilateral triangle, say “My, my. Read again the definition of ‘equilateral.'” instead;
Increase the score by one;
move the supposed equilateral to the equilateral box.

To decide whether (x – a number) equals (y – a number):
if x is y, decide yes;
decide no.

Definition: A triangle is isosceles if its side A equals its side B, or its side B equals its side C, or its side C equals its side A.

The isosceles box is a tester. It is in the lab. “A small box is here; silver letters on it say ‘drop isosceles triangles here.'”

Instead of inserting something (called the object) into the isosceles box:
if the object is not an isosceles triangle, say “A mysterious force prevents you from doing that.” instead;
Increase the score by one;
Move the object to the isosceles box.

Instead of taking something which is in a tester, say “You can’t reach inside the box.”.

Test remove with “put green into isosceles box / get green / get pink”

To decide what number is the square of (x – a number): decide on x times x.

To decide what number is the lesser of (x – a number) and (y – a number):
if x is greater than y, decide on y;
decide on x.

To decide what number is the greater of (x – a number) and (y – a number):
if x is less than y, decide on y;
decide on x.

To decide what number is the lesser of (x – a number) and (y – a number) and (z – a number):
let a be the lesser of x and y;
decide on the lesser of a and z.

To decide what number is the greater of (x – a number) and (y – a number) and (z – a number):
let a be the greater of x and y;
decide on the greater of a and z.

To decide what number is the middle value of (x – a number) and (y – a number) and (z – a number):
let a be the lesser of x and y;
let b be the lesser of y and z;
let c be the lesser of x and z;
decide on the greater of a and b and c.

To decide whether (x – a number) forms a pythagorean triple with (y – a number) and (z – a number):
let a be the lesser of x and y and z;
let b be the middle value of x and y and z;
let c be the greater of x and y and z;
if the square of a plus the square of b is the square of c, decide yes;
decide no.

Definition: a triangle is rectangle if its side A forms a pythagorean triple with its side B and its side C.

Mi riesco facilmente a immaginare come la concisione di Inform potrebbe essere catturata in un sistema per la realizzazione di applicazioni gestionali.

Un impiegato è una persona. Un impiegato ha una data di nascita, un nome, un cognome, e un numero chiamato salario…

Un utente appartiene a molti gruppi. Un gruppo contiene molti utenti. Un gruppo ha un insieme di diritti di accesso…

Tutti questi esperimenti con la generazione di applicazioni, e la comprensione del linguaggio naturale, sono stati fatti e abbandonati negli anni 80-90. Andavano sotto il nome di “linguaggi di quarta generazione”. Perché fallirono negli anni 90? Perché potrebbero avere successo oggi? Non c’è una singola ragione precisa. La ragione c’è, e dipende da come vengono fatte le cose. Prima di tutto, potremmo osservare che ci sono centinaia di framework per realizzare applicazioni web, ma solo una manciata sono di qualità paragonabile a Rails.

Rails mi ha subito colpito per l’attenzione che dava alla gestione del linguaggio naturale, sia nel presentare output all’utente (niente “0 file(s) copied”!) sia in come appare il sorgente al programmatore.

class User < ActiveRecord::base
  validates_presence_of :name, :address
  validates_uniqueness_of :nickname, :email

  has_many :posts
  has_and_belongs_to_many: groups
end

Definire "has_many :posts" aggiunge alla classe User una serie di metodi: ad esempio "user.posts" che restituisce gli oggetti "post" associati all'utente. Questo implica che Rails deve sapere che il singolare di "posts" è "post", così che venga usata la classe Post. Rails è preconfigurato con le regole più comuni della lingua inglese, ma posso benissimo estenderlo con regole aggiuntive. Per esempio, recentemente ho dovuto scrivere questo, per permettere a Rails di lavorare con un database legacy con i nomi delle tabelle in italiano:

Inflector.inflections do |inflect|
  inflect.irregular 'campagna',   'campagne'
  inflect.irregular 'promotore',  'promotori'
  inflect.irregular 'provincia',  'province'
  inflect.irregular 'regione',    'regioni'
  inflect.irregular 'trattativa', 'trattative'
end

E' stato sufficiente dare a Rails questa lezioncina di italiano per integrare i nomi di tabelle italiani nell'applicazione. Questo ti dà il senso che programmare bene significa definire un linguaggio. O meglio insegnare alla macchina un linguaggio, che ne estende le capacità.

Annunciato l’Agile Day 2006

Wednesday, October 4th, 2006

Summary: the third Italian Agile Day has been announced

Marco Abis ha pubblicato la data per l’edizione 2006 dell’Agile Day. Si svolgerà il primo dicembre. Mi piacerebbe portare anche quest’anno una presentazione, ma non so ancora a proposito di che cosa.

Un nuovo XP user group in marcia…

Monday, October 2nd, 2006

Summary: we have a new XP user group in Varese

Oggi un gruppo di coraggiosi ex-essap si è riunito in un aula dell’Università dell’Insubria. Sono molto contento… c’è entusiasmo. Abbiamo ascoltato una presentazione di Max Pepe, che ci ha raccontato come ha imparato ad amare TDD insieme a Rails. Abbiamo deciso il nome del gruppo (varese-xpug, con sottotitolo Open Team) Abbiamo fatto una mappa mentale di Examinando, un’applicazione che svilupperemo a mo’ di esercitazione. Prossima riunione fra due settimane. Yay!