martedì 12 giugno 2007

Letteratura Fiabesca Applicata all'Informatica



Suppongo siate in pochi ad essere a conoscenza del fatto che le fiabe e, più in generale, i racconti del folclore, sono classificabili secondo un sistema analitico, definito da Aarne e Thompson, che si sono presi la briga di leggersi migliaia di fiabe e di appiccicargli etichette tipo: AT 425A “Il mostro o animale come sposo”, o AT 0151 "Lezioni di musica da animali selvaggi".

Sarà anche probabile che non possa fregarvene di meno di questa notizia e che stiate già per cambiare blog, borbottando che cercherete di fare del vostro meglio per dimenticarvi queste inutili nozioni, come Sherlock Holmes quando Watson gli fece notare che la terra gira attorno al sole ("Uno studio in rosso").

Se decideste davvero di farlo sarebbe solo l'n-esima triste conferma che la scuola non prepara più come una volta, che stiamo perdendo l'interdisciplinarietà e potenziali Leonardo e Galileo, appiattiti in una bruttura informatico-virtuale, per la quale non dovrete stupirvi se incontrerete a breve qualcuno che, usando espressioni care al Manzoni, potrà giustamente apostrofarvi con nel mezzo, vile meccanico.
(se siete riusciti a sopravvivere alle contorsioni e forzature della frase precedente - n-esima triste conferma del fatto che la scuola non sa più insegnare a scrivere in italiano -, forse avrete anche speranze di salvarvi culturalmente, ma dovreste certamente preoccuparvi per potenziali problemi mentali latenti).

Quelli tra voi più illuminati ed abituati a ragionamenti elastici, invece, non si saranno certo fatti sfuggire l'evidente parallelismo tra questo tipo di tipizzazione e quella presente nei linguaggi di programmazione (converrete senza dubbio, invece, che sarebbe un po' forzato trovare somiglianze con i Design Pattern, per i quali potremmo, invece, spingerci a considerare lo Schema di Propp).

Sarà inoltre evidente a tutti che gli spunti provenienti da un umanesimo di alto livello adatti ad introdurre il mio contributo nell'arena della tipizzazione forte o debole nell'informatica avrebbero potuto essere molteplici (dal 'sono un tipo, anzi un topo' di Geronimo Stilton, ad approfondimenti su grammatiche e licenze poetiche, etc. etc.), ad ulteriore dimostrazione che non si tratta di un argomento ormai consunto, ma di parte integrante delle esigenze culturali fondamentali dell'uomo e, pertanto, degno di essere ancora una volta approfondito...

(per il mio e vostro bene, qualcuno mi tolga dalla testa lo scrittore barocco che sta suggerendo queste ultime righe, prima di continuare la lettura)



Prima di iniziare la tesi di laurea, pur conoscendo (ovviamente! spero non vi abbia neppure sfiorato il dubbio!) la differenza tra tipizzazione forte e debole (strong and weak o static and dynamic typing), avevo sempre affrontato il problema procedendo per istinto.

Esattamente al contrario del mio tutor, che usava il Common Lisp ricercando strutture e controlli sui tipi di dati come se stesse usando il C, io tendevo a programmare in modo volontariamente non tipizzato.

