Corso docker

Introduzione a Docker

Docker (www.docker.com) è una piattaforma open source (realizzata in go) per lo sviluppo, il trasporto e l’esecuzione di applicazioni distribuite – in modo semplice, veloce, scalabile e portabile. Docker permette di istanziare container. Un contenitore Docker è un’unità software standardizzata che impacchetta un servizio software, insieme alle sue configurazioni e dipendenze.

docker-vmUn container non è una macchina virtuale (anche se in qualche modo la ricorda).  Un container non ha un SO, né device driver. Il container espone verso l’esterno un servizio, ha al suo interno tutte le librerie e il codice necessario al funzionamento del servizio stesso.

Per esempio immaginare App1 come un http server e App2 come un Msql Server. Il container1 esporrà verso l’esterno il servizio http e il container2 esporrà verso l’esterno il servizio mysql.

I Container Docker sono leggeri (usano poche risorse e si avviano velocemente), standardizzati, si possono eseguire sui principali sistemi operativi (Linux e su Windows e Mac OS, ma anche sul cloud) e sono sicuri.

La piattaforma Docker consente una separazione tra le applicazioni e l’infrastruttura di esecuzione, in modo da semplificare il rilascio delle applicazioni. Garantisce che il servizio implementato da un contenitore possa essere eseguito sempre nello stesso modo, indipendentemente dal suo ambiente di esecuzione – sia on premise che sul cloud.

Docker Engine

Il nucleo fondamentale della piattaforma Docker è Docker Engine.  Docker Engine è basato su un’architettura client-server.

docker-engine

il client (docker) accetta comandi dall’utente mediante un’interfaccia dalla linea di comando (CLI) e comunica con il demone Docker sull’host. Il client e il demone Docker comunicano mediante un’API REST.

docker-server-manageil server è un host in grado di gestire Container Docker. In particolare sul server è in esecuzione il processo demone Docker (dockerd), il quale, gestisce inoltre un insieme di oggetti Docker (contenitori, immagini e relativa cache , le reti e i volumi). Sul server è in esecuzione il demone di docker che gestisce gli oggetti docker e permette l’interazione con i client locali o remoti  tramite  CLI e REST.

Il registry (pubblico o privato) contiene un insieme di immagini. Il registry pubblico di Docker è Docker Hub. Un’organizzazione potrebbe gestire un proprio registry privato

Containers e immagini

Contenitore e immagine sono due tipi fondamentali di oggetti Docker, sono due concetti correlati ma distinti. Un immagine può essere assimilata all’immagine ISO di una macchina virtuale. Un immagine è statica:

  • Non può essere eseguita direttamente;
  • Non ha un proprio stato;
  • E’ immutabile.

Un conteiner rappresenta un istanza di un immagine. un contenitore è un concetto dinamico, runtime:

  • Può essere eseguito su un host
  • Ogni Conteiner ha un proprio stato che può cambiare durante l’esecuzione (es., il contenuto del file system nel disco)

 

Enviroment preparation

Prima di iniziare con l’installazione, è necessario precisare che Docker utilizza alcune funzionalità del kernel di Linux che, per ovvi motivi, non sono presenti in un sistema Windows. Per ovviare a questo problema si installa una macchina virtuale Linux con all’interno il demone Docker, a gestire i container ed un set di API utilizzabili in un’ottica client/server per inviare comandi.

docker-installation

Questo meccanismo è completamente “trasparente” all’utente, in quanto l’installer di Docker si occuperà di installare tutto il necessario. Ad oggi, esistono due diversi installer, in base alla versione di Windows e al processore che si ha a disposizione.

Se il sistema operativo è Windows 10 nelle versioni Professional, Enterprise o Education e il processore è a 64 bit, l’installer è Docker for Windows. In tutti gli altri casi Docker Toolbox. La differenza principale tra i due installer consiste nell’hypervisor utilizzato: Docker Toolbox utilizza Oracle VirtualBox, mentre Docker for Windows utilizza Microsoft Hyper-V ed è in grado di funzionare come servizio Windows, garantendo quindi una migliore integrazione.docker-windows-home

 

Docker for windows scaricare l’installer e eseguirlo. Nella fase finale dell’installazione, in cui potrebbe esser richiesto di abilitare le funzionalità di Hyper-V: accettiamo e riavviamo la macchina. Se invece si installa Docker Toolbox, tra le varie cose, verrà installato anche Oracle Virtual Box, mediante cui sarà generata la macchina Linux.

Una volta terminata l’istallazione è possibile aprire la console di Powershell ed eseseguire il primo dei comandi docker docker version.

docker-version

L’output è suddiviso tra client e server. Il client è la macchina locale, mentre il server è la macchina virtuale Linux che Docker ha istanziato. Le parti comunicano tra loro grazie allo strato di API.

 

