PDI^2

articoletto su darcs

programmazione, web February 4, 2008 8:02 am (Save post)

Su StackTrace l’editor della categoria SW Engineering (piergiuliano bossi) ha pubblicato un mio articoletto su darcs, andate a darci un’occhiata :)

Se l’editor di The Ruby Mine (andrea reginato) trova tempo di riscriver^Wcorreggerlo, dovrebbe apparire un mio articoletto anche lì.

E con questo posso tirare una riga su “Cose da fare nel 2008: scrivere qualcosa per TRM e ST“.

script/performance/request in rails 2

personale, rubyonrails January 13, 2008 10:27 am (Save post)

Avete visto che figa la nuva fìciur che c’è in rails2? In pratica script/performance/request permette di eseguire uno scriptino che simula un’interazione dell’utente effettuandone il profiling.

Ora, vi invito a guardare il changelog, che mostra questo fantastico esempio;

    $ cat login_session.rb
    get_with_redirect '/'
    say \"GET / => #{path}\"
    post_with_redirect '/sessions', :username => 'john', :password => 'doe'
    say \"POST /sessions => #{path}\"
    $ ./script/performance/request -n 10 login_session.rb

Ora, cosa c’è che non va in questo eempio, diranno i miei piccoli lettori? Quello che non va in tutti gli esempi che ci sono in rails dalla versione 1.2 in poi, il fatto che non funziona.

Perché? Semplicemente perché post_with_redirect e get_with_redirect non esistono. say, d’altro canto, è un puts inutuile e non si capisce perché ci sia, forse perché a jeremy kemper piace molto perl6.

I dati, che verranno generati anonimamente nella directory tmp/ del vostro progetto, senza che ci sia modo di saperlo, sono d’altronde i normali dati di ruby-prof, il che significa che vi mostreranno come il 99% del tempo sia speso da rails per definire dei metodi. Sigh sob. Ah e ad ogni esecuzione request si lamenta di non trovare un file descriptor per la console (?) .

Mi chiedo che fine abbia fatto quella pulizia e precisione che c’era in rails pre 1.0 :/

Ah, i professionisti

programmazione, personale December 21, 2007 8:43 am (Save post)

Tra le cose che amo di più c’è il realizzare, di tanto in tanto, quanta aria fritta viene pompata ad altissima pressione e velocità da chiunque. Me in primis, quindi la cosa dà serenità, una specie di ansia-da-prestazione-litico.

Ora, prendiamo rails. Ci lavorano un sacco di professional da un sacco di tempo. Io non amo rails, ma cavolo, è oggettivamente potente, e io ne conosco forse il 20%.

Rails offre un’infrastruttura per la scrittura di test che è fantastica, chiunque ci abbia messo mano vi dirà quanto sono fighi i test funzionali, quelli unitari, assert_valid_markup, le fixture automatiche etc etc.

Vi diranno anche che i test dì integrazione, quelli che servono a verificare che i vari pezzi del progetto funzionino insieme, sono una figata pazzesca.

La cosa simpatica, è che nei test di integrazione è impossibile testare l’upload di un file, a causa di un bug che esiste da due anni, con il suo bel ticket, e c’è anche la patch. Ho provato a chiedere nella ML internazionale, ma la mail è passata in silenzio, c’è troppo traffico e di bassa competenza su quella lista. Su ruby-it c’è stato un feedback volenteroso, ma appunto abbiamo concluso che c’è un bug.

Ora riflettete: è impossibile testare gli upload, da due anni.
Significa che tutti i professional che ci sono la fuori, negli ultimi due anni, non hanno mai scritto un test per verificare se funziona l’upload di un file.

Che tradotto significa: o negli ultimi due anni nessuno ha mai usato un file_field, o nessuno la fuori ha mai fatto sviluppo TDD. Ma che dico TDD, diciamo “test automatici”, in generale, anche fossero alla fine di un processo waterfall.
È bello sapere che gli altri sono cazzoni quanto me :)

