AMP: HTML to its full potential

Problemi con il caricamento delle pagine web, fastidiosi reflow, scarsa responsività?
Arriva AMP (Accelerated Mobile Pages): un framework HTML open source sviluppato in Google che fornisce una modalità semplice di creazione di pagine web che sono veloci, dal caricamento fluido e che danno priorità all’UX prima di tutto, primariamente per i dispositivi mobile.

Se avete notato, vedrete che quando effettuate una ricerca su Google con un dispositivo mobile come lo smartphone, quando cliccate sul link del risultato che volete visitare, può accadere che non compaia subito la pagina target ma venga invocato il sito ampproject.org in modo tale da rendere i risultato in modo veloce e fluido. Questo dipendentemente dal fatto che il sito sia stato attrezzato per utilizzare questo framework per ottimizzare le pagine con AMP.

AMP definisce una serie di tags estesi (che si chiamano componenti) che vengono gestiti da una libreria JavaScript obbligatoria che ogni pagina AMP deve caricare all’inizio della sezione <head> che hanno la proprietà di caricarsi velocemente nel browser e completamente prima di venire visualizzate, fornendo un’ottima esperienza utente (UX).

Per esempio, uno dei problemi che molti siti web mostrano (soprattutto se non ottimizzati per viewport del tipo smartphone) è il caricamento progressivo delle risorse della pagina web e il passaggio attraverso una fase in cui la pagina si ridisegna in continuazione: viene caricato un blocco di testo, poi un’immagine e viene ricalcolato il blocco di testo per aderire al layout… questo lavorio intermedio, piuttosto fastidioso, è detto HTML reflow e AMP fornisce degli strumenti che consentono di visualizzare la pagina solamente al termine delle determinazioni della geometria da parte del motore grafico del browser e del caricamento di tutte le risorse (font, testo, immagini).

Tecnicamente si tratta di ridefinire un set di pagine web dalla estensione .amp.html che utilizzano i componenti amp anziché i tag html standard (per esempio, l’utilizzo di <amp-img> anziché del tag <img>). Il rendering di questi tag è realizzato con la libreria Javascript che si trova nel CDN di ampproject.org.

Ma la potenza di AMP non si ferma ai siti web: può essere applicata in modo verticale a blog, stories, siti di ecommerce, ads e addirittura email!

Fonti: Search Engine Land, AMP Project, AMP dev

Pillole Python/Linux: pretty printing json files

Esaminando il contenuto di un file json con il comando less, mi veniva tutto su una linea

[{"id":"5d070cce-a504-4375-94c3-403f71eb4212","name":"prod36.mirth.mysite.it:8443","address":"https://prod36.mirth.sanita.padova.it:8443","javaHome":"BUNDLED","heapSize":"512m","icon":"egyptian_pyramid.png","showJavaConsole":false,"sslProtocolsCustom":false,"sslProtocols":"","sslCipherSuitesCustom":false,"sslCipherSuites":"","useLegacyDHSettings":false},{"id":"7431b71c-7a2d-4be6-a7f1-6f1129e3a8ce","name":"https://test36.mirth.sanita.padova.it:8443","address":"https://test36.mirth.mysite.it:8443","javaHome":"BUNDLED","heapSize":"512m","icon":"pepper.png","showJavaConsole":false,"sslProtocolsCustom":false,"sslProtocols":"","sslCipherSuitesCustom":false,"sslCipherSuites":"","useLegacyDHSettings":false}]

Piuttosto scomodo. Avrei potuto aprirlo con un editor con filtri di interpretazione, ma ho trovato questo metodo comodissimo:

$ less connections.json | python -m json.tool 

Il risultato è molto più confortevole

[
    {
        "address": "https://prod36.mirth.mysite.it:8443",
        "heapSize": "512m",
        "icon": "egyptian_pyramid.png",
        "id": "5d070cce-a504-4375-94c3-403f71eb4212",
        "javaHome": "BUNDLED",
        "name": "prod36.mirth.sanita.padova.it:8443",
        "showJavaConsole": false,
        "sslCipherSuites": "",
        "sslCipherSuitesCustom": false,
        "sslProtocols": "",
        "sslProtocolsCustom": false,
        "useLegacyDHSettings": false
    },
    {
        "address": "https://test36.mirth.mysite.it:8443",
        "heapSize": "512m",
        "icon": "pepper.png",
        "id": "7431b71c-7a2d-4be6-a7f1-6f1129e3a8ce",
        "javaHome": "BUNDLED",
        "name": "https://test36.mirth.sanita.padova.it:8443",
        "showJavaConsole": false,
        "sslCipherSuites": "",
        "sslCipherSuitesCustom": false,
        "sslProtocols": "",
        "sslProtocolsCustom": false,
        "useLegacyDHSettings": false
    }
]

