Minix 3 on a Mac

February 27th, 2006

Installing Bochs on a Mac is a pain. First you have to compile it, (no big deal with the standard ./configure && make && make install). Then you find it trashed your /usr/local directory with its files. When you finally make it run, it turns out the Carbon interface sucks 100% CPU even when the emulated PC is doing nothing. On top of all that, Minix fails to boot.

Given that Minix is the reason I wanted Bochs for in the first place, this is a bit of a let down. Luckily I found out about the Mac OS X version of QEmu. It booted Minix from the CD-ROM image with no problems. I ran “setup”, and in a couple of minutes I had Minix installed on the emulated disk. Joy!

]]>

Siti web realizzati da geni

February 22nd, 2006

Ore 9.07, navigo su www.genialloyd.it (non cliccate!) per rinnovare l’assicurazione della mia auto. L’altoparlante del mio computer inizia a blaterare ad alta voce “Benvenuto in Genialloyd!” Aaaaargh! Come si permettono di fare partire dei suoni sul mio computer? Abbasso il volume, e intanto la voce continua, “…per escludere l’audio clicca sull’icona dell’altoparlante…”. Da bravo utente clicco, e intanto la voce continua. Riclicco, e la voce continua.

Quando si fa un sito web, bisogna ricordare che il computer su cui gira il browser appartiene all’utente. Non dobbiamo permetterci di fare partire suoni senza che l’utente lo richieda esplicitamente. Così come non dobbiamo aprire nuove finestre o spostarle; sono atti che mandano il messaggio “Il tuo computer appartiene a noi.”

Oltre a tutte queste considerazioni, che dovrebbero essere ovvie per chiunque faccia del web il suo mestiere, c’è la figuraccia di mettere un bottone per escludere l’audio che non funziona.

Molto bene. Chi l’ha fatto, alla fine, il sito di Genialloyd? In fondo alla pagina leggo: “Sito realizzato in collaborazione con Accenture”. Complimenti.

]]>

Un sistema operativo estremo

February 22nd, 2006

Ogni anno, quando si approssima l’inizio del mio corso di Sistemi Operativi, sento il bisogno di illustrare i meccanismi del S.O. con del codice funzionante. Il problema è che mettere il naso dentro il codice di Linux, per dirne una, è difficilissimo anche per me. Anche con l’ausilio di ottimi libri come Understanding the Linux Kernel di Bovet e Casati, nel codice di Linux ci sono troppe complicazioni. Che sono necessarie per realizzare un SO realistico, ma rendono difficile afferrarne il funzionamento.

In alternativa, ci sono un numero di SO giocattolo, pensati per la didattica. L’esempio più famoso è Minix di Tanenbaum, che è una versione molto semplificata e comprensibile di Unix, e gira sui comuni PC Intel. Poi c’è Xinu, che non è Unix, come da acronimo ricorsivo, ma ha lo stesso spirito di Minix: realizzare un SO funzionante in C su hardware comune.

Un’altra categoria sono i SO giocattolo “non realistici”, cioè che non sono in grado di ospitare un completo sistema di sviluppo e compilare sè stessi. Al politecnico di Zurigo c’è Topsy, che è un SO microkernel che gira su processore RISC. Ad Harvard c’è OS/161, che gira su una CPU fittizia (con un assembler ancora più semplice.) Il mio preferito in questa categoria è GeekOS, che ha tutto un percorso didattico associato: ci sono una serie di esercizi che devono essere realizzati (in C e assembly x86), e il tutto gira su Bochs.

Ancora un’altra categoria è quella dei simulatori, che illustrano il funzionamento del SO simulando in maniera più o meno realistica l’hardware. Il più famoso è Nachos.

Alla fine, non ho mai usato nessuno di questi SO didattici, e ho sempre nel profondo l’idea che sarei forse in grado di realizzarne uno che centri il giusto equilibrio di semplicità e completezza. Giusto l’altro giorno stavo tornando su questi pensieri, e mi è venuto in mente che potrei affrontare il problema in stile XP, sfruttando questa mia nuova abilità nel Test Driven Development. L’idea che mi è venuta è vedere se si riesce a fare un simulatore che sia assurdamente semplice.