la gestione della Network in Docker

Se si esegue il comando docker network ls è possibile visualizzare le reti messe a disposizione da docker. Anche se è possibile creare network custom, appena istallato docker mette a disposizione 3 reti.

docker-network-1

docker-networkla rete host rappresenta la rete del server host. la rete bridge invece è la rete nell’interno della quale vengono costruiti i containere. Ogni container creato avrà un indirizzo ip appartenente a questa rete. Docker network insopect <network name>permette di avere informazioni sulle reti

docker-network-inspect

Ogni container creato avrà un indirizzo ip appartenente a Subnet: 172.17.0.0/16″,

 

I comendi Docker

Di seguito si riportano la lista dei comandi che il Client Docker può inviare al server.

comandi docker

Tramite la docker cli è possibile gestire diversi ogetti Docker: Immagini, volumi nettwork e container. Si può schematizzare  i comandi della docker cli per container con la seguente immagine:

docker-command

Dall’immagine risulta chiaro per esempio che eseguire il comando docker run equivale a eseguire un docker create docker-run-help(crea un nuovo container) e un docker start (fa partire il container). Quando il container è nello stato running è possibile: stopparlo o restartarlo.

Se si desidera conoscere lo usage di un comando docker basta far seguire il comando dall’opzione –help. Es: docker run –help. L’unico parametro obligatorio del comando docker run è l’mmagine da istanziare nel container che si vuole creare.

 

Docker in pratica

Come si è detto prima, il comando docker run permette di creare e far partire un nuovo container. Immaginiamo di voler istanziare nel container l’immagine hello-world.

docker run hello-word

hello-world è un immagine di esempio messa a disposizione dal docker hub. Creando un container con questa immagine verrà visualizzata a schermo un output che sintetizza cosa avviene tra client e server durante l’esecuzine del comando in esame.

docker hello-world

  1. Il docker client contatta il demone di docker;
  2. il demone scarica l’immagine hello-world dal docker hub;
  3. Il demone crea il nuovo container dall’immagine, esegue l’applicativo presente nell’immagine producendo l’output;
  4. il demone invia l’output al client che lo visualizza nel terminale.

Per visualizzare tutte le immagini scaricate dal docker hub e presenti sul server, si esegue docker images.

docker-images

In questo momento, l’unica immagine presente sul server è helo-world. Questo comando da una serie di informazioni sull’immagine:

  • REPOSITORY: il nome
  • TAG: la versione
  • IMAGE ID: id dell’immagine
  • CREATE: il momento di creazione dell’immagine sul docker hub
  • SIZE: la dimensione dell’immagine

per vedere i container creati, si esegue docker ps -a (se non si usa l’opzione -a vengono visualizzati solo icontainer nello stato running/up ) l’opzione -a visualizza tutti i container aprescindere dallo stato in cui si trovano.

docker-ps-a

Anche questo comando da diverse informazioni su i container presenti sull’ambiente:

  • CONTAINER ID: id del container
  • IMAGE: immagine istanziata nel container
  • COMMAND: comando eseguito nel container
  • CREATED: periodo di creazione
  • STATUS: stato attuale del container
  • NAME: nome del container. Se non viene assegnato nessun nome, Docker assegna un nome di default

Docker permette, mediante l’uso dei container, di far partire due o più versioni diverse della stessa applicazione senza che queste vadano in conflitto. Il container permette di isolare le due applicazioni. Ogni container rappresenta per docker un processo isolato.

Si immagini di voler far partire un container con un  server apache (versione 2).

docker run -d -–name apache-2 httpd:docker-run-httpd-2

 

 

L’opzione -d permette di eseguire il container in background. –name assega un nome al container. http:2 rappresenta l’immagine da istanziare seguita dalla versione (tag). httpd è l’immagine dell’apache server presente sul docker hub.

Docker permette, mediante l’uso dei container, di far partire due o più versioni diverse della stessa applicazione senza che queste vadano in conflitto. Il container isola le due applicazioni. Ogni container rappresenta per docker un processo a sestante.

Se si volesse far partire anche un server apache versione 2.4

docker run -d -–name apache-2-4 httpd:2.4

docker-run-httpd-2-4

docker-images

Eseguendo i due comandi, si nota subito che l’operazione di pulling è molto più breve nel secondo comando. Durante il pulling in nostro server docker scarica in locale le immagini di cui ha bisogno.

Le immagini docker sono strutturate a layer, questo consente una gestone più agevole della memoria.

Tenendo presente quanto detto, quando si esegue il primo comando, nessuna versione dell’immagine httpd è presente sul server, quindi vanno scaricati tutti i layer dell’immagine httpd:2.