Qual è la differenza tra un programma e uno script?

Scrivendo gli ultimi articoli ho pensato di chiarire la differenza tra linguaggi di scripting e di programmazione. Il criterio di differenza più netto che ho trovato in rete è quello di suddividere in queste due categorie i linguaggi di programmazione allo stesso modo in cui si suddividono i linguaggi tra compilati ed interpretati.

Ma ho trovato parecchie inesattezze su quest’ultima classificazione, per una buona parte dei linguaggi attualmente disponibili.

La verità è che la differenza non è più così netta per tutta una serie di linguaggi molto popolari.

PHP non è un linguaggio interpretato come scritto da più parti, ma ha il suo bel bytecode generato a runtime da un compilatore che fa parte del core Zend. In pratica il compilatore Zend compila il sorgente in bytecode che viene poi interpretato dalla macchina virtuale Zend. Quindi non è veramente del tutto un linguaggio interpretato né del tutto compilato come si può dire del C.

Una risorsa che riporta un chiaro diagramma sul funzionamento di PHP è disponibile qui.

Anche Java viene trasformato in bytecode ed eseguito da una macchina virtuale (Oracle JVM, IcedTea etc).

La stessa cosa si può dire per Python in quanto anche qui ho una macchina virtuale che esegue bytecode (i file .pyc che vengono creati a runtime).

Quindi il codice che scriviamo non viene tradotto ed eseguito instantaneamente come succedeva per il BASIC, bensì viene compilato in bytecode e il bytecode viene interpretato.

C’è una importante differenza tra interpretazine dei bytecode e i programmi compilati puri come il C: il binding delle variabili, ossia il calcolo dell’indirizzo delle variabili, non è eseguito alla compilazione (anzi in realtà al momento dell’esecuzione del linker) ma all’esecuzione della virtual machine, quindi runtime. Nel C invece viene calcolata la posizione di memoria delle variabili in modo relativo nel codice hello.o e poi il linker le rende assolute nel contesto esecutivo del sistema operativo.

Javascript è un linguaggio di scripting poiché viene eseguito dal browser che diventa una sorta di “sistema operativo”. Ma anche questa nozione è superata. Il browser come Chrome in realtà opera una traduzione in bytecode, tramite il motore (engine, un altro modo di chiamare l’interprete) V8, degli script collegati alla pagina web. V8 è l’evoluzione dell’interprete JavaScript dei primi browser in un compilatore bytecode allo stesso modo di Java, PHP e Python. V8 è usato anche da node.js.

Un altro criterio distintivo potrebbe essere l’interazione con l’utente. Generalmente gli script consistono in una serie di comandi automatizzati che implementano la logica di un programma inteso come macchina di Von Neumann (inizializzazione di variabili, decisioni, cicli) e che vengono eseguiti in modalità batch, una modalità in cui il programma parte (spesso da solo, su innesco di uno scheduler come cron), fa una serie di operazioni e il risultato può essere verificato da un operatore a distanza di tempo e anche senza interazione alcuna con il software (ad esempio andando a vedere i log o i risultati in un database). In questa categoria si inseriscono gli script bash, potentissimi programmi Unix/Linux.

Riferimenti web

Pillole Git: come applicare una patch

Ho due applicazioni residenti in due cartelle diverse che condividono uno stesso file (ad esempio il file contiene una stessa istruzione sql che viene emendata)

  • Estraggo la patch applicata al primo repository
$ git diff [ID COMMIT1] [ID COMMIT2] > diff.patch
  • Sposto il file nella cartella del secondo repository
$ mv diff.patch [altraCartella]
  • Applico la patch al secondo repository Git
$ git apply diff.patch

Se la patch è applicabile Git lo farà. Se i file sono diversi non lo farà. Infatti il contenuto della patch è

marcob@jsbach[15:29:18]:altraCartella$ cat diff.patch 
diff --git a/inviti/inv610.db.inc.php b/inviti/inv610.db.inc.php
index 9d9b678..797f68d 100644
--- a/inviti/inv610.db.inc.php
+++ b/inviti/inv610.db.inc.php
@@ -272,7 +272,7 @@ where
 	and d.id_tipo = f.id