Ho lanciato Eclipse (ho scelto Java perché i miei studenti già lo conoscono) e ho cominciato a chiedermi come lo testerei questo SO giocattolo. Quello che è saltato fuori è abbastanza strano, sicuramente molto diverso da quello che avrei fatto lavorando nel vecchio metodo non-TDD. Dopo numerosi rimaneggiamenti ho prodotto un paio di test. Il primo dimostra che il SO contiene un task di init, il cui sorgente viene passato al costruttore del SO:

  public void testGetInitTask() {
    String source = "again: JMP again";
    InsubOS os = new InsubOS(source);
    Task init = os.getTask(1);
    assertEquals(source, init.getSource());
  }  

Il secondo test verifica il comportamento della chiamata di sistema fork(2):

  public void testFork() {
    String forkOnce = "fork; again: JMP again";
    InsubOS os = new InsubOS(forkOnce);
    assertEquals(1, os.getTaskCount());
    os.step();
    assertEquals(2, os.getTaskCount());
    assertEquals(forkOnce, os.getTask(1).getSource());
    assertEquals(forkOnce, os.getTask(2).getSource());
  }

Questi test sono semplici schizzi, buttati lì per vedere che effetto mi fa vederli (il codice che li fa passare è semplicissimo.) Non avrò mail il tempo di portare avanti questo progetto, purtroppo. Però quello che vedo mi piace. Penso che mi piacerebbe lavorare sul concetto di sorgente: invece di una stringa di pseudo assembler, mi piacerebbe una costruzione secondo il pattern Composite; qualcosa tipo

  new Source(new Syscall("fork"), new Loop(new Noop()))

E sicuramente va aggiunto un concetto di root filesystem. Ragiono in termini Unix-centrici, perché questo è quello che insegno e che mi piace.

Chissà se lo porterò avanti?

]]>

Che vergogna

February 16th, 2006

Essere alleati degli aguzzini di Abu Grahib e Guantanamo.

]]>

From the way too cool dept.

February 11th, 2006

Bel momento per lavorare con Rails. Ci sono tantissime risorse che spuntano in giro…

  • Kevin Clark ha pubblicato un bell’articolo Rails Best Practices, Tips and Tricks, dove, fra l’altro, dà alcuni utili consigli sul testing
  • www.globalize-rails.org pubblica un plugin che risolve i numerosi problemini di localizzazione di Rails
  • Duane Johnson ha realizzato un simpatico plugin che facilita l’uso di widget dinamici, come ad esempio una textarea che può essere ridimensionata dall’utente
  • Le Migrazioni permettono di evolvere con facilità lo schema dei dati; ma anche di sviluppare con un database molto leggero come SQLite o MySql e andare in produzione con Oracle. (Per i clienti che ritengono di avere bisogno di Oracle…)
  • Con Capistrano è facile installare, disinstallare, far ripartire e in generale manutenere un’applicazione su uno o più server
  • Techno-weenie ha realizzato acts_as_authenticated, un semplice e dolce plugin per generare i meccanismi di registrazione e login. Sempre Techno-weenie ha anche un plugin che permette di versionare in maniera molto semplice i contenuti di una qualsiasi tabella.
  • Jonas Bengtsson ha realizzato un plugin per facilitare l’uso di Selenium in Rails. Selenium è una libreria per fare test di accettazione di applicazioni web. I test girano direttamente nel browser. Quelli che Rails chiama “functional tests” in realtà sono programmer tests sui controller; per fare veri test di accettazione occorre un tool esterno a Rails come Selenium.

Pain, and still no gain.

February 6th, 2006

Jamie Andreas è un fighissimo maestro di chitarra, uno che è
veramente in grado di insegnarti come suonare la chitarra. Non che lo
conosca personalmente, ma solo dai suoi ottimi e numerosi scritti. Sulla sua
mailing list stamattina:

Hello Jamie,


I remember asking my high school band teacher (who I thought was a great guitar player) if it was possible for anyone (me) to become a good player. He assured me that “Yes” it was and it just depended on how hard you work at it.

… your teacher is wrong. Actually, your teacher is half right, but there is nothing more untrue than half of the truth!

Now, the reason your high school teacher was wrong is because you can work as hard as you want, but if you are working the wrong way, you will go nowhere. It doesn’t matter how fast I drive, if I am on the wrong road I will not get where I want to go! Now, I agree, it is better to keep going, no matter what, than to give up. There is always the chance you will come upon the right knowledge, the right teaching, the right road. Then, you can put the other half of the truth with what your teacher said, and fulfill the two requirements of success in anything: do the right thing, and do enough of it.

