Sommario
< Home
Stampa

Creare una Web Application

Nel momento in cui si comincia a realizzare applicazioni web complesse, emergono tre problematiche:

  1. E’ necessario suddividere il progetto in più files, per garantire maggiore leggibilità del codice, rendere possibile lavorare in contemporanea su più componenti da parte di team di progetto, ed infine poter riusare componenti in progetti successivi.
  2. Una applicazione complessa può utilizzare librerie e strumenti realizzati da terze parti, presenti in repository disponibili su Internet.
  3. Le configurazioni nei progetti condivisi su Internet devono essere separate in modo netto dal codice, in modo da garantire sia la sicurezza (es. delle password di accesso ad un database) sia la possibilità di utilizzare la stessa applicazione in ambienti di esecuzione differenti.

Vedremo in questa lezione come risolverle.

Cosa è un progetto?

Un progetto può essere definito come l’insieme dei prodotti software che il team di programmatrori realizza per far funzionare l’applicazione. Esso è costituito principalmente da 4 principali tipologie di artefatti:

  • il codice sorgente (codebase) dell’applicazione scritto dai programmatori stessi, suddiviso in uno o più files;
  • librerie di terze parti, ovvero codice (o librerie compilate) scritte da terze parte, che vengono utilizzate dal codice sorgente;
  • gli asset di progetto, ovvero files che non contengono codice che deve essere eseguito ma elementi comunque necessari per funzionare: icone, immagini, font, CSS, audio, video, ecc.;
  • le configurazioni, ovvero files che contengono informazioni per far funzionare il software in un determinato contesto di esecuzione (ovvero un ambiente)

Questi 4 elementi sono chiamati nel loro insieme deliverable, ovvero i componenti del pacchetto che verrà distribuito al committente, che viene chiamato build.

In un progetto Javascript vanno quindi gestiti insieme come una unica entità, in questa sede approfondiremo in particolare librerie e configurazioni.

Librerie

Le librerie sono un insieme di strumenti e tool realizzati da terzi che importiamo nel nostro progetto che implementano funzioni semplificando il nostro lavoro di codifica. Si ricorda che le librerie possono essere sia codice compilato e relativi simboli sia codice sorgente anche in linguaggi differenti da quello che usiamo, ma in ogni caso non vanno mai considerate parte della codebase che produce lo sviluppatore

Non bisogna invece inoltre fare confusione con le librerie di sistema, che vengono anch’esse utilizzate dal programmatore, ma che non sono parte dei deliverable (sono fornite “chiavi in mano” direttamente con il linguaggio e il runtime). Ad esempio DOM e BOM sono librerie di sistema.

Quando si vogliono librerie di terze parti esistono due diversi modi per utilizzarle:

  • il primo è quello di includerle direttamente nell’HTML tramite il tag <script src=”url” …/> dove la url è una URL pubblica che contiene la libreria pronta per essere usata. Questa risorsa è distribuita su Internet tramite server distribuiti chiamati CDN (Content Delivery Network) ed ha il grande vantaggio che non dobbiamo scaricare nulla nel nostro progetto. Ma anche lo svantaggio che il nostro progetto dipende dalla disponibilità di una risorsa su Internet (non garantita) e che se questa URL non funziona lo si scopre solo a runtime.
  • Il secondo è quello di scaricare la libreria, metterla in una qualche cartella del progetto, e poi includerla con il tag <script>. Con questo sistema si garantisce che tutti i files del progetto sono nella cartella di progetto senza dipendenze esterne, a build time.

Ad esempio la libreria Bootstrap è utilizzabile in entrambi i modi.

Nei progetti reali si usa sempre il secondo sistema, per evitare rischi di dipendenze verso sistemi esterni. Il problema che si pone, tuttavia, è che se si usano molte librerie di terze parti si crei nel proprio progetto una confusione di cartelle e sottocartelle, senza permetterci di capire cosa abbiamo incluso, dove si trova, cosa non ci serve più. Va poi considerato il problema di andare a cercare queste librerie, scaricandole ciascuna dal suo sito web, vedere se sono uscite nuove versioni, ecc.

In pratica è necessario tenere un database delle librerie di progetto e possibilmente una cartella che le possa contenere tutte. Per risolvere questo problema viene in aiuto Npm.

Npm e Package.json

Per usare Npm bisogna installare NodeJS.

Finora Javascript è stato visto come un linguaggio che funziona all’interno di una pagina web che per funzionare quindi ha bisogno di un browser ed una pagina html. In realtà a partire dal 2012 è stato sviluppato un runtime in grado di eseguire Javascript anche senza un un browser. Questo prodotto si chiama NodeJs, e grazie a questo è diventato possibile realizzare applicazioni eseguibili sulla maggior parte dei sistemi operativi (per approfondire si rimanda a questa lezione).