Quando due uomini forti si scontrano su argomenti così decisivi per il bene della comunità è quasi inevitabile che nasca una discussione (animata, ma divertente): io difendevo la flessibilità che un simile approccio poteva fornire (soprattutto in lisp e, caspita, se non si cerca il massimo della flessibilità proprio nell'AI...) e lui difendeva la correttezza formale ed il controllo a compile-time, necessario, in particolar modo, in caso di sistemi particolarmente complessi (e ulteriormente utile, nel caso si debba lavorare con risorse alle prime armi o quasi, per ridurre significativamente le probabilità di errori).

Ancora oggi, di fatto, mi piace ridurre al minimo i vincoli, soprattutto se posso fidarmi degli sviluppatori del team.
Mi piacciono e ritengo fondamentali i Generics, ma se programmo per mio divertimento (sia per attività AI-related che non), tendo a saltarli apposta e mi gioco con reflection, metadati, valutazione dinamica di espressioni e, in genere, di codice (e perchè no, generato automaticamente) ed ignoro i warning di non tipizzazione delle collection che rischiano di ridurre la flessibilità del mio sistema (ovviamente, il cast automatico delle classi è due volte essenziale).

Cerco la genericità anche a livello di database, nei pochi spazi concessi (se c'è un sistema giustamente tipizzato quello è il DB, converrete). Che so: quanto è meglio poter dire varchar2, al posto che varchar2(20)? oppure, e questo viene condiviso praticamente da tutti, quanto è bella la sintassi che permette di definire, in PL/SQL, una variabile come di tipo tabella.campo%TYPE? E, nonostante il rischio di ridotte performance (ma dipende dai casi) e la complessità nel costruire query dinamiche che siano anche solide, non posso evitare di essere attratto anche da questa ulteriore non tipizzazione.

Senza esagerare, chiaramente: non proponetemi campi di testo o LOB per contenere informazioni aggiuntive, neppure se state pensando di strutturarle in XML (anzi, peggio, se sono strutturate in XML - ma ne parlo un'altra volta, perchè i motivi non c'entrano con questo argomento).

Non sono un estremista, in questo senso: semplicemente ritengo, come in altri casi, che sia essenziale conoscere i pro e i contro di ogni approccio e che, evidentemente, le regole informatiche sono fatte per essere infrante, anche se solo quando si sa esattamente cosa si sta facendo, comprendendone appieno gli effetti collaterali.

Dobbiamo tener presente che siamo comunque costretti a trattare con la tipizzazione dinamica, anche perchè ne siamo circondati. Per esempio:
  • http: tutto è stringa (siamo noi che le riportiamo a tipi, una volta che estrapoliamo dalla request, cercando un mapping e binding più o meno esplicito, ma il protocollo non prevede altro)
  • Javascript: le dichiarazioni di tipo non esistono e possiamo cambiare allegramente il tipo dati (e nessuno dice che sia corretto o consigliabile o facilmente debuggabile - anzi, già che ci siamo: vi anticipo che ritengo che, laddove si usi Javascript lato client, sia veramente pericoloso ed inutile, per la povertà dell'ambiente di esecuzione, utilizzare coscientemente questa possibilità)
  • polimorfismo: nasce per migliorare il riutilizzo di codice: è una sorta di via di mezzo tra tipizzazione forte e debole, no? (tipizzate pure fortemente, tanto io vi referenzio ad un livello più astratto, meno caratterizzato, anche se proprio nelle vostre particolarità...). In realtà tende così tanto alla tipizzazione dinamica che non pochi linguaggi di ampio uso permettono quello che viene chiamato Duck Typing. Che ha un po' a che fare con l'induzione (ricado sempre nell'AI, non c'è verso...). Vi consiglio di approfondire in particolare l'estratto del precedente link riguardante il duck typing in Java e, in particolare, l'articolo di David Orme (il papà di Visual Editor Project di Eclipse) che riporta il pattern e i suoi dettagli implementativi
  • etc. etc.
Spingendo all'estremo l'interpretazione del concetto in esame fino alle generiche strutture dati, saltano agli occhi anche le seguenti alternative (da considerarsi come esempi non esaustivi):
  • ResultSet vs. Bean ORM: i ResultSet con i loro metadati sono una sorta di interfaccia non tipizzata (che, curiosamente, wrappa dati fortemente tipizzati), con ottimizzazioni basate sulla presenza di metadati, in contrapposizione ad un classico (da Hibernate, per intenderci) mapping tra tabelle e Java Bean
  • Bean vs. HashMap: si tratta di una alternativa simile alla precedente, che si può porre laddove preferiate non ricompilare, ma, piuttosto, gestire una configurazione, perdendo in controlli compile-time
Proviamo a ricordare, prendendo spunto dalla solita Wikipedia, le funzionalità principali che sono sostenute dalla tipizzazione forte:
  • sicurezza: il compilatore può già identificare codice errato, riducendo i costi di debugging. Posizioni estremiste arrivano a dire che una tipizzazione molto forte potrebbe evitare la gran parte degli errori del codice, nonostante l'esperienza insegni che, pur essendo indubbio il vantaggio fornito in questo senso, solitamente i bug più insidiosi non potranno mai essere individuati dal compilatore (anche perchè, nella maggioranza dei casi si tratterà di interpretazioni di business)
  • ottimizzazione: un controllo di tipo statico fornisce al compilatore informazioni fondamentali per creare codice più efficiente. Il vantaggio viene in parte compensato dal fatto che, mentre è innegabile che la generalizzazione implichi solitamente esecuzioni più complesse (quindi più lente - es.: reflection), è anche vero che richiede minori controlli per verificare che i tipi siano o meno rispettati. Inoltre, tipicamente, la tipizzazione debole richiede meno righe di codice sorgente, meno codice da rivisitare, cicli di edit-compile-test-debug ridotti.
  • documentazione: i tipi sicuramente aiutano ad indicare chiaramente le intenzioni del programmatore, migliorando complessivamente il passaggio di informazioni
  • astrazione e/o modularità: tipi complessi permettono ai programmatori di progettare ad un livello più elevato (es: stringhe e non array di bytes), semplificando la definizione delle interfacce tra componenti e sistemi. Migliorare la definizione delle interfacce è, ovviamente, particolarmente utile (meglio: fondamentale, inevitabile, basilare, essenziale, ...) nell'ambito della progettazione ad oggetti e nel caso di integrazioni con sistemi gestiti da altri team (con contratti chiari e fortemente tipizzati è più facile definire precisamente le responsabilità e ridurre i tempi complessivi, aumentando l'interoperabilità e riducendo le inconsistenze tra i sistemi).
Sempre la stessa voce della Wikipedia ricorda anche, però, che la tipizzazione dinamica si trova spesso nei linguaggi di scripting e nei linguaggi per il RAD (Rapid Application Development)

Per quanto riguarda i linguaggi di scripting, rimanderei alla conversazione tra Bill Venners e Guido van Rossum (il creatore d Python), veramente interessante sia da un punto di vista di progettazione software che da un punto di vista di gestione tecnica di progetto, un must sull'argomento, anche se, come me, non userete mai Python in vita vostra (a meno che non vi paghino bene, intendo...) e non sarete completamente d'accordo con Van Rossum: casomai non lo aveste già capito, personalmente sono per lo strong typing (soprattutto per progetti grossi, team giovani e laddove ci siano molte integrazioni), ma con tante scappatoie per poter lavorare in modo veloce e flessibile, tipiche di un weak o duck typing - leggermente più dinamico rispetto alla posizione espressa da alcuni esponenti di Microsoft, ma non troppo.

Per quanto concerne il RAD: qualcuno potrebbe sostenere che dire 'se volete programmare velocemente, usate dynamic typing' sia una visione errata dello sviluppo veloce, perchè si basa su una ipotesi di partenza che non considera la manutenzione, ma, sostanzialmente, si ferma alla prototipazione e/o primissimi rilasci, senza considerare che, quando cresce la complessità del sistema, è molto facile che si creino errori.
Questa considerazione è vera solo fino al punto in cui si presuppone che chi sta usando il sistema non si accorga del pericolo e non sappia cosa sta facendo. Cosa che può capitare, come già anticipato, se il progetto è grande e composto da molte risorse junior.
Certo che, se si riesce ad impostare un ragionevole modo di lavorare e un controllo appena decente, si possono ottenere tutti i vantaggi della R di RAD e ridurre a quasi nulla i possibili svantaggi.
Non è vero che i costi di controllo sono il prezzo da pagare: quelli fatti bene, con caratteristiche simili a quelli che servono in questo caso, dovrebbero esistere comunque (altrimenti i problemi non tarderanno a farsi vedere, con o senza strong typing).

Ovvero, per dirla con Bruce Eckel (che da anni, oramai, cerca di farci diventare poliglotti informatici), non abbiamo bisogno tanto di una forte tipizzazione, quanto di forti test.
Sorvolando sul fatto che, evidentemente, in Italia la parola test non è facile da tradurre e che, quindi, la frase precedente potrebbe non essere capita da tutti... ;)

La stessa dicotomia non può che porsi anche ad un livello architetturale più alto, come ben evidenziato dalla diatriba tra SOA e REST. Riporterò solo un interessante pezzo tradotto a braccio da un famoso articolo di Steve Vinoski:
Ironicamente, il fatto che SOA prescriva specifici contratti per le interfacce, di fatto insidia il suo obiettivo di separare l'interfaccia dall'implementazione, perchè interfacce specifiche tendono a rivelare più della sottostante implementazione di quanto facciano le interfacce generiche. Inoltre, interfacce specifiche - per definizione - vincolano la loro implementazione perchè modificarle spesso richiede dei cambiamenti nell'interfaccia. [...]
Stranamente, alcuni degli architetti e sviluppatori che conosco che lavorano su grandi sistemi SOA (come quelli di aziende nel campo delle telecomunicazioni e della finanza) si sono inventati per conto proprio i vincoli dell'interfaccia uniforme, senza aver mai sentito parlare del REST. Sfortunatamente l'hanno fatto nel modo più complesso, sviluppando e consegnando dapprima interfacce specifiche per un servizio e poi notando cosa si rompeva quando i loro sistemi crescevano in scala.
Direi che, per ora, mi sembra sufficiente, per farci meditare ancora sull'infinita saggezza popolare nascosta da secoli nella fiaba (della tipizzazione) del (brutto) anatroccolo...

Bye
    Depa

5 commenti:

Ugo Cei ha detto...

Molto interessante, anche se mi ci vorrà una settimana per digerirlo tutto. Vorrei per il momento limitarmi a fare il pignolo e ribattere a:

"http: tutto è stringa (siamo noi che le riportiamo a tipi, una volta che estrapoliamo dalla request, cercando un mapping e binding più o meno esplicito, ma il protocollo non prevede altro)"

Veramente HTTP prevede l'header Content-Type, quindi è decisamente type-oriented. Dire che in HTTP tutto è stringa è come dire che in Java, alla fin fine, sono tutti bit. Sarà anche vero, ma non è molto utile.

Cheers.

Depa ha detto...

Ugo, quanto dici è ovviamente corretto, e c'era un evidente errore nell'espressione il protocollo (sig!) non prevede altro.

Spero fosse chiaro che, in realtà, mi stavo riferendo, alla forma più banale di passaggio di parametri solamente veicolati dall'http, ma, di fatto, tipici di form e link dell'HTML, per cui, alla fine, date, numeri e booleani arrivano sempre come stringa al server dove li riprendiamo per ri-tipizzarli.

Non per nulla è proprio sull'HTML che si dovrebbe agire, per aggiungere tale mancante tipizzazione, con possibili future evoluzioni quali quelle previste da Web Forms 2.0, cui già accennavo indirettamente nel post Quando meno te lo aspetti.
Cosa succederà alle note classi - es: ServletRequest e figliolanza - per gestire questi parametri? Avrà senso introdurne altre, proprio per considerare il fatto che si tratta di parametri tipizzati di un nuovo HTML?

Queste considerazioni mi fanno venire in mente come ambienti quali .NET e JSF introducano già ora una tipizzazione sui componenti di layout, inducendo a gestire nel code behind/backing bean tale diversità, con il rischio di conseguenti ricompilazioni in caso di modifiche alla modalità di presentazione di uno stesso dato(che, invece, se recuperato come parametro generico dalla request, torna ad essere gestibile in modo più generalizzato e flessibile).

Depa ha detto...

oh ke bel caso di omonimia...o si dice onominia...o ominopia...o omnionemia...vabè...hai capito...

Depa ha detto...

Nel mio caso non si tratta certo di omonimia, al più di soprannomonimia o di abbreviazionomonimia... ;)

Interessante blog: li fai tu quei disegni?

Bye
Depa

Depa ha detto...

ti rispondo qui ke almeno lo leggi sicuro...sì, mie modeste creazioni, e se si può dir così lo faccio di mestiere, beh, ci si prova, sn ancora agli inizi...ma sulla carta d'identità pare ke mettano Disegnatore alla voce Occupazione