Questo mi fa venire in mente certi sviluppatori che lavorano 10 o più ore al giorno, e comunque consegnano tutto in ritardo e con tanti difetti. Non serve lavorare tanto, serve lavorare bene. Tempo fa raccontavo di questo mio cliente che mi diceva:

Guarda Pino, lui sì che si impegna! Sta su fino a notte tarda tutte le sere!

Il mio amico che ascoltava (lui stesso un dirigente) ha esclamato “uno che fa tardi tutte le sere è un pirla! E’ uno che non si sa organizzare“.

Sono tornato spesso col pensiero a questo Pino (non è il suo vero nome) e
alla sua famiglia che lo aspetta a casa fino a tardi. Ho ripensato al lavoro
che gli ho visto fare, e ho trovato due cose.

Prima di tutto, Pino fa un sacco di cose che proprio non sono
necessarie
. Per esempio, aggiungere a un database dei vincoli che non
servono a supportare nessuna delle cose che il cliente ha chiesto; vincoli che
poi risultano errati e vanno tolti, con il risultato che tutti perdono un
sacco di tempo. Oppure complicare l’applicazione per “renderla più sicura”,
senza avere ben chiaro qual’è il modello della minaccia da cui
vogliamo difenderci e comunque senza un’esplicita richiesta da parte del
cliente
.

La seconda cosa è che Pino non automatizza nulla. I programmatori pragmatici mi
hanno insegnato che qualunque operazione vada fatta più volte (per esempio:
creare un nuovo database, fare il rilascio di un’applicazione) deve essere
realizzata con un solo
comando
. Per esempio make install, o ant
create-database
. Se non ti crei uno script per fare operazioni
complicate, finisce che perdi un sacco di tempo non solo a ripetere
manualmente le operazioni, ma anche a ricordarti di preciso come bisognava
farle, a controllare che siano state fatte correttamente, a correggere gli
inevitabili errori che si fanno quando si deve ripetere manualmente una
sequenza di operazioni.

Cerchiamo di non fare come Pino. Basta seguire due semplici regole: tutto
quello che si fa, è per implementare una storia che
mi è stata data dal cliente. E tutte le operazioni ripetitive
vanno automatizzate.

]]>

Gemme agili

January 31st, 2006

Mary Poppendieck scrive, in Principles of Lean Thinking (pdf);

The Basic Principles of Lean Development

Add Nothing But Value (Eliminate Waste)
Center On The People Who Add Value
Flow Value From Demand (Delay Commitment)
Optimize Across Organizations

Questi principi si traducono abbastanza facilmente nella pratica di sviluppare in maniera agile. Eliminare gli sprechi: quante cose si fanno in un progetto software che non servono a niente? Feature aggiunte perché lo sviluppatore le trovava interessanti, o magari che fanno parte della spec ma in realtà al committente non servono… Ottimizzare trasversalmente rispetto alle organizzazioni (fiuuu… suona meglio in inglese): coinvolgere il cliente in ogni passo dello sviluppo. Far fluire il valore dalle richieste: you ain’t gonna need it, non far nulla che non sia legato alla storia, al test su cui stai lavorando in questo preciso momento. Concentrati sulle persone: non considerare il programmatore come scimmia sottopagata che esegue lavori in maniera semiautomatica. Il programmatore è al centro del processo di sviluppo: è lui che conosce i veri dettagli da cui dipende la buona riuscita del progetto.

Mi piace molto questo elenco che Zio Bob (jpg)
ha pubblicato in The Agile Test:

Lower your hands if:

  • You are not working on an Agile Project.
  • You are working on an Agile project and the iteration size is > 30 days.
  • Your iteration size is > 2 weeks.
  • You are not working in an open office or lab.
  • You have no unit tests.
  • You are not writing unit tests first.
  • You have no acceptance tests whether automated or manual.
  • You have no continuous build process.
  • You have no automated acceptance tests.
  • You are not pairing
  • Less than 100% of your features are defined by automated acceptance tests.

Uberto Barbini ha scritto, nella mailing list italiana di Extreme Programming, questo elenco, in risposta a una domanda di Francesco Cirillo:

Quali sono per voi i 10 problemi/sfide principali che avete dovuto
affrontare/state affrontando per applicare/introdurre XP/metodi
Agili?