Quando invece si esegue il secondo comando, sul server è già presente una versione dell’immagine httpd. Il server scaricherà solo i layer che mancano tra la versione 2 e 2.4. Anche il container una volta creato ha un layer (accessibile sia in lettura che in scrittuta). I layer dell’mmagine sono statici, le modifiche fatte sul layer del container (istallazione di nuovi pacchetti) non modificano l’immagine, ma seguono il ciclo di vita del container. Se si installa vim sul container httpd-2, il pacchetto verrà istallato sul layer del container e vim sarà utilizzabbie finchè il container rimmarrà in vita.

Se si volesse avere vim dentro l’immagine http:2  sarebbe necessario creare una nuova immagine: Partendo dall’immagine http:2 aggiungere un layer e istallare vim.

Dopo questa breve digressione che approfondiremo più avanti, torniamo alle immagini e ai container appena creati. Ora sul server ci sono le due nuove immaggini scaricate e anche nella lista dei container sono presenti i due nuovi container creati.

docker-ps-a-images

Dopo aver creato il container è possibile eseguire su di esso una serie di comandi. I container possono essere identificati o dal nome o dal container id.

per eseguire un comando all’interno di un container si usa <code>docker exec</code>Per esempio per attivare il terminale bash all’interno del container apache-2, si può scrivere <code>docker exec -it apache-2 bash</code>  Per stoppare, startare o restartare il container apache-2

docker stop apache-2

docker start apache-2

docker restart apache-2

Per rimuovere un container si usa docker rm. Prima di rimuovere un container va soppato (Andrebbe fatto un docker stop de container). L’opzione -f stoppa il container prima di rimuoverlo.

docker rm apache-2
docker rm -f apache-2-4

Interazione tra container e Host

Fino ad ora, si è visto come sia possibile esequire diversi comandi su i container. Sarebbe interessante capire come poter interaggire con i servizi messi a disposizione dal container dall’ esteno. Per Interaggire dall’esteno con i servizi messi a sisposizione dai container si usa il port-binding.

Dal comando docker ps si può notare che ogni container espone una porta verso l’esterno. In particolare apache la porta 80.

docker-ps-a-images

binding port Il binding tra le porte consiste nell’associare la porta del container (es 80) ad una porta del sistema host.

per applicare il port binding basta aggiungere al comando docker run ,già visto in precedenza, l’opzione -p. In particolare -p <host port>:<container port>.

docker run -d –name apache-2 -p 8080:80 httpd:2

docker run -d –name apache-2-4 -p 8081:80 httpd:2.4

Dopo aver creato i nuovi container, se si visualizza la lista dei container si può notare nella colonna PORTS che è stato settato il binding

docker-run-port

apache

codice html interno al container

 

Un ulteriore prova è che se ora sul andiamo su http://localost:8080 o http://localost:8081 accediamo ai due servizi apache.

 

La persistena dei dati in un container

 

I dati all’interno del container permangono fino a quando il container esiste. Se per esempio si crea un db all’nterno di un container mysql i dati verranno conservati nel db fino a quando il container non verrà distrutto. Un altro esempio potrebbe essere quello dello sviluppo di un’applicazione: il codice di sviluppo sarà presente nella macchina finche questa non verrà distrutta. Sinteticamente si può quindi dire che di per se un container non garantisce la persistenza dei dati. Per ovviare a questo problema si usano i volumi.

L’utilizzo dei volumi si basa sul concetto di mount di un filesystem. In pratica monto un foder esterno al container (del host o di un altro server) all’interno del conteiner stesso. per applicare un volume basta aggiungere al comando docker run ,già visto in precedenza, l’opzione -v. In particolare -v <host path>:<container path>.

html volume

codice html modificato

Tornanto all’esempio precedente il db in un volume esterno al container, così come il codice di sviluppo, anche qualora il container venisse distrutto i dati rimarrebbero nel dileSystem esterno. Si Immagini per esempio di voler sviluppare sul server Apache (sostituire l’html di default di apache con quello contenuto nel folder di sviluppo “d:/docker/php”).

docker run -d –name apache-2 -v d:/docker/php:/usr/local/apache2/htdocs -p 8080:80 httpd:2

Una volta eseguito il comando Sarà possibile:

  • sviluppare senza accedere al container, lavorando direttamente nel folder d:/docker/php (aggiunge eliminare o modificare file).
  • Ovviamente se si accede alla macchina e si creano e modificano file all’interno del path /usr/local/apache2/htdocs, le modifiche verranno salvate all’interno del volume d:/docker/php

Come prima sarà possibile accedere a http://localost:8080 e visualizzare il risultato delle modifiche apportate.

Creare Immagini Docker

Fino ad ora sono state usate solo immagini base, scaricate direttamente da Docker hub. Si è anche visto come le modifiche fatte su un container (come installazone di pacchetti) seguano il ciclo di vita del container.