-	and f.cod in (1, 2, 4, 5)
+	and f.cod in (1, 2, 3, 4, 5)

Git controlla prima che l’hash del secondo file (di arrivo) sia uguale al file da emendare: se sono diversi, vuol dire che non posso applicare la patch e Git terminerà.

Grails: lavorare con i layouts

Lavorando coi layouts un web designer può efficientemente creare una struttura di inclusione che fattorizza in modo ottimale le parti di html. Cioè può raccogliere a fattore comune tutte le parti di layout che sono comuni a tutte le funzionalità legate al singolo controller e personalizzare le parti dedicate al singolo metodo. Usiamo la prassi “Convieni piuttosto che Configurare” (convention over configuration). Questo frammento di progetto è l’esposizione casuale di una citazione (quote) tratta da una tabella, assieme al suo autore.

  • il layout si chiamerà come il controller: se abbiamo definito un controller QuoteController troveremo un template nei layouts con lo stesso nome quote (utilizzando il programma create-controller Grails creerà un controller e un layout per default):
grails-app/views/layouts/quote.gsp
  • All’interno della view dedicata alla citazione poi dovremmo convenire di chiamare il blocco div che vogliamo personalizzare con il nome del layout:
grails-app/views/quote/random.gsp

in questo modo

<div id="quote">
    <q>${content}</q>

    <p>${author}</p>
</div>
  • A sua volta il nome della view è il nome del metodo del controller che viene invocato dalla url:
http://localhost:8080/qotd/quote/random

Memorizziamo che

  • controller -> layout e
  • metodo -> view e,
  • all’interno della view, div -> controller

Groovy on Grails

Questo framework si ispira anche onomatopeicamente a Ruby on Rails ed è la composizione di un linguaggio di programmazione per JVM (Groovy) su un framework MVC opzionalmente corredato da Spring (per il controllo della sicurezza) e Hibernate (lo strato ORM verso il database) che è Grails.

Il linguaggio di programmazione è Groovy che però è molto simile a Java, avendo poi rispetto questo una serie di “ammorbidimenti” (vedi l’articolo Programmare in Groovy).

Grails è un framework MVC che può essere associato a Spring per il controllo degli accessi e Hibernate come ORM. È un framework Open Source full-stack per applicazioni web basate su JVM. Adotta Apache Groovy come linguaggio di programmazione e il paradigma “meglio convenzione che configurazione” per consentire un’esperienza di programmazione estremamente produttiva e “aerodinamica”.

Ho scritto alcune guide come Creare un progetto Grails da linea di comando oppure con l’utilizzo della IDE Intellj IDEA di JetBrains. Uso la versione Ultimate che, tra le altre belle cose, ha che è possibile avere contemporaneamente anche un ambiente di sviluppo PHP attraverso l’attivazione di un plugin. In effetti JetBrains produce anche PHPStorm e quindi PHPStorm= IDEA + PHP Plugin.

Oltre a questo, anche una introduzione a Groovy come linguaggio di programmazione derivato da Java e una sezione di Q&A.

Groovy on Grails Q&A

Indice

  • Problems copying method. Incompatible JVM?
  • casServerUrlPrefix cannot be null
  • Aggancio al CAS non riuscito
  • ERROR pool.ConnectionPool

Vari errori che mi sono capitati

Problems copying method. Incompatible JVM?

Si manifesta quando si vuole eseguire l’applicazione da riga di comando con

$ grails run-app

Ho trovato che il problema è la versione di Spring, avevo la 1.2.0 e in StackOverflow consigliano la 1.2.4:

$ wget https://repo.spring.io/release/org/springframework/springloaded/1.2.4.RELEASE/springloaded-1.2.4.RELEASE.jar -O springloaded-1.2.1.RELEASE.jar

casServerUrlPrefix cannot be null

Devo proteggere la mia applicazione con accesso di login e mi aggancio per questo ad un server CAS. La configurazione che ho fatto (minimale) è di inserire nel file BuildConfig.groovy, nella sezione plugins la riga

compile ":spring-security-cas:2.0.1"

Eseguendo il build:

$ grails s2-quickstart test1 Utente Ruolo Requestmap

SI verifica un errore (e Tomcat non parte)

Exception starting filter CAS Single Sign Out Filter Message: casServerUrlPrefix cannot be null.

Ora la configurazione dei parametri CAS era stata effetuata regolarmente nel file Config.groovy (tutti questi file si trovano nella cartella grails-app/conf del progetto Grails):