Dal piu’ importante al meno

  • Capire realmente io cosa vuol dire Agile
  • Trasmettere l’idea di lavoro di squadra agli altri componenti del
    team
  • Convincere il dirigente che deve rivolgersi al team e non alle
    singole persone

tutto il resto IMHO sono dettagli. Cmq cito in ordine sparso:

  • Imparare a fare efficamente Pair
  • Disciplina negli UT
  • Scrivere e splittare le storie
  • Stimare i task
  • Coinvolgere il cliente (p.e. FIT)
  • Continuare a rifattorizzare il vecchio codice
  • Pensare alle classi in termini di behavior e non di entity

]]>

Spec, spec delle mie brame

January 31st, 2006

Joel Spolski non è esattamente un fan di XP, ma mi piace il suo Joel Test:

  1. Do you use source control?
  2. Can you make a build in one step?
  3. Do you make daily builds?
  4. Do you have a bug database?
  5. Do you fix bugs before writing new code?
  6. Do you have an up-to-date schedule?
  7. Do you have a spec?
  8. Do programmers have quiet working conditions?
  9. Do you use the best tools money can buy?
  10. Do you have testers?
  11. Do new candidates write code during their interview?
  12. Do you do hallway usability testing?

The neat thing about The Joel Test is that it’s easy to get a quick yes or no to each question. … Give your team 1 point for each “yes” answer.

A score of 12 is perfect, 11 is tolerable, but 10 or lower and you’ve got serious problems. The truth is that most software organizations are running with a score of 2 or 3, and they need serious help, because companies like Microsoft run at 12 full-time.

Spolski è un fan di lavorare con una specifica (vedi voce 7), infatti quello che faceva in Microsoft prima di mettersi in proprio era scrivere la specifica del Visual Basic incorporato in Excel.

Joel mi ha aperto gli occhi su come dovrebbero essere scritte le
specifiche. Prima di allora pensavo che una specifica dovesse per forza essere
basata su un farraginoso template (word),
tipo quelli propugnati da Steve McConnell nel suo libro Software Project Survival
Guide
. Joel ha scritto, in Painless
Functional Specifications
, che una spec dovrebbe essere
divertente da leggere. Dovrebbe essere scritta in uno stile e in un
formato inventato apposta per il tuo progetto, piuttosto che copiata da un
template. Dovrebbe raccontare storielle su Miss Piggy e le sue
avventure a mo’ di esempi.

Parlando di esempi, le spec scritte nel solito stile triste, verboso e farraginoso ne sono di solito prive. Eppure sono gli esempi la cosa più importante. Quando c’è un dubbio su quello che la spec vuol dire, è il momento di fare un esempio e vedere come il sistema si deve comportare. Questo in effetti è lo stile di spec prediletto dagli XPer, con l’aggiunta del fatto che gli esempi devono, a un certo punto, essere eseguiti automaticamente sul sistema.

Lavorare con una spec non è anatema per gli XPer. Come spiega bene Zio Bob:

On XP/Agile teams, programmers don’t just have a spec. They have a spec that executes. They have a spec that is unambiguous and cannot get out of sync with the application. They have a spec that is run against the system on a daily, or even hourly basis. On an XP team it is against the rules to check in code that breaks the spec.

La specifica per gli XPer è un insieme di test di accettazione, scritti in uno stile il più possibile vicino al linguaggio del cliente, in modo che il cliente possa capirla, confermarla, e —idealmente— scriverla.

Quello che un team agile non fa è

  • scrivere tutta la specifica prima di iniziare l’implementazione
  • fare scrivere la specifica a un analista che poi non partecipa all’implementazione
  • scrivere i test di accettazione dopo che la feature funziona

Ci sono molti diversi sistemi per realizzare i test di accettazione. In ogni caso l’obiettivo è arrivare a un minilinguaggio che sia comprensibile per l’utente (Marick dice: business facing piuttosto che “technology facing”). Il concetto chiave è che non è necessario complicarsi la vita con lex e yacc e i diagrammi sintattici. E’ sufficiente un semplice parser realizzato in 4 righe di Java, Ruby, o simili.

In Extreme Programming Adventures in C#, Ron Jeffries scrive un semplice editor XML per suo uso e consumo. I test di accettazione sono degli script, in un semplice linguaggio inventato da lui, che permettono di specificare in maniera semplice il comportamento dell’editor.

    *input
    

This is the first p|aragraph.

This is the second paragraph.

*end *enter *output

This is the first paragraph.

|