Per la costruzione di un’immagine personalizzata, Docker utilizza un approccio di tipo infrastructure-as-code – sulla base di un file di testo speciale di nome Dockerfile.
Il Dockerfile contiene tutti i comandi da eseguire per costruire un’immagine personalizzata. Il comando docker build -t image-name context consente di costruire automaticamente un’immagine (di nome image-name) a partire da un contesto context. Il contesto può essere una cartella locale e deve contenere il Dockerfile, insieme a ogni altro file di interesse (ad es., file binari, script e template). Un Dockerfile è composto da una sequenza di istruzioni.

Per vedere i comandi fondamentali del dockerfile analizziamo il seguente esempio:

angular-dockerfile

  • l’istruzione FROM specifica l’immagine di base da cui costruire l’immagine personalizzata (e la sua versione)
  • L’istruzione RUN specifica un comando che va eseguito durante la costruzione di un’immagine.
  • l’istruzione EXPOSE [port] specifica che il contenitore ascolta a runtime alla porta port
  • l’istruzione ENV [key value] imposta una variabile d’ambiente nel contenitore
  • l’istruzione WORKDIR [path] imposta la directory di lavoro
  • l’istruzione COPY [src dest] copia un insieme di file o cartelle dalla sorgente src (che deve essere relativa al contesto della costruzione dell’immagine) alla destinazione dest (nel contenitore)
  • l’istruzione CMD [command] è un’istruzione che  deve essere eseguito dai contenitori che verranno creati da questa immagine

un Dockerfile deve iniziare con un’istruzione FROM e, di solito, termina con una singola istruzione CMD.

un Dockerfile può contenere più istruzioni RUN che vengono eseguite in sequenza. La differenza principale tra l’istruzione CMD e le istruzioni RUN è il momento della loro cmesecuzione. Le istruzioni specificate da RUN vengono eseguite durante la costruzione di un’immagine, l’istruzione specificata da CMD verrà eseguita dai contenitori creati a partire dall’immagine.

Di solito è preferibile avere in un Dockerfile una sola istruzione RUN (o comunque poche) che specificano una sequenza di comandi separati  da ‘&&’. Questo prerchè ogni istruzione RUN aggiunge un layer all’immagine che si sta creando.I Layer vengono conservati i chache. Se due immagini eseguono la stessa seguena di istruzioni il server non rieseguirà il comando, ma usera il layer in chache

Una volta eseguito il comando docker build -t angular:1.2 verrà creata la nuova immagine, sarà visualizzata nella lista delle immagini (docker images) e potrà essere deployata in un container. Per istanziarla in un container basta usare docker run.

Docker Compose

Docker è utilizzato non per costruire ambienti distribuiti, anche di grandi dimenzioni. E’ facile capire come utilizzare  CLI di docker per costruire, modificare un ambiente di sviluppo o produzioone formato da 10 container sia quanto meno scomodo.

Immaginiamo per esempio di voler creare un ambirnte di sviluppo formato da 4 container (macchine):

  • Un Server Http con php;
  • Un db mysql
  • Un phpadmin (per gestire il db)
  • Una container con Angular installato.

In particolare, le chiamate al server, vengono effettuate da angular.  L’http server si connette al db per ricavare le informazioni richieste. Il php admin serve solo per acedere e gestire direttamente il db.

Si potrebbe creare i 4 container separatamente, ma l’operazione sarebbe certamente lunga. Per ovviare a questo problema ci viene in aiuto docker-compose. docker-copmpose è un tool messo a disposizione da docker, che appoggiandosi su un file yml, permette di creare tutte le macchine necessarie per il nostro ambiente di sviluppo con in solo comando:  docker-compose -f <nome_file> up -d

L’opzione -d serve per manare il comando il background. L’opzione -f permete di dichiarare il nome del file yml in cui sono definiti i container che fanno parte dell’ambiente da creare. Se l’opzione -f non viene definita il comando docker-compose cercherà nel folder il file chiamato docker-compose.yml.

Quindi tutti i container vanno definiti all’interno del docker-compose.yml file. All’interno di questo file i container vanno definiti come servizi. Per utilizzare docler-compose sarà necessario semplicemente fare una trascrizione (conversione) delle opzioni del comando docker run in formato yml.

Per semplicità riporto il file yml utilizzato per costruire l’ambiente sopra indicato e poi lo analizzeremo riga per riga. (Il file si chiama php-apache-mysql.yml).

docker-compose-yml-1docker-compose-yml-2

La prima istruzione e version che dice a docker-compose quale versione dele api usare per fare il parsing del file. Come già detto ogni container per il docker-compose è un servizio.