PS
esiste la possibilità però che il vero professional testi tutto con selenium..

coComments diventa uno schifo, passo a co.mments e mi scrive l’estensione

programmazione, web, software August 31, 2007 10:32 am (Save post)

La versione 2.0 beta di coComments è stata accolta da una salva di critiche enorme, al punto che gli autori hanno tenuto a specificare che no, suvvia, non è che deve rimanere così, gli utenti sono quelli che comandano etc etc…

A me però anche dopo le ri-modifiche continua a non piacere. Già prima era abbastanza bruttino, e l’estensione per firefox, per quanto potente, era ultralenta.

Per cui sto sperimentando con co.mments.com, che ha un tracking dei commenti molto migliore.

Purtroppo non ha integrazione col browser, il che significa dover cliccare su una bookmarklet per registrare una conversazione e visitare il sito per vedere le novità (o leggere il feed).

Per la prima cosa, non è un vero problema, e anzi, ha dei vantaggi.

La seconda è un po’ scomoda, per cui ho smanettato un po’ e mi son tirato fuori un’estensione per firefox che mostra un’iconcina colorata nella status bar quando ci sono nuovi commenti, e cliccando sulla quale si può andare a vedere il tracking.
Ho smanettato due ore, poi le divinità di javascript mi hanno dato una mano e ho ottenuto una cosa funzionante in 4 minuti netti.

Se volete provarla fate un fischio.

Fare casino con IRB, binding ed eval

ruby July 3, 2007 9:49 pm (Save post)

Ricordate quando parlavo del mio piccolo doctest per ruby?

Ok, continua ad essere sporco e puzzolente, ma adesso ha un paio di feature in più, tra cui la possibilità di effettuare il replay di una sessione passata.
Questo significa che se avevate un test-esempio


>> a = 10
=> 10
>> b = 20
=> 20
>> def sum(a,b)
>>  a+b
>> end
=> nil
>> sum(a,b)
=> 30

potete effettuare il replay della sessione ed andare avanti con


>> def triplesum(a,b)
>>  sum(sum(sum(a,b),b),b)
>> end
=> nil
>> triplesum(a,b)
=> 70

Che è molto carino, e utile imo.
Ora, dove sta il problema? Primo, nel modo in cui funziona eval, secondo, nel modo in cui è scritto IRB.

evil eval
Che eval sia fondamentalmente malvagio è una cosa rinomata, ma per scrivere un REPL rimane la cosa più sensata.
Quello che potreste non sapere è che in ruby eval() non può definire una variabile nello scope in cui è richiamata. O quasi.

Lasciate stare IRB e provate questo:

ruby -e \"eval('a=10');a\"

Se tutto funziona normalmente dovreste beccarvi un bel NameError. Questo perché il parser non ha mai visto nessuna a nello scope corrente.
Se però provate questo:

ruby -e \"eval('a=10');p eval('a')\"

vedrete stampato un bel 10 che dimostra che la variabile esiste solo che non è accessibile con il solito approccio.

good IRB
IRB però vi frega in questo, guardate un po’:

>> eval(\"a=10\")
=> 10
>> a
=> 10

Perché? Perché ovviamente IRB usa internamente eval, non fa il parsing come l’interprete farebbe normalmente, e quindi tutto funziona.

good require
Se caricate un file con require() le variabili locali rimangono.. beh.. locali, e quindi non sono accessibili all’esterno. Allora come facciamo a caricare le variabili locali che avevamo nella sessione precedente?
Non possiamo fare un dump del codice su un file e caricarlo con questo metodo, ma possiamo usare eval() per definirle in un oggetto Binding e poi convincere IRB che deve usare quell’oggetto come spazio di lavoro.

evil IRB
Solo che IRB, di default, non permette di effettuare questa cosa. C’è un casino di setup quando la console interattiva viene inizializzata, che va dal caricare l’encoding al verificare la configurazione di default all’impostare il nome del programma, e tutto questo è fatto tramite IRB.start che non ammette alcun parametro utile per i nostri scopi.

Soluzione
Qual’è la prima forma di riuso? Il copia&incolla, esatto. Quindi per definire la nuova funziona ci si limita a ricopiare il codice di quella originale in modo quasi identico, cambiandolo dove serve.

In attesa che qualcuno ci dia una versione di IRB che ci semplifichi la vita, potete quindi usare il mio IRB.start_in_binding che crea una console per il binding dato (o per TOPLEVEL_BINDING).
Pare funzionare, in caso non andasse potete ravanere nei sorgenti di IRB da soli o sfruttare il lavoro fatto da flgr in ruby-breakpoint

Costruttori brutti linguaggi dinamici belli

programmazione June 26, 2007 8:55 am (Save post)

Sul blog di gilad bracha c’è un post che parla del perché i costruttori sono anti-oo.
Giovanni Corriga(finalmente ha un blog!), vi direbbe che è perché la gente continua a pensare agli “oggetti” invece che ai “messaggi”. In pratica cosa c’è che non va?

Fondamentalmente, che usando un costruttore alla java/c#/c++ si introduce un accoppiamento forte nel codice che andrebbe evitato. È una nozione abbastanza diffusa che uno dovrebbe scrivere codice relativo all’interfaccia e non all’implementazione, e invece usando i costruttori ci si lega invariabilmente a un certo modo di fare le cose. Esempio scemo:

DatabaseMapper dm = new DatabaseMapper()
dm.save(someObject)

A un certo punto vi rendete conto che DatabaseMapper potrebbe essere preferibile come singleton o come un riferimento a un pool di oggetti. In qualsiasi modo vogliate spostarvi dall’avere un oggetto sarete costretti a rompere l’interfaccia introducendo un metodo come getInstance() e nascondendo il costruttore.

In ruby, Smalltalk, python, perl e CL, invece, non esiste un concetto speciale di costruttore.
Un metodo è responsabile di allocare un oggetto. Un altro metodo è responsabile per l’inizializzazione. Infine, un comodo metodo di utilità si occupa di fare entrambe le cose.
Scrivendo

 dm = DatabaseMapper()
in python quello che in realtà accade è che richiamate il metodo __call__() il quale a sua volta alloca l’oggetto con __new__(), lo inizializza con __init() e lo restituisce.

Quando decidete di passare al singleton non dovete far altro che cambiare un metodo e tutto continua a funzionare correttamente.
Lo stesso discorso vale per ruby, solo che i metodi in questione sono new, allocate e initialize.

Smalltalk e common lisp, per quel che ne so, seguono lo stesso identico approccio, con la sola singola differenza che i metodi non hanno una visibilità ristretta ma sono pubblici. Nel post di gilad bracha si parla di Smalltalk dicendo che non forza il fatto che un oggetto sia inizializzato una sola volta, e immagino parli di questo, ma da buon programmatore dinamico io ritengo che si tratti di un non-problema.

Il linguaggio non deve costringere a fare cose stupide, ma non è utile trattare il programmatore da idiota.

Ad ogni modo credo sia interessante considerare come, ancora una volta, aggiungere un costrutto ad un linguaggio (i costruttori) ne diminuisca le potenzialità invece di aumentarle. Meditate gente, meditate.

UidBind e il self-marketing

programmazione, linux, web June 24, 2007 2:37 pm (Save post)

Da anni sono un utente felice di un certo servizio di hosting, per vari motivi.

Primo, sono open-source friendly. Nel senso che usano software libero, contribuiscono allo sviluppo di quel che usano e supportano la gente che supporta l’open source, come ruby-it o ziobudda .

Secondo, ho il supporto via jabber di una persona (roberto) che conosco di persona :)

