Pensieri e parole su HCI, home computing, tecnologie desktop e sul Progetto Lobotomy

mercoledì 24 novembre 2010

Riuso Fai-da-Te

0 commenti
Una delle cose che piu' amo del software libero e' la possibilita' di utilizzare e riutilizzare all'infinito frammenti e porzioni di codice, magari anche in contesti diversi rispetto a quello entro cui sono stati scritti. Spesso e volentieri io stesso mi trovo a copiare e incollare funzioni o intere classi dall'Internet, pescando dai repository, e al "costo" di poche righe di commento destinate ad indicare il copyright dell'autore originale si ottiene in pochi secondi la funzionalita' desiderata.
Tale proprieta' non e' purtroppo sempre applicabile ai componenti software complessi.
In questo periodo mi sono trovato a dover elaborare una soluzione composta, in buona sostanza, da un captive portal, un pannello per la gestione delle utenze, ed una centralizzazione degli accounts su un unico server. Scopo del gioco: esibire i documenti per l'autorizzazione alla navigazione web (grazie, Pisanu) una volta sola, e poter poi accedere a tutti i locali all'interno del network convenzionato e geograficamente sparso usando sempre la stessa utenza.
Di captive portal opensource e' pieno il web. Nessuno di questi prevede una gestione avanzata degli accounts, i quali sono sempre e solo gestiti localmente. E, anche volendo dirottare le connessioni al database con qualche hack (pericoloso, in quanto comunque deve esistere un meccanismo di validazione dei routers periferici nei confronti del server centrale), non sarebbe comunque possibile personalizzare in modo agevole le anagrafiche trattate per fargli fare quel che mi serve (banalmente: associare gli accounts ai soci dei locali nel network, con tutto quel che ne consegue in termini di scadenze delle iscrizioni).
Dopo ardue ricerche incrociate, e valutazione di diversi blocchi di codice pescati qua e la', non son riuscito ad isolare i pezzi che mi servivano ed alla fine ho ceduto ed ho ben deciso di rifare tutto daccapo prendendo ispirazione qua e la'.
Purtroppo non si puo' porre un argine a questo problema, comune a pressoche' qualsiasi applicazione complessa. Isolare in modo chirurgico i componenti e' una best practise che esiste solo sui manuali accademici di ingegneria software, nel mondo reale non si puo' fare in quanto comunque alcuni presupposti (ad esempio: la gestione e la validazione degli utenti) devono essere validi a priori in tutto il sistema ed inevitabilmente vanno a cozzare contro i presupposti usati altrove.
Quel che piu' mi perplime comunque non e' l'utilizzo di componenti separate, quanto l'utilizzo di piu' componenti insieme. In questo periodo mi sto molto interessando alla questione della legge regionale piemontese per la promozione del software libero, e spesso scopro che alcune amministrazioni in giro per l'Italia e per l'Europa hanno gia' rilasciato questo o quest'altro frammento potenzialmente utile per altre amministrazioni, ma temo il giorno in cui esse dovranno essere messe insieme e proposte a mo' di pacchetto chiavi-in-mano a qualche istituzione: ciascuna e' stata scritta con un framework diverso, in un linguaggio diverso, con specifiche ed architetture diverse, e presenta una interfaccia diversa, organizzata in modo diverso. Mettere insieme tutti questi pezzi, che presi singolarmente sono assai utili ma comunque non determinanti, si annuncia come una missione impossibile, e gia' so che il giorno in cui si prendera' di petto la questione molti di essi dovranno essere in buona parte riscritti. I sogni di riusabilita' immediata e propagazione del software pubblico sono destinati ad infrangersi contro lo scoglio del pragmatismo.
Ancora oggi la riusabilita' e' un mito. Che urge sfatare, per sbloccare finalmente in modo completo l'immenso potenziale del software libero.

domenica 14 novembre 2010

Zero Upgrade

0 commenti
Nel precedente post ho fatto menzione alle comodita' programmative dell'usare una rappresentazione "uno a uno" degli oggetti manipolati ad alto livello con lo schema del proprio database: poco codice che gestisce tutto quanto, logica abbastanza lineare e necessariamente coerente dunque comprensibile, grande flessibilita'...
Qui vorrei fare una rapida menzione ad un ulteriore vantaggio di questa strategia, che ho l'altro giorno implementato e perfezionato nel codice del mio gestionale per gruppi di acquisto: l'aggiornamento automatico e trasparente del database in caso di upgrade dell'applicazione.
Passando dalla release 1.0 alla release 2.0 mi sono posto il problema di rendere l'upgrade di GASdotto semplice, almeno tanto quanto lo e' l'installazione, ma ho sicuramente fatto le cose un po' di fretta e mi son ritrovato un garbuglio di "ALTER TABLE" che certamente non avrei potuto mantenere anche nella futura release 3.0 (dovendo peraltro gestire i casi di migrazione partendo da 1.0 o 2.0). Alche' mi sono ingegnato ed ho deciso di spremere meglio la mia mappatura degli oggetti sul database, implementando l'operazione inversa: costruire il database partendo dalle classi PHP.
La funzione che effettua davvero le query (resa unica in tutto il programma originariamente con l'intento di centralizzare la gestione degli errori) e' stata modificata in modo che, se una richiesta verso il database fallisce, prima di tentare una seconda volta verifica che tutte le tabelle siano al loro posto e che esse abbiano tutte le colonne che descrivono gli attributi dei miei oggetti PHP di alto livello. L'effetto collaterale di tale meccanismo e' ovvio: GASdotto non abbisogna piu' di una procedura esplicita di upgrade, basta decomprimere l'archivio compresso al posto del precedente (magari salvandosi prima il file di configurazione) e al primo login si arrangia da solo nel modificare il database allineandolo alla struttura richiesta con le nuove colonne e le nuove tabelle.
La procedura deve ancora essere testata con cura, ma i primi esperimenti sono stati soddisfacenti: trovandomi adesso ad attuare qualche correzione alla gestione delle notifiche mi trovo a dover aggiungere qualche attributo alla classe Notification, e laddove prima dovevo rimaneggiare la classe PHP, quella Java e lo schema del database, adesso metto mano solo al codice e la prima volta che ricarico l'applicazione nel browser la query fallisce, esegue il controllo, crea le nuove colonne richieste nelle tabelle e tira dritto.
Sebbene il tutto sia ancora migliorabile (manca la definizione dei valori con cui inizializzare le eventuali nuove porzioni di database) posso ritenermi soddisfatto di questa novita': ho eliminato un passaggio richiesto per l'amministrazione dell'applicazione da parte degli utenti (spianando peraltro la strada ad un futuro automatismo per l'aggiornamento trasparente, come quello gia' esistente nell'ottimo Wordpress), ed io ho ridotto la quantita' di cose di cui preoccuparmi durante lo sviluppo.
Regola 1: essere pigro, e far fare alla macchina quello che non si ha voglia di fare a mano.