environments {
...
    custom {
        grails.plugin.springsecurity.cas.serverUrlPrefix="https://cas.remotesite.com/cas"
        grails.plugin.springsecurity.cas.active = true
        grails.plugin.springsecurity.cas.loginUri = "/login"
        grails.plugin.springsecurity.cas.serverUrlPrefix = "https://cas.remotesite.come/cas"
        grails.plugin.springsecurity.logout.afterLogoutUrl = "https://splashdown.remotesite.com/logout.php"
    }
...
}

E parimenti è stata fatta la configurazione del core di Spring che ometto.

Per farla breve l’errore era una ulteriore configurazione da aggiungere nel file BuildConfig.groovy: nella sezione dependencies

        compile "org.jasig.cas.client:cas-client-core:3.3.3", {
            excludes 'commons-codec', 'commons-logging', 'junit', 'log4j', 'opensaml', 'servlet-api', 'spring-beans',
                    'spring-context', 'spring-core', 'spring-test', 'xmlsec' }

Riferimenti: https://github.com/grails-plugins/grails-spring-security-cas/issues/9

Aggancio al CAS non riuscito

In questa situazione CAS viene invocato richiama l’host di ritorno passando il token di sessione, ma il client lato applicazione lo ignora e fa riferimento ad un suo db locale, un database H2.

L’url del db è scritto in DataSource.groovy ed è jdbc:h2:prodDb

ERROR pool.ConnectionPool

Mancano i driver che vanno aggiunti al file conf/BuildConfig.groovy:

    dependencies {
        // specify dependencies here under either 'build', 'compile', 'runtime', 'test' or 'provided' scopes e.g.
        runtime 'mysql:mysql-connector-java:5.1.27'
        // runtime 'org.postgresql:postgresql:9.3-1100-jdbc41'
        test "org.grails:grails-datastore-test-support:1.0-grails-2.3"
    }

La riga relativa a mysql di default è commentata: decommentarla. Eventualmente aggiungere il parametro di Oracle se invece si usa Oracle: si devono aggiungere i jar di odbc e ora sotto lib

marcob@jsbach[11:35:58]:betablog$ ll lib/
 totale 3140
 drwxrwxr-x  2 marcob marcob    4096 ago 26 18:07 ./
 drwxrwxr-x 15 marcob marcob    4096 ago 26 18:05 ../
 -rw-rw-r--  1 marcob marcob 1555682 ago  5 16:47 ojdbc14.jar
 -rw-rw-r--  1 marcob marcob 1646178 ago  5 16:47 orai18n.jar

Programmare in Groovy

Groovy è un linguaggio fortemente tipizzato derivato da Java con in più le performance e la flessibilità di un linguaggio di scripting come Python ad esempio. È un derivato del Java con una nuova sintassi tale da renderlo molto familiare ai programmatori Java.

Le caratteristiche di Groovy risolvono una serie di problematiche di produttività ed eleganza con un buon compromesso sulla tipizzazione.

Essenzialmente è un linguaggio “Java light” che rispetto a Java ha alcuni rilassamenti:

  • Si possono definire i tipi delle variabili “in corsa” senza specificarne il tipo che viene dedotto al momento della compilazione (come avviene anche per PHP 7)
    def pi = 3.14
    e pi sarà un Float
  • La tipizzazione non è rigida come con Java, praticamente scompare la differenza tra classe e tipo primitivo:
    int a=1
    equivale a
    Integer a = 1
  • non sono necessari i ; alla fine dell’istruzione
  • overload degli operatori per gli oggetti. Ad esempio si potrà scrivere indifferentemente l’operatore == tra due int o due Integer, o addirittura tra un int e un Integer:
int a=2            // in Java sarebbe un tipo primitivo
print(a)

Integer b=2        // in Java sarebbe una classe
print(a.equals(b)) // stampa true
print(a==b)        // stampa true

Per testare costrutti Groovy si può utilizzare la consolle che si può far partire da IDE selezionando Tools > Groovy console:

e cliccando sulla freccetta bianca in alto a sinistra si compila ed esegue il programma:

Tips on Grails programming

Ci sono alcune pratiche utili che consentono di sviluppare in modo coerente.

Io sono partito da questa esigenza: voglio che ogni modello (o dominio come viene chiamato in Grails) debba possedere uno standard, ad esempio voglio che tutti i modelli siano corredati dai campi ch riportano lo username del creatore dell’oggetto, e i timestamp di creazione e modifica.d