Terzo, sono una manica di hacker, nel senso positivo del termine. Il vero motivo per cui su unbit è possibile usare Camping o Django, si ha disposizione mercurial, e si può accedere al pannello di controllo tramite XMP-RPC è perché è fico, non perché ci sia un grosso mercato.

Ma essendo una manica di hacker hanno anche i tipici difetti di relazione col mondo, ad esempio una homepage inaccessibile.

Tutto questo per parlarvi di uidbind, che è un modulo kernel per linux che permette di impostare permessi di accesso granulari a specifiche porte TCP/UDP.

L’amministratore può, tramite un albero di directory configfs, selezionare alcune porte e rendere possibile solo all’utente X di effettuare una bind() su di esse, il che ha un grosso potenziale per evitare che si crei casino.

Mettiamo che si permetta agli utenti di lanciare dei server (esempio: mongrel, o tomcat). Il default è che gli utenti comincino a pestarsi i piedi a vicenda, andando ogni volta a occupare le porte altrui e forzando un algoritmo distribuito di “ti frego la porta o devo modificare le configurazioni” che è decisamente sgradevole.

Con uidbind è possibile assegnare ad ogni utente una porta e far si che usi sempre e solo quella e che nessun altro abbia la possibilità di usarla, in nessun modo.

Il modulo ha anche il potenziale di eliminare quella vecchissima eredità di UNIX per cui le prime 1024 porte sono riservate a root. La ragione, all’epoca, era che si voleva evitare che un utente potesse effettuare l’hijack di servizi trusted (esempio: telnet o http), ma l’effetto collaterale è che ancora oggi tutti i servizi classici devono partire inizialmente come root.
Facendo si che l’accesso alle porte sia gestito in modo granulare sarebbe possibile riservare le prime porte a root e poi, caso per caso, riassegnarle ad utenti specifici come httpd o smtpd, superando finalmente limitazioni vecchie di decenni.

Ora vabè che il modulo è ancora in betamm ma guardate la pagina di uidbind. Neanche un po’ di auto-esaltazione porca miseria!

Perché Java è meglio di Ruby

ruby, java, fun June 22, 2007 4:56 pm (Save post)

Si, siamo una comunità di disturbati, e ne siamo fieri.

Ruby & rails vs J2EE, di nuovo

ruby, java, blogosfera June 13, 2007 2:44 pm (Save post)

Su TRM c’è un articoletto che ha l’intento di spiegare rails al programmatore J2EE, e da lì c’è un articoletto di risposta di uno sviluppatore J2EE, appunto.

Le mie dure lire: usate quello che è più adatto al progetto corrente, che conoscete meglio e che preferite. È il modo giusto per vivere felici :-)

Ad ogni modo, nel post e nei commenti ci sono dei punti validi: la m17n in ruby è ancora debole (ma per il web cambia poco, visto che utf8 è gestito), il deploy non è ancora un’operazione banale, ruby non ha i thread nativi ed è un interprete lento, non esiste accesso a tutta la pletora di MOM che c’è in java e altro. Ricordo che io, fondamentalmente odio rails ;)

Però, siccome l’autore dice di cercare l’oggettività, per quanto ovviamente possibile, mi permetto di rettificare alcune cose sbagliate ( credo siano dovute alla mancanza di conoscenza dell’ambiente, non a un FUD intenzionale ;)