servicers permette di definire la lista dei servizi.
Il servizio db rappresenta il container in cui è presente mysql (il nome del servizio non è il nome del  container).
image rappresenta l’mmagine di partenza scaricata dal docker hub.
container_name è il nome che sarà assegnato al container.
command esegue permette di eseguire un comando una volta che il conteiner è stato creato.
volumes equivale a l’opzione -v di docker run. Permette di devinire uno o più volumi. I volumi vanno definiti uno sotto l’altro e ogni volume deve essere preceduto dal degno ‘-‘ e racchiusi tra virgolette.
environment permette di definire una serie di variabili di ambiente. Ovviamente ogni immagine del docker hub a le sue variabili dambiente. Nel cado in esame l’immagine mysql permette di definire in fase di creazione del container utenti e relative password
Se ora si analizza il servizio phpadmin che rappresenta il container con il phpadmin istallato, si possono notare oltre le precedenti anche altre istruzioni.
depends_on permette di devinire uno o più dipendenze. docker compose sa che prima di creare il container in esame deve creare i container dai quali dipende Le dipendenze vanno definite una sotto l’altro e ogni dipendenza deve essere preceduta dal degno ‘- ‘ seguito dal nome del sevizio. Nel caso in esame, si può creare il phpadmin solo dopo aver creato il container con il mysql. Nella sezione enviroment è definito l’host a cui collegarsi (il sevizio db)
ports equivale a l’opzione -p di docker run. Permette di devinire uno o più port binding. I port binding vanno definiti uno sotto l’altro e ogni volume deve essere preceduto dal degno ‘-‘ e racchiusi tra virgolette.
Se si analizza il servizio web o angula si può notare l’istruzione build che equivale al comando docker build per la crazione di immagini castomizzate. context rappresenta il folder dove è conservato il dockerfile, mentre dockerfile rappresenta il nome del docker file. Nel servizio angular è stato utilizzato un nome non di default.
Si riportano di seguito i docker file del servizio web e angular:

http-dockerfileangular-dockerfile

docker-custom-nettworkUna volta definita la struttura dell’enviroment si esegue il comando
docker-compose -f php-apache-mysql.yml up -d.
Come si può notare docker-compose oltre a creare i singoli container crea anche una network che rachiude l’ambiente definito e permette ai container di comunicare tra loro utilizzando questa rete.
docker-compose-up
Una volta creati i container è possibile vedere lo stato dei singoli containe con il comando
docker-compose -f php-apache-mysql.yml ps
(equivale al comando docker ps ma filtra sulla rete creata dal docker-compose). Visualizza solo le macchine definite nello yml.
docker-compose-ps

E’ possibile anche distrugere l’ambiente

docker-compose -f php-apache-mysql.yml down

il comando distrugge anche la network

 

Nota
Sul container web, per permettere la connessione con il db nella stringa di connessione al posto dell’hostname va indicato il npme del servizio del database: ‘db’.

db_conn

Biografia

Lo sviluppo di Apps in Logica Informatica

Pionieri?

Forse non tutti sanno che Logica Informatica è stata una delle prime società informatiche italiane ad interessarsi allo sviluppo di applicazioni per smartphone. Già nel 2006, assorbendo la società IS&O, acquisiva il progetto PocketLine, che prevedeva una modalità di comunicazione avanzata tra sistemi centrali “tradizionali” e smartphone dotati di un sistema operativo appena accettabile. A quel tempo il Symbian della Nokia e il Blackberry erano più o meno gli unici sistemi su cui si poteva pensare di sviluppare un’applicazione “utile”. PocketLine era però in grado di usare i sistemi primitivi di messaggistica (SMS, MMS) per rendere possibile ad un’azienda la condivisione di informazioni tra i sistemi centrali e dispositivi remoti, in modo generalizzato ed estensibile.

PocketLine rimase a livello di prototipo e non divenne mai un prodotto commerciale; in effetti fu una fortuna non aver investito ulteriori energie nel progetto, visto che già nel 2007 fu presentato al mondo il primo iPhone e  l’anno dopo divenne disponibile l’Apple Developer Program per iOs che avviò l’era dello sviluppo di App.  Ci si rese conto subito che paragonare una tecnologia pensata per il più avanzato dei Nokia con il primo iPhone era come confrontare un’Ape Piaggio con una Bugatti. L’iPhone avrebbe portato rapidamente all’estinzione dei dinosauri.

Saltiamo sul treno

Ovviamente non siamo rimasti a guardare. Le nostre prime sperimentazione mostravano che l’iPhone aveva capacità quasi da fantascienza: era  possibile realizzare praticamente qualsiasi cosa (figuriamoci adesso). Nei primi mesi di vita dell’Apple Store erano state pubblicate migliaia di App, molte delle quali potremmo definire “inguardabili”; c’era comunque l’impressione che le possibilità creative fossero illimitate. Inoltre, solo in minuscola percentuale si trattava di App provenienti da sviluppatori italiani e in proporzioni ancora più infinitesimali da Società italiane.