Grails ha il notevole supporto ai template per ogni oggetto del paradigma MVC: dai model, ai controller alle alle view.

Per installare nella propria applicazione i template si ricorre al comando

$ grails install-templates
| Templates installed successfully
$

Questo comando semplicemente copia i template dell’installazione di Grails dentro alla cartella src/templates e si suddivide in quattro cartelle:

  • artifacts che contiene i file Controller.groovy, DomainClass.groovy, Filters.groovy, …
  • scaffolding che contiene le pagine gsp di layout delle views standard

Pillole Linux: il comando wget

wget è un programma Linux che effettua il download di una risorsa web agendo allo stesso modo dei crawlers dei motori di ricerca e la deposita in un file in locale nel computer in cui si è lanciato il comando.

Digitando

$ wget https://www.mysite.org

scarico in locale la pagina indice:

marcob@jsbach:mysite$ ll
 totale 20
 drwxr-xr-x 2 marcob marcob  4096 ago  7 15:01 ./
 drwxr-xr-x 4 marcob marcob  4096 ago  7 15:00 ../
 -rw-r--r-- 1 marcob marcob 11395 ago  7 15:01 index.html

Se c’è una gerarchia di directory posso scaricare anche quella, cioè scaricare tutti i file le directory e le sottodirectory, con l’opzione -r (recursive) e specificando il numero di livelli di gerarchia a cui voglio scendere al massimo; per esempio se voglio fermarmi al terzo:

$ wget -r -l3 https://www.mysite.org

Spesso però i siti vengono impostati in modo da bloccare questo tipo di download massivo, ma wget è molto potente: possiamo inviare nella richiesta anche degli header HTTP personalizzati con l’opzione ‐‐header, ad esempio fingendoci un browser vero:

$ wget -r -l3 --no-parent --header="Accept: text/html" --user-agent="Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:21.0) Gecko/20100101 Firefox/21.0" https://www.mysite.org

Tuttavia il web server può sempre bloccare lo user agent quando il numero di pagine richieste al secondo è troppo elevata. Con queste opzioni ci presentiamo al server come se fossimo un browser Firefox per sistema operativo Mac OS X. Inoltre specificando ‐‐no-parent evitiamo di fare il download anche delle eventuali cartelle soprastanti quella di cui vogliamo fare il download.

Come ultimo esempio, potendo inviare header HTTP a piacere, possiamo inviare l’header di autenticazione per siti protetti con autenticazione. Ovviamente dobbiamo avere un account in quel sito e possiamo evitare di mandare in chiaro la password in http utilizzando l’opzione ‐‐ask-password:

$ wget -r -l10 --no-parent --user=myuser --ask-password --header="Accept: text/html" --user-agent="Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:21.0) Gecko/20100101 Firefox/21.0" http://www.mysite.org

Pillole Oracle: altro esempio con WITH

Un utilizzo un po’ meno banale di quello illustrato nel primo post sulla clausola WITH è quello che alla fine ho utilizzato per riuscire in un task del genere:

Come faccio a produrre un recordset contente le date di una settimana da domenica a sabato dato che sia un giorno qualsiasi della settimana che si vuole estrarre?

Utilizzando la clausola WITH possiamo costruirci una tabella temporanea arr_dates con un’unica colonna arr_date:

Ora questo costrutto ha una sua complessità. Partiamo individuando i blocchi:

  • la clausola WITH definisce un recordset temporaneo arr_dates
  • contente il campo arr_date
  • il recordset è definito come segue: seleziona (riga 2) il sabato successivo (+5) al parametro data (:1)
  • union all
  • seleziono (riga 4) il giorno precedente (-1) dal recordset definito sopra con la condizione che la data deve essere maggiore della data di inizio della settimana della data parametro (:1); questa condizione è soddisfatta da tutti i giorni dall’inizio della settimana di partenza alla domenica successiva.
  • alla fine (riga 9) c’è una semplice selezione sull’oggetto appena costruito

Quindi l’effetto è quello di selezionare 7 “record” centrati attorno al giorno :1. Ad esempio se prendiamo come parametro il 2 luglio 2019 ho

Stesso recordset se come parametro scegliamo il 5 luglio 2019. Se invece scegliamo come “centro” il 10 luglio 2019:

Alla fine possiamo calcolare questi recordset inglobando il tutto in una function ma lo vediamo nel prossimo post.