giovedì 11 novembre 2010

Il Pallino del Database

2 commenti
Ogniqualvolta mi confronto con un qualche programmatore in merito ad una qualsiasi applicazione che deve gestire un po' di dati, pare che la prima (ed unica?) preoccupazione sia lo schema del database. Mi e' gia' capitato con numerosi personaggi, tra cui un SAPpista, un imprenditore ex-sviluppatore di gestionali, diversi developers freelance, insomma con chiunque abbia anche una vaga idea di come scrivere codice: quando si parla di un programma, la prima cosa che vogliono vedere e' il database.
Saro' un eretico, ma a me non pare che questo componente necessiti di tali particolari attenzioni.
Certamente dallo schema del database adottato dipende la scalabilita', la possibilita' di aggiungere funzionalita' complesse in futuro, ed in parte la performance del sistema completo, ma da quando ho adottato una nuova prospettiva nel processo di sviluppo di GASdotto ho smesso di preoccuparmi particolarmente della cosa.
Sostanzialmente, in GASdotto il database e' la rappresentazione "uno a uno" degli oggetti maneggiati dall'applicazione, e tutte le interazioni con questi oggetti sono formalizzate secondo una manciata di regole.
Ad esempio: l'oggetto "Order" e' un ordine aperto presso un fornitore. All'interno della classe sono iscritte le proprieta' che compongono tale elemento. Sul database, c'e' una tabella che si chiama "Orders" (tipicamente le tabelle si chiamano nello stesso modo della classe di riferimento, ma ho dovuto fare una eccezione poiche' "order" e' una parola chiave di SQL) che riporta esattamente quelle stesse proprieta'. Dove l'oggetto ha una stringa, sul database c'e' un varchar. Dove c'e' un numero, corrisponde un intero. Dov'e' c'e' un riferimento ad un oggetto descritto da un'altra tabella, vi si trova la chiave esterna a quella tabella. Nel caso particolare delle relazioni "uno a molti" (ad esempio: i prodotti contemplati all'interno dell'ordine), si utilizza sempre una tabella di appoggio che si chiama "nomedellaclasse_nomedellattributo" e due colonne, una per l'entita' di riferimento (l'ordine) e l'altra per i sottoelementi (i prodotti).
Lo schema non e' per nulla ponderato o meditato: ogni informazione che serve e' memorizzata secondo una forma definita a priori, senza soffermarsi mai sul caso specifico.
Durante l'implementazione del supporto alle "varianti" dei prodotti in GASdotto 2.0 ho constatato come questo approccio sia facilmente adattabile: alla fine dell'opera mi son ritrovato con numerose nuove tabelle, ma per quanto complessa sia la relazione tra prodotto, variante, prodotto ordinato, varianti ordinate, prodotti consegnati eccetera, in breve sono riuscito a cavarne una definizione sempre coerente e non eccessivamente arzigogolata.
Il vantaggio maggiore di tale strategia e' che, essendo tutto maneggiato con poche regole sempre valide, il codice necessario alla serializzazione, deserializzazione, e reperimento e salvataggio delle informazioni e' unico in tutti i casi. Il guscio piazzato intorno al database e' ridotto a poco piu' dei minimi termini, una unica classe ("FromServer". Nome assai poco fantasioso...) provvede alla stragrande maggioranza del lavoro. Cosa non da poco, in termini di mantenibilita'.
Sicuramente lo schema finale non e' il piu' ottimizzato che si possa pensare, e non dubito che si potrebbe fare molto di meglio in termini di performance e risorse occupate, ma in fin dei conti la differenza non si nota. L'istanza nota piu' grossa di GASdotto conta attualmente 600 diversi prodotti da 30 diversi fornitori, il dump completo (e compresso con l'opzione -Ft di pg_dump) di PostgreSQL e' di quasi 1 megabyte, eppure il tutto pare sufficientemente reattivo ai 170 utenti registrati (a parte quando la componente Javascript inizia a macinare tutti quei dati in un colpo solo nel browser, ma e' un altro discorso).
Insomma: personalmente, ho smesso di dare tanto peso a come e' fatto il database di backend delle applicazioni. Quantomeno delle mie. Qualche microsecondo di elaborazione in piu' val bene tutta questa flessibilita' compressa in una cosi' modesta quantita' di codice.