Logica Informatica, per rispettare la sua natura (e perché era più facile) decise di cimentarsi nella creazioni di applicazioni “utili”, in particolare di applicazioni che potremmo definire “di consultazione”. Nel Dicembre 2008 pubblicò la prima: Ipse Dixit, dizionario di citazioni, in quattro lingue, seguita nei mesi successivi dai Codici (Civile, Penale ecc.), da FarmaciaPlus (prontuario dei farmaci), Comuni d’Italia e via dicendo. A tutt’oggi abbiamo realizzato più di 30 App, sia per il mercato “consumer” diretto (cioè vendendole come Logica Informatica), sia per conto terzi (ad es, Maggioli Editore, Guardia di Finanza, ecc.), sia per utilizzo interno di  nostri clienti. Per alcune di queste App ci sarebbe molto da raccontare, ma non lo farò questa volta. Parlerò invece della evoluzione “tecnologica” che ha subìto questa area di sviluppo in Logica Informatica.

Android, Windows e gli altri

Tanto per cominciare, dopo l’iPhone, il quadro si complica: nel 2009 compaiono i primi telefoni dotati di sistema Android, e si vede qualche miglioramento degli smartphone basati su Windows; si affacciano sul mercato anche altri possibili sistemi operativi (Tizen, Firefox,…): a tutt’oggi risultano però semplici esperimenti non riusciti.

Logica Informatica decide di tentare, senza fretta, il “porting” di FarmaciaPlus, la sua App più importante, su Android e Windows. L’impresa riuscirà con fatica, su Android, solo nel 2011, mentre le limitazioni intrinseche di Windows la renderanno impossibile fino all’uscita di Windows Phone 8.1 (Windows CE non poteva gestire un database più grande di pochi megabytes). Per quanto riguarda Windows, l’attenzione dedicatagli si rivela tempo perso, visto che nel 2016 i dati di mercato cominciano ad indicare l’inarrestabile declino della quota di mercato già minima di Windows Phone; il porting di Farmacia Plus su Windows Phone non verrà quindi mai completato. Riposi in pace.

Sviluppo cross-platform

Fino al 2012, lo sviluppo delle App di Logica Informatica era avvenuto con gli strumenti nativi di ciascuna piattaforma, cioè XCode / Objective C per iPhone, Android Sdk / Java per la piattaforma Android e Visual Studio / C# per Windows Phone. Si tratta di strumenti completamente diversi uno dall’altro, come del resto i sottostanti sistemi operativi, e il costo dello sviluppo di un’applicazione complessa per tutte e tre le piattaforme risulta tanto elevato da costituire un problema. In particolare, Logica deve risolvere questo problema nel momento in cui viene ingaggiata da Clienti per la realizzazione di App che devono presentarsi identiche su iOs e Android; la competizione con gli altri possibili concorrenti costringe a trovare e adottare soluzioni tecniche che consentano il “write once, deploy many”, cioè scrivere un solo codice sorgente e poterlo poi “compilare” per le diverse piattaforme.

Il problema si presenta in effetti fin dal 2010, ma diviene essenziale proporre una soluzione solo nel 2012, per la realizzazione di un’App per le ricevitorie Sisal. A quel punto, si esplorano le varie tecnologie disponibili e si sceglie la nostra prima piattaforma per lo sviluppo cross-platform su dispositivi mobili: Titanium Appcelerator. Comincia quindi nel 2012 una strada che porterà ad altri cambi di piattaforma e che sicuramente non è ancora conclusa: ecco qualche dettaglio di questa storia.

Titanium

Titanium Appcelerator (oggi semplicemente Appcelerator) è uno strumento che permette di usare il linguaggio Javascript per realizzare applicazioni “sostanzialmente” native: in effetti, con un’architettura piuttosto ingegnosa, Appcelerator presenta gli oggetti nativi della piattaforma (cioè tutte le componenti visuali e non visuali disponibili su iOs e Android) attraverso dei “wrappers” javascript. Quindi si programma in Javascript, ma in effetti ogni view, widget, file, database, connessione ecc. è realizzata dall’oggetto “nativo” sottostante.

Il risultato è che non solo l’aspetto visuale di un’App realizzata con Appcelerator è uguale a quello di una App nativa, ma anche le prestazioni dell’App sono molto simili, anche se leggermente inferiori, a causa dell’ overhead che il passaggio attraverso Javascript produce rispetto ad una soluzione realmente nativa. Inoltre le App sviluppate con Titanium sono considerevolmente più voluminose del loro equivalente nativo, a causa dei componenti che sono presenti necessariamente in ciascuna di esse, in particolare un interprete Javascript e tutte le interfacce di tra oggetti Javascript e oggetti nativi.