Su ruby:

  • ruby non ha le variabili dì’istanza pubbliche di default, anzi non è proprio possibile avere variabili pubbliche, si accede solo attraverso metodi.
    Le variabili d’istanza pubbliche sono una rottura dell’incapsulazione (eccezione: property alla python/C#/TP) e infatti in Smalltak, che la OO l’ha inventata, non esistono.
  • non so cosa significhi che la struttura delle classi è neogotica, perché non so qual’è l’equivalente degli archi a sesto acuto in ambito programmatorio, ma la gerarchia delle classi mi sembra abbastanza ragionevole. Non c’è neanche l’ereditarietà multipla che dovrebbe far storcere il naso ai javisti (io, essendo anche pythonista non ci vedo niente di male :)
  • sinceramente non mi pare sia possibile assegnare una variabile da sinistra a destra in ruby, a meno che non ci sia un operatore “->” che non ho mai trovato negli ultimi 6 anni
  • le variabili d’istanza vengono istanziate al volo, vero, ma puoi comunque farlo solo tramite i metodi (o la reflection) quindi non c’è problema
  • “La tipizzazione degli oggetti base è da barzelletta non esiste”. De gustibus, a me i tipi dinamici piacciono. D’altronde neanche java è type safe, e HAppS è ancora un po’ ostico per me.
  • gli errori sono più comprensibili in ruby imho. Almeno l’equivalente di NullPointerException ti dice che metodo è stato richiamato, perché nil è un oggetto
  • mai fallita l’installazione di una gemma, ma capisco possa accadere. Però il confronto con maven mi pare inappropriato, non è un package manager.

Su Rails:

  • il sistema di template (che imo pone pochi problemi) si cambia in una riga. script/plugin install liquid | haml | erubis | ya2yaml | amrita | markaby o quel che volete
  • credo che il plurale di persona (as in dramatis persona) sarebbe personae, ma si sa che gli inglese col latino fanno porcate :) . Aldilà di questo, è possibile definire le proprie inflection se si vuole un db sgrammaticato (o uno legacy)
  • non ho capito che significa che la gestione degli url viene fatta in punti diversi, io la faccio solo in routes.rb
  • non so perché non si possa usare un qualsiasi approccio allo sviluppo. In teoria si può sviluppare un’applicazione RoR anche senza modelli e controller ma grazie al cielo lo fanno in pochi ;)
  • si può usare uno schema legacy, si può fare. Ci sono pure plugin per farlo. Certo, manca JCA.
  • manca il supporto all’internazionalizzazione builtin, ma esistono plugin come globalize apposta. Rimane sempre meglio averla builtin, come in django (lo dicevo di là) e comunque il supporto a unicode è scadente, come dicevo prima, ma c’è sempre UTF-8.
  • non ho capito il problema con gli scaffolding. Quelli servono a evitare di scrivere un po’ di codice, mica sono un’interfaccia di amministrazione (django++ ma per rails ci sono, ancora, dei plugin)

Sui punti generali non posso commentare.. non uso capistrano, ViM è il mio IDE e Rails forse non scala ma non per colpa di FastCGI (che è concettualmente molto diverso da CGI). Yahoo, Google, Digg, reddit, Flickr, livejournal etc scalano infinitamente senza servlet. <flamebait>e poi vorrei vederla questa mega applicazione in java che scala come slashdot, che è fatto con mod_perl </flamebait>

Ancora, right tool for the job, KISS, long life & prosperity, io domani parto per l’heineken jammin festival dove non mi preoccuperò di queste cose :)

ruby, doctest e lo pseudofile DATA

ruby June 12, 2007 8:33 am (Save post)

Sono un maestro del tosare yak.
Ovvero, di quella antica e nobile pratica per cui devi risolvere un problema, che però dipende da un altro, il quale porta a un altro che porta a un altro e a un certo punto ti trovi a depilare uno yak per far funzionare il tuo blog.

Nel mio caso il processo è stato

  1. mephisto non ha la feature X (che ho dimenticato cosa fosse)
  2. cavolo dovrei scrivermi il mio blog engine..
  3. beh posso farlo usando ramaze
  4. peccato non abbia una gui di amministrazione automatica
  5. beh posso sempre farla se ho un buon ORM
  6. ma non mi va di usare ActiveRecord, oltretutto son sempre stato un fan del Data Mapper
  7. oddio c’è la v0.50 di Og.. no ancora non è rilasciata e non hanno tolto tutti i rescue Object… brrr
  8. vabè, potrei scrivermene uno io, piccolino, ma ben testato
  9. cavolo se son brutti sti test..
  10. ah beh posso usare test/spec
  11. cavolo sti test fanno schifo..
  12. e poi non son capace di azzeccare una descrizione..
  13. ah avessi doctest come in python..
  14. beh potrei scrivermi il mio..