This is the second paragraph.

Questo esempio specifica che se premo “enter” quando il cursore sta in mezzo a un paragrafo (il cursore è rappresentato dalla linea verticale nella seconda riga), il risultato deve essere di aprire un nuovo paragrafo e posizionare il cursore fra il tag di apertura e quello di chiusura.

Uno strumento consolidato per realizzare test di accettazione è fitnesse. In fitnesse i test sono specificati come tabelle di dati, e inseriti in un wiki. Le pagine del wiki possono facilmente essere modificate dal cliente o dagli sviluppatori, per riflettere la continua evoluzione della comprensione dei requisiti da parte di entrambi. Sull’argomento “specifiche sotto forma di tabelle”, è interessante questo raccontino di Brian Marick. Rick Mugridge ha scritto un libro di test Fit for Developing Software, dedicato a Fitnesse.

Esistono tool di accettazione specifici per applicazioni web. Selenium rappresenta i test come tabelle html conservate sul server, che vengono interpretate come programmi dal browser. Watir pilota Internet Explorer attraverso l’automazione COM. Questi tool violano una convenzione abbastanza accettata che i test debbano bypassare la interfaccia utente. Infatti rendono abbastanza difficile scrivere test che siano concisi e orientati al business.

Nel mio piccolo, mi sono trovato molto bene nello scrivere test di accettazione come semplici script nel linguaggio della shell di Unix, Bash. Sicuramente sarebbe stato più elegante usare Ruby; il mio problema è che sono tuttora molto più abile con bash che con Ruby (ha ragione Giuliano!)

PS: nell’ultimo progetto che ho lavorato, il nostro punteggio-Joel è stato di 7-8. Sigh.

Waterfall vs Agile

January 30th, 2006

Esempio: lo sviluppo di un compilatore per il linguaggio C. Un team di waterfallisti procederebbe in questa maniera: dato che la specifica funzionale è già fatta e consiste nel manuale del linguaggio C, si passa alla fase di design. Il design per il waterfallista consiste nello scomporre il sistema in moduli: l’analizzatore lessicale, che comunica con il parser, che comunica con il modulo che traduce l’albero sintattico in assembler, che comunica con l’ottimizzatore. Si definiscono delle interfacce, dopodiché la fase di design e conclusa, e si passa alla costruzione. Ciascuno di questi moduli viene sviluppato separatamente, il che permette (in questa fase) di fare lavorare più persone in parallelo. Ciascun modulo viene testato separatamente. Quando la fase di costruzione è finita, si passa all’integrazione: i vari moduli vengono compilati e linkati insieme. Quando il build funziona, si passa alla fase finale di test di integrazione.

Il problema di questo metodo di lavoro è che non c’è una misura concreta della qualità del lavoro fino a quando non si passa alla fase di testing. Il che significa che il committente può sapere qualche cosa di concreto sullo stato del lavoro solo verso la fine. L’avanzamento della costruzione dei vari moduli non è una misura concreta, perché non è possibile sapere per certo che il modulo funzioni nel contesto, fino a quando non viene integrato nel resto del sistema. I test unitari non possono trovare gli errori nell’implementazione o nell’interpretazione delle interfacce del modulo verso l’esterno.

Un team agile approccerebbe il lavoro in maniera molto diversa. Per prima cosa si fa funzionare il programma vuoto: “int main() {}”. Si scrive una prima versione funzionante del compilatore che è in grado di accettare il programma vuoto in ingresso e produce in output un file eseguibile (che non fa niente). Quindi dal primo giorno il committente ha in mano un programma funzionante, che implementa una parte, inizialmente molto piccola, delle specifiche funzionali.

Il passo successivo consiste, ad esempio, nell’accettare la dichiarazione delle variabili automatiche: “int main() { int x; }”, quello dopo nell’implementazione dell’assegnamento “int main() { int x; x = 0; }”, seguito forse dall’implementazione dei vari operatori aritmetici e logici, dalle chiamate di sistema, e così via. Ad ogni passo il compilatore è incompleto ma funzionante: implementa un sottoinsieme del linguaggio C. Ogni passo consiste nel prendere una carta dalla lista delle storie da implementare, scrivere i test di accettazione, i test unitari, e il codice di produzione, e integrare il tutto con il lavoro degli altri membri del team.

]]>

Prova

January 29th, 2006

1, 2, 3, Prova, prova… Si inizia sempre con un test.