L’esperienza Titanium dura 2-3 anni e interessa lo sviluppo di varie App per terze parti (in particolare, iGdF); progressivamente, la Logica Informatica si orienta però verso un abbandono della piattaforma, sia perché non supporta Windows (problema che si riteneva ancora rilevante fino a un anno fa) sia perché il sistema di licensing del prodotto e il ritmo degli aggiornamenti di release non convincono e creano qualche problema. Inoltre, emergono anche problemi squisitamente tecnici nello sviluppo: pur raggiungendo il risultato di mantenere un solo codice sorgente per tutte le piattaforme,  ottenere i risultati visuali e funzionali desiderati risulta piuttosto faticoso, proprio a causa delle modalità sofisticate con cui la piattaforma Titanium nasconde gli oggetti nativi dietro interfacce Javascript.

Sencha Touch

Intorno al 2014, si decide di cambiare approccio e di orientarsi verso lo sviluppo di App di tipo HTML 5 /JS / CSS 3: si tratta cioè di sviluppare l’App come fosse un sito Web (in effetti come una “single-page application“, usando HTML e Javascript) per poi compilarla in modo che venga eseguita all’interno di una “web view” nativa della piattaforma. Il “compilatore” è fornito dal prodotto open-source Cordova della Apache Foundation, che è utilizzato universalmente da tutte le piattaforme di sviluppo di questo tipo.

Si studia un po’ la situazione del mercato e, tra le molte scelte disponibili, si opta per Sencha Touch: il motivo è che Logica Informatica già utilizza dal 2011  Sencha ExtJs per la realizzazione dei suoi prodotti Web-based (in particolare DCSys e Lossis) e Sencha Touch è una versione dello stesso prodotto, adattata alle necessità dei dispositivi mobili. Lo sviluppo con Sencha Touch richiede l’utilizzo di Sencha Architect, prodotto che consente di comporre in maniera visuale il layout delle pagine e di manipolare componenti e proprietà in modo guidato.

Con Sencha Touch si realizzano alcune applicazioni, tra cui iMinerva, per la Scuola Superiore di Polizia Tributaria, e l’ultima versione di iGdf. Nonostante gli aspetti positivi della scelta, con il tempo si comincia a considerarla non sostenibile, più o meno per gli stessi motivi di Titanium: problemi strettamente tecnici (la piattaforma è così sofisticata che ottenere i risultati desiderati su tutti i modelli di smartphone e tablet risulta piuttosto complicato) e ragioni strategiche: il sistema di licensing e il frequente passaggio di release del prodotto rendono rapidamente obsoleto quanto realizzato; ad ogni evoluzione richiesta dai Clienti si deve affrontare il costo della migrazione delle App all’ultima versione della piattaforma.

L’obiettivo strategico rimane quello di usare un approccio basato su HTML, ma si comincia a ragionare su una forma di downgrade della piattaforma, cioè il ritorno ad un modello di sviluppo che aggiunga ai componenti fondamentali la quantità minima possibile di sovrastrutture. Questo ha anche una precisa corrispondenza nella qualità del codice HTML e Javascript utilizzato: quando si sviluppa con una piattaforma come Sencha Touch, la struttura HTML costruita dalla piattaforma è talmente complicata che risulta difficile controllarne i comportamenti (ad es. affinare dimensioni e posizioni per adattarsi a diversi formati dello schermo).

Xamarin

Mentre si comincia a sperimentare la prossima evoluzione della soluzione HTML, il cliente Poste Italiane mette in condizioni Logica Informatica di sperimentare Xamarin, piattaforma di proprietà della Microsoft, per realizzare il prototipo di una nuova App di uso interno.

Xamarin si basa sullo sviluppo con C# (in Visual Studio) per creare applicazioni cross-platform  native: il risultato cioè viene convertito effettivamente in codice compilato per Windows Phone, Android, iOs. In questo caso, il fatto che la piattaforma provenga da Microsoft, società che sta chiaramente fallendo il suo tentativo di penetrazione nel mercato degli smartphone, solleva qualche dubbio sull’opportunità della scelta fatta dal Cliente, ma comunque consente di esaminare anche questa possibile strada.

L’impressione conclusiva ricavata dall’esperienza su Xamarin è che si tratti di un sistema ancora immaturo, risultante da un collage di componenti non ancora perfettamente integrati, che presenta gli stessi problemi di ogni piattaforma “proprietaria” provata fino ad oggi: non è cioè facile riuscire a costringere lo strumento a produrre i risultati voluti, su ogni tipo di dispositivo.

L’ultimo passo?

Nel corso del 2015, Logica Informatica comincia a sperimentare la soluzione identificata, quella cioè basata su un utilizzo “a basso livello” di HTML, Javascript e CSS, associato ad Apache Cordova per la compilazione dei pacchetti finali. Il risultato finale della sperimentazione è applicato a FarmaCross (pubblicata su Apple Store nel febbraio 2016), versione riveduta e corretta di FarmaciaPlus, della quale parlerò in un altro articolo.

