Among the many characteristics of Ruby on Rails that help increase productivity there two that in my opinion are fundamental: the emphasis on tests, and the readability of code, which makes it self-documenting.
Developers often dislike writing tests, and if the language or the platform make it difficult, they try to avoid it (or cheat, writing useless or bad tests that will come back to haunt them later; a lot could be written about this topic) until they reach enlightenment, understanding that the time spent upfront will more than pay for itself when tests will help quickly find issues that would have taken hours to debug.
Luckily Rails makes writing tests almost a pleasure, thanks to the many "shortcuts" that make it particularly expressive. Rails inherits the Ruby legacy, with its emphasis on "Domain-Specific Languages"; in other words, the language is so powerful and natural that features you implement become extensions of the language.
Testing is usually something that only matters to developers; customers expects a perfect bugfree product, and they don't want to know anything about how that goal is reached (never mind the time and cost involved in it). The point is that quality starts before the first line of code is written, and if client and developer don't understand each other from the start, the project will only generate frustration and be destined to be unsuccessful.
Agile methodologies offer a solution: customer and team interact using "stories" written by the customer in natural language (in english, or in their own native language) with minimal formality but sufficient clarity to be read by developers and immediately implemented.
Cucumber is a tool that enables feature documentation in plain text, as well as generate tests from them. This post is an introduction to cucumber, but unfortunately it's only in italian, since there are already excellent introductions to Cucumber in english.Tra i tanti aspetti di Ruby on Rails che aiutano ad aumentare la produttività ce ne sono due a mio avviso fondamentali: l'enfasi sui test, e la leggibilità del codice, che lo rende autodocumentante.
Scrivere test è spesso un compito ingrato per gli sviluppatori, e se il linguaggio o la piattaforma lo rendono difficile, un compito a cui spesso cercano di sfuggire (o di imbrogliare, scrivendo test inutili o deleteri; e su questo argomento si potrebbe scrivere molto) finché non raggiungono l'illuminazione comprendendo che il tempo speso all'inizio viene più che ripagato quando i test aiutano a scoprire velocemente problemi che avrebbero poi richiesto ore di debugging.
Fortunatamente in Rails è quasi un piacere scrivere test, grazie alle molte "scorciatoie" che lo rendono molto espressivo. D'altro canto Rails eredita tutta la tradizione Ruby, che ha sempre posto un'enfasi particolare sui cosiddetti "Domain-Specific Languages"; in altre parole, il linguaggio è così potente e naturale che le funzionalità implementate diventano a tutti gli effetti estensioni del linguaggio stesso.
Il testing tradizionalmente viene ritenuto qualcosa che riguarda solo gli sviluppatori; un cliente si aspetta un prodotto perfetto, senza bachi, e non vuole sapere nulla dei dettagli di come ciò viene raggiunto (né, nella maggior parte dei casi, del tempo e del costo relativo). Il punto che sfugge è che la qualità inizia prima di scrivere la prima riga di codice: da cattive specifiche non può che nascere un cattivo prodotto, e se il cliente e lo sviluppatore non si sono compresi fin dall'inizio, il progetto creerà solo frustrazioni e sarà destinato a non essere un successo.
Le metodologie agili propongono una soluzione diversa: il cliente1 e il team di sviluppo interagiscono tramite delle "storie", scritte dal cliente stesso in linguaggio naturale (in italiano, o in inglese) con un formalismo minimo ma con sufficiente chiarezza da poter essere lette dagli sviluppatori e immediatamente implementate. Le storie assumono quindi valore di specifica e di documentazione; ma la cosa più interessante è che se sono sufficientemente chiare e non ambigue, possono anche essere uno strumento di testing e di misurazione dell'avanzamento del progetto.
Figura 1: una funzionalità molto semplice
La figura 1 mostra un esempio di funzionalità, così come un cliente potrebbe inizialmente descriverla, insieme ad altre operazioni come "caricare un prodotto a magazzino", "inserire un nuovo prodotto", e così via. Come si può vedere, le richieste sono espresse in italiano, senza richiedere al cliente lo sforzo di imparare niente di complesso. Il formalismo si limita a poche semplici regole (le parole evidenziate come "Funzionalità", "Dato", eccetera hanno tutte un preciso significato) che si imparano in pochi minuti. Questa funzionalità è talmente semplice che quasi non varrebbe la pena esplicitarla (si spera che cliente e team possano intendersi su una cosa così basilare), ma l'esempio contiene il nocciolo di funzionalità più complesse. Ad esempio, il cliente potrebbe voler evidenziare una giacenza particolarmente bassa, in modo da avvisare il magazziniere che potrebbe non essere corretta; in questo caso il rischio di malintesi è più alto, e la documentazione più importante. Sarà quindi necessario prevedere un nuovo scenario, come si può vedere in figura 2.
Figura 2: funzionalità in dettaglio
Immaginiamo ora che il cliente desideri che i suoi clienti possano consultare la giacenza dei prodotti; ma se la giacenza è bassa non dovrebbero vedere la giacenza esatta, ma soltanto un messaggio di avviso. Inseriremo questa scenario come nuova funzionalità, specificando il diverso comportamento.
Figura 3: esempio di una seconda funzionalità
La differenza fra una funzionalità e uno scenario è sottile ma importante: uno scenario corrisponde ad una sequenza relativamente semplice di operazione, che può essere descritta in poche parole, e che porta ad un risultato che spesso ha un significato nel mondo reale. Una funzionalità è un concetto più ampio, che tipicamente comprende più scenari. Negli esempi abbiamo visto due funzionalità separate, il sito "intranet", usato dai magazzinieri e il sito pubblico, usato dai clienti; come è tipico, la prima funzionalità è utile in sé anche prima che la seconda sia implementata, mentre gli scenari all'interno della stessa funzionalità hanno spesso dipendenze (ad esempio, non è molto utile poter visualizzare la giacenza se non è possibile incrementarla o decrementarla).
Finora abbiamo descritto le esigenze, ma non abbiamo veramente sfruttato cucumber. Questo è il momento milgiore per iniziare (ora, prima di iniziare a scrivere il codice!):
Figura 4: esempio di esecuzione di cucumber
Le righe mostrate in giallo corrispondono a "passi" dell'esecuzione di uno scenario che non è possibile testare. Cucumber in effetti, grazie all'integrazione con webrat, fornisce alcune funzionalità che permettono di accedere di creare oggetti di test in un database o interagire con una pagina web, ma non può certo fare tutto da solo! Gli scenari gialli sono "pending" (ossia in sospeso) in attesa dell'implementazione di passi che verifichino se le condizioni sono rispettate; a quel punto le righe corrispondenti diventeranno verdi se il test ha successo, o rosse in caso contrario.
Questa informazione è fondamentale per lo sviluppatore, ma in uno scenario di continuous integration e di un ciclo "agile" di vita del prodotto non è da escludere la possibilità di rendere i risultati accessibili anche al cliente tramite una interfaccia web, in modo che questi possa avere visibilità dell'avanzamento del progetto in termini non di "issue" (poco significativo per persone non tecniche). La disponibilità di questo canale comunicazione aperta, trasparente e continua è di rendere superfluo l'invio periodico di report sull'avanzamento del progetto, risultato non da poco!
Speriamo in questo post di avere mostrato come cucumber possa aiutare a snellire la comunicazione tra il cliente e il team. Post futuri entreranno più nel dettaglio di come uno sviluppatore può scrivere i "passi" di esecuzione dello scenario, e dall'altra di quali sono i principi che un cliente (o più probabilmente, chi aiuta il cliente nella documentazione delle funzionalità) dovrebbe seguire nello scrivere funzionalità e scenari.
Se nel frattempo volete installare Cucumber, trovate informazioni e istruzioni per installarlo dalla pagina ufficiale su github. L'ultima release contiene anche la traduzione in italiano contribuita dal sottoscritto.
Note:
1: Il concetto di "cliente" va inteso in senso lato. Spesso il cliente finale non ha le idee abbastanza chiare da poter scrivere le storie da solo, e deve essere aiutato da una figura che lo aiuti ad esplicitare le sue esigenze e lo "rappresenti". In altri casi, ad esempio nella realizzazione di prodotti "finiti" da vendere sul mercato, il "cliente" è puramente interno.