Insieme a NodeJS è stato introdotta una applicazione, Node Package Manager Npm è il package manager di Node (“Node Package Manager”). Npm è una applicazione che si appoggia ad un database unificato su Internet (www.npmjs.com) che contiene la quasi totalità delle librerie esistenti per il linguaggio Javascript. Tramite un unico comando npm è quindi possibile installare e disinstallare qualsiasi libreria, in qualsiasi versione, il tutto in una sola cartella e memorizzare in un file di configurazione le librerie installate al momento nel progetto.

La cartella dove sono contenute tutte le librerie si chiama node_modules e il file di configurazione si chiama package.json. In realtà package.json fa molto più di questo: esso permette di definire un insieme di metadati di progetto (autore, titolo, versione, licenza, ecc.) e memorizza anche un insieme di comandi utili per far funzionare il progetto (es. per eseguire test, per eseguirlo, ecc.).

Qui un esempio di package.json.

{
  "name": "Hello World",
  "version": "1.0.0",
  "description": "simple Hello World application",
  "main": "index.js",
  "author": "cipiaceinfo.it",
  "license": "ISC",
  "dependencies": {
     "mylibrary": "1.1.0"  
  }
}

Un file package.json viene inizializzato col comando

npm init

Per installare una libreria bisogna conoscerne il nome (reperibile sul sito web sopra indicato) e poi eseguire il comando

npm install --save miopacchetto

Npm scaricherà il pacchetto lo metterà nella cartella node_modules, aggiornerà il package.json e sarà quindi possibile usarla.

Gestione delle dipendenze: import ed export

Finora nei casi in cui si sono scritti progetti con più files JS questi files sono stati inclusi nella pagina HTML con il tag script:

<script src="file1.js" type="text/javascript" />
<script src="file2.js" type="text/javascript" />

Con questo metodo il browser carica in sequenza tutti gli script e rende disponibili le funzioni e le variabili (globali) del file1.js a quelli successivi (file2.js) ma non ovviamente viceversa (quindi file1.js non “vede” gli oggetti presenti in file2.js).

Questo metodo, molto rapido, e molto usato fino al 2015 (era l’unico possibile) è però concettualmente sbagliato. Prima di tutto perché i files JS potrebbero essere decine o centinaia, inoltre perché non potrebbero essere necessari tutti e subito, rallentando quindi il caricamento della pagina web. Infine, ed è il problema più importante, tutti gli oggetti sono di fatto globali rendendo quindi molto facile avere sovrapposizione di variabili o peggio utilizzi errati e confusionari di oggetti creati chissà dove, rendendo praticamente impossibile gestire qualsiasi progetto che superi qualche centinaio di righe.

Dal 2015 con ES6 è stato definito il nuovo standard ES Modules che prevede invece che ogni file script possa definire un insieme di simboli che possa esportare, ed un insieme di simboli che possa importare. Facciamo un esempio: poniamo di definire un insieme di costanti in un file Javascript conf.js

export const configuration = {
 "singola": 10,
 "doppia": 5,
 "tripla": 3
}

export const cacheToken = "123456789abcdefg";

export const log = (data) => { console.log(data): }

Questo file esporta uno più oggetti verso altri script.

Per importare questi oggetti si usa import:

import { configuration, log } from './conf.js';

log(configuration);

Come si vede è possibile scegliere anche cosa importare. La potenza di questo sistema è che permette di importare solo quel che serve senza usare oggetti globali.

Ogni script può sia importare che esportare e quindi è possibile creare un grafo orientato (necessariamente aciclico) di dipendenze come nell’esempio seguente:

File di configurazione

Pacage.json non è l’unico file di configurazione. Sono molto importanti anche altre configurazioni e nello specifico:

  • file contenenti password di autenticazione;
  • file contenenti strutture di dati che definiscono un contesto di esecuzione, ad esempio indirizzi IP, label da visualizzare, parole chiave, ecc.

Queste due tipologie di configurazione vanno tenute separate dalla codebase perché contengono informazioni che non sono codice eseguibile e che soprattutto possono cambiare se si installa l’applicazione in contesti differenti. Ricordarsi sempre che bisogna separare sempre l’astrazione (il codice) dai dettagli (le configurazioni).

Inoltre quando si usa git, bisogna tenere questi files non solo separati dalla codebase, ma anche fuori dal tracciamento di git, inserendoli nel file .gitignore.

Le configurazioni non sono mai codice, anche se inserite in file JSON o Javascript. Per importarle è poi possibile includere nel progetto o tramite il meccanismo di import oppure in alternativa caricandole tramite fetch (una GET verso la URL dove si trova la configurazione).