La scelta del metodo di sviluppo si basa su alcuni principi, ma lascia una notevole libertà nei particolari:

  • clean html: l’HTML che costituisce le varie pagine dell’App deve essere privo per quanto possibile di sovrastrutture generate da strumenti di varia natura (in FarmaCross, l’HTML è stato costruito a mano).
  • si usano jQuery e componenti aggiuntivi basati su jQuery (ne esistono in numero illimitato: jQueryUI, jEasyUI, jQuery Mobile, ecc.)
  • possono essere usati componenti di ausilio per il layout (ad es. bootstrap)

La scelta effettuata ha consentito di ottenere alcuni risultati eccezionalmente utili:

  1. lo sviluppo avviene utilizzando il browser come sistema di debug (in particolare, il debugger Chrome in modalità device)
  2. non è necessario acquisire altri skill al di fuori di quelli utili alla realizzazione di una moderna applicazione Web
  3. l’App può essere costruita per essere aggiornabile “on the fly”, cioè può ricevere aggiornamenti e correzioni senza bisogno di essere ripubblicata (da server si possono acquisire porzioni di HTML e scripts che vanno automaticamente a sostituire le parti corrispondenti del pacchetto)

In sostanza, questo tipo di metodologia di sviluppo rigetta gran parte delle nuove strumentazioni nate specificatamente per lo sviluppo cross-platform, ma utilizza fortemente tutte le innovazioni nate per il web 2.0, a partire da HTML5 e CSS3. Componente fondamentale rimane però Apache Cordova, il vero asso nella manica dello sviluppatore.

L’esperienza con FarmaCross ha consentito di trarre alcune importanti conclusioni:

  • è il sistema di sviluppo più semplice e maneggevole tra quelli utilizzati finora
  • la quantità di codice comune a tutte le piattaforme è praticamente il 100%
  • le App sono più lente delle corrispondenti App native

Quest’ultimo punto è ovviamente importante: intendiamoci,  non parliamo di giochi interattivi, né di realtà virtuale, né di applicazioni stile Whatsapp. Nel nostro caso si tratta di applicazioni  principalmente di consultazione, dotate di un database locale, di modalità di colloquio con un server e di qualche funzione di notifica; questo restringe il numero di possibili problemi di prestazioni, ma si è dovuto comunque tenerne conto nel progettare la user experience. 

Il caso più tipico è la presentazione di liste a scorrimento: in un’applicazione iPhone nativa (come ad es. la nostra Comuni d’Italia), una lista può tranquillamente contenere migliaia di righe senza che l’utente percepisca il minimo rallentamento. Una lista di migliaia di righe realizzata con HTML su uno smartphone è semplicemente una cosa da evitare, a causa del tempo necessario al browser per effettuare il rendering della pagina.

Il futuro

Mentre Logica Informatica si ingegna, il settore delle App continua ad essere in piena effervescenza, anche se le statistiche indicano che solo una minima parte delle App realizzate (in tutto il mondo più di 2 milioni) producano introiti sufficienti a mantenerle. In quest’ottica, diventa essenziale avere strumenti migliori per ridurre tempi e costi di sviluppo e ci si aspetta quindi un crescente numero di proposte in tal senso.

Già oggi esistono una serie di possibilità che non abbiamo ancora esplorato a fondo:

  • application makers: si tratta di strumenti o più spesso siti che permettono di costruire un’App in modo guidato, usando modelli e componenti predefiniti. Spesso viene proposto un canone, che prevede anche servizi di monitoraggio. Il numero di offerenti è enorme (vedi ad es. https://www.websitetooltester.com/en/blog/app-makers) ed è oggettivamente difficile capire quanto siano efficaci senza sperimentarli sul serio.
  • piattaforme di sviluppo complete: in particolare Google Firebase e altre (Syncano, Telerik, Intel), propongono ciascuna un proprio ecosistema che si “sposa” o si rigetta in toto.
  • altri framework basati su Javascript: due dei più diffusi sono Ionic e React Native; quest’ultimo presenta qualche aspetto innovativo interessante.

Secondo la mia personale opinione, la strada maestra dovrebbe comunque basarsi sulle stesse tecnologie del Web 2.0, cioè HTML, CSS e Javascript, per motivi pratici e anche di principio: si tratta in fondo solo di due canali lievemente diversi che portano agli stessi contenuti e servizi.

Con l’evolvere delle capacità degli smartphone, il fattore velocità (lentezza) diventerà meno rilevante, così come tenderanno a sparire le differenze tra i diversi “motori” di rendering e interpreti Javascript. In prospettiva, mi aspetto che gli stessi “motori” siano via via incorporati ad un livello sempre più vicino al “core” del sistema operativo e all’ hardware, portando di fatto ad una convergenza tra programmazione Javascript e programmazione nativa.