Ed è a questo punto che ci ritroviamo, circa una settimana dopo, 1400 righe più tardi, e con SLOCCount che per questo progetto stima 4 mesi di lavoro e una spesa di 38.581 dollari, da investire in 0.83 sviluppatori (?).

1400 righe? Ma sei scemo?? diranno ora i miei piccoli lettori.
In verità si, ma non per questo, in quanto solo un quinto di queste sono la libreria, mentre il resto sono i miei test unitari & doctest.
La mia libreria è piccina, se considerate che SLOCCount su ActiveRecord trova 22941 linee di codice :) .

Ed il bello è che metà di queste righe sono doctest, che nella mia microimplementazione significa: apri irb, prova cose, copincolla.

Come funziona test/doc

La “libreria” che fa funzionare il tutto è lunga ben 30 righe, perché è mal scritta e scorretta, ma io le voglio bene lo stesso.

L’idea è semplice: ogni operazione in un REPL come irb è composta da due parti: il codice, e il risultato. Se usate irb con l’opzione –simple-prompt si tratta di una cosa come questa:


>> codice()
=> risultato

dunque se le righe sono in un oggetto enumerabile basta usare grep per trovarle e ignorare le altre linee, nelle quali potrete aggiungere utili commenti o, nel mio caso, i modeltest di django ancora da tradurre :)

Una volta che avete la lista ordinata in coppie input/output basta fare l’eval del primo e confrontrarlo con il secondo. Facile, no?

In realtà no, definendo un metodo o una classe in irb questo non va perché vi trovate con input multilinea, ma io mi limito a ignorare il problema, e i miei test sono abbastanza carini.

Ora: dov’è il posto migliore per mettere i doctest? Nei commenti, potreste dire voi. Concordo in generale, ma in questo caso, visto che le cose da fare sono molte e le righe del modello molto poche, sembrava più conveniente mettere i test nello pseudofile DATA.

Per chi non lo sapesse, ruby mette a disposizione del programmatore una variabile, DATA appunto, che si comporta come un oggetto File, ovvero è possibile leggere le linee, fare seek etc etc.

Il contenuto dell’oggetto non è però un vero file, ma il pezzo del file .rb corrente che sta dopo dopo la keyword __END__.

Sembrava perfetto per il mio scopo. Nessun require strano, nessun problema per fare parsing, codice
& esempi nello stesso file ma separati e dovendo aggiungere una singola linea di codice.

Senonché, e qui viene il problema, DATA non funziona come mi ricordavo io.
Ovvero, la variabile è globale e rappresenta la relativa sezione non del file corrente (cioè di __FILE__) ma dello script in esecuzione (cioè $0 o $PROGRAM_NAME).

Ergo eseguire i miei doctest tramite rcov è impossibile, perché DATA è inizializzato, male, in rcov stesso. Vabè, torniamo al parsing a mano, in fondo basta leggere il file in un array di linee e poi scorrerlo finché non si trova __END__

Però dovrei ridurmi a specificare il nome del file ogni volta che voglio creare un doctest.

Soluzione: filename ||= caller[0][ /^.*?(?=:)/ ].

Lasciando stare la Regexp, significa che usiamo come nome del file quello in cui c’è il codice che crea il DocTest.

Quindi se ho una riga DocTest.new in test/sample.rb non c’è bisogno che usi degli argomenti, perché usando caller posso scoprire automaticamente qual’è il file chiamante (appunto, test/sample.rb.

Ora i miei test funzionano, sono gradevoli e posso usare quelli di django praticamente copincollandoli (come noterete ci son pure gli stessi commenti).
Trentottomila dollari ben spesi!

Get free blog up and running in minutes with Blogsome
Theme designed by Janis Joseph