Riconoscimenti
-
Questo materiale è ampiamente basato su quello realizzato dai Prof.
Mirko Viroli e Roberto Casadei, che ringrazio.
-
Ogni errore riscontratovi è esclusiva responsabilità degli autori di questo documento.
Quando il gioco si fa duro, i duri automatizzano
La gestione della compilazione potrebbe diventare complicata:
- Sorgenti in molte cartelle
- Divisi in molti package
- Alcune librerie binarie di cui non abbiamo il sorgente
Comandi molto lunghi! Facile sbagliarsi, tedioso da fare a mano!
Soluzione: costruire degli script!
Script per compilare?
In fin dei conti, è solo software che, di mestiere, compila software
…a sua volta, da compilare o interpretare.
Fare uno script personalizzato è molto flessibile, ma se abbiamo molti progetti?
- Copiarlo da tutte le parti vuol dire doverlo modificare in molti posti in caso di errore!
- Viola un principio importante: Don’t Repeat Yourself (DRY)
La compilazione è ripetitiva!
Potremmo costruire un sistema che:
- Si aspetta che i sorgenti siano in un posto standard
- Se li trova, allora compila, mettendo il risultato in un posto standard
- Se sono in un posto non standard, si configura per funzionare
Principio convention over configuration
Build systems
Sono software che si occupano di aiutare con le varie fasi della costruzione del software:
- Ricerca e scaricamento di librerie (vediamo in futuro)
- Compilazione (vediamo oggi)
- Testing (vediamo in futuro)
- Packaging (vediamo in futuro)
- Generazione di documentazione (vediamo in futuro)
- Delivery degli artefatti (non oggetto del corso)
Gradle
- Un moderno build system
- Supporta Java (oltre a C/C++, Scala, Kotlin…)
- In tutto l’ecosistema, che include Android
- Ne vedremo solo i rudimenti
- Per noi è strumentale a costruire software Java
- Impareremo come sfruttarlo per automatizzare le operazioni di cui sopra
La costruzione del software
Costruire sistemi software non è solo programmare.
Dipendentemente dal sistema in esame, potrebbero servire:
- Manipolazione e pre-processing del sorgente (inclusa generazione)
- Verifica della qualità del sorgente
- Gestione delle dipendenze
- Ricerca, scaricamento, e importazione delle librerie
- Compilazione
- Manipolazione del binario compilato
- Esecuzione dei test
- Misurazione della qualità dei test (e.g., coverage)
- Generazione della documentazione
In principio, si può anche fare a mano
- ma richiederebbe molto tempo…
- …e gli umani si stancano presto di lavori noiosi e ripetitivi
Build automation
Automatizzazione del processo di costruzione del software
- Di fatto, scrivere software che di lavoro fa manutenzione di altro software
Stili
- Imperativo/Personalizzato
- Tipicamente realizzato tramite script in qualche linguaggio di programmazione
- Flessibile e configurabile
- Difficile da adattare e riusare
- Dichiarativo/Standardizzato
- Tipicamente realizzato tramite un file di configurazione di un software dedicato alla build automation
- Portabile e di semplice comprensione
- Limitato dalle opzioni di configurazioni disponibili, e quindi poco flessibile
Convention over configuration
Principio per cui un certo sistema software ha una configurazione “ragionevole” di default,
che può essere sovrascritta in caso di necessità
- Induce la creazione di standard di fatto
- La convenzione tende a diventare il modo “normale” di fare le cose per minimizzare la configurazione
- Riduce le ripetizioni
- Aumenta la portabilità!
Automatori ibridi
Sono sistemi che cercano di unire il meglio dei sistemi dichiarativi e imperativi
- Il file di configurazione è in realtà uno script in un linguaggio di programmazione vero e proprio
- Aprendolo sembra un file di testo con la configurazione
- In realtà è uno script valido!
- Quanto non specificato si assume come da convenzione
- Quando si vuole personalizzare qualcosa, si ha a disposizione la “potenza di fuoco” di un linguaggio di programmazione vero e proprio
Esempi
- Sbt, che si appoggia su Scala
- Gradle, che si appoggia su Kotlin o Groovy
Il linguaggio host deve consentire di costruire dei Domain-Specific languages
- ossia, essere così flessibile da permettere di costruire un “linguaggio nel linguaggio”
Gradle
- Un moderno build system ibrido
- Pilotato in Kotlin (preferibile) o in Groovy
- Supporta Java (oltre a C/C++, Scala, Kotlin…)
- In tutto l’ecosistema, che include Android
- Ne vedremo solo le basi di utilizzo
- Per noi è strumentale a costruire software Java
- Impareremo come sfruttarlo per automatizzare le operazioni di cui sopra
Gradle è in espansione: Google trends
Concetti base in Gradle: task, progetto, plugin
Progetto
Una directory contenente il file speciale build.gradle.kts
e/o settings.gradle.kts
,
detti build file.
La loro presenza segnala a Gradle che la cartella rappresenta un progetto
Plugin
Componente software contentente task pronti all’uso.
Gradle contiene diversi plugin pronti all’uso
(per i linguaggi più comuni, come Java).
Task
Un task in Gradle rappresenta una singola operazione atomica del processo di costruzione del sofware
- singola $\rightarrow$ un task fa una sola cosa (Single Responsibility Principle)
- atomica $\rightarrow$ indivisibile: un task comincia e finisce senza interruzione
Qualunque esecuzione di Gradle richiede di specificare uno o più task, ad esempio:
gradle tasks
(elenca i task disponibili, escludendo quelli non categorizzati)
gradle tasks --all
(elenca tutti i task disponibili)
gradle compileJava
(compila i sorgenti java)
Gradle è in grado capire le dipendenze fra task ed eseguirli nell’ordine corretto.
Gradle: configurazione minimale per Java
- Gradle viene pilotato con due file:
settings.gradle.kts
- Per i nostri scopi, serve solo a dare un nome al progetto
build.gradle.kts
- Conterrà tutta la logica di costruzione del software
- Ma noi sfrutteremo le convenzioni, configurando ben poco!
- Al momento, ci basta una sola riga di codice per ciascuno!
settings.gradle.kts
rootProject.name = "minimal-build"
build.gradle.kts
Così configurato, Gradle autonomamente:
- cerca e compila i sorgenti java dalla cartella:
src/main/java
- produce i binari dentro:
build/classes/java/main
Vogliamo percorsi diversi?
Va configurato.
Gradle: Hello World in Java, struttura
├── build.gradle.kts
├── settings.gradle.kts
└── src
└── main
└── java
└── HelloWorld.java
build.gradle.kts
settings.gradle.kts
(opzionale)
rootProject.name = "hello-world"
HelloWorld.java
public class HelloWorld {
public static void main(String... args) {
System.out.println("Hello, world!");
}
}
Gradle: Hello World in Java, task e loro utilizzo
- elencare i task disponibili:
- compilazione:
- pulizia (cancellazione della directory
build
dove Gradle lavora):
- esecuzione (non responsabilità di Gradle):
java -cp build/classes/java/main HelloWorld
(Non) installare Gradle: il wrapper
Se da una versione all’altra di Gradle dovesse cambiare la convenzione,
cosa succederebbe?
- Il nostro software smette di funzionare se aggiorniamo il build system!
E se avessimo progetti diversi che richiedono versioni diverse di Gradle?
Ci serve un modo per portarci dietro la versione di Gradle che ci serve
Gradle wrapper
Un insieme di script con un software minimale che:
- Scarica la versione di Gradle indicata in un file di configurazione
- se non già disponibile nel sistema
- Usa quella versione per costruire il nostro sistema!
Il wrapper può (deve) esser copiato in ogni progetto che gestiamo con Gradle
Dato che si auto-scarica, non occorre installare Gradle!
- Anche se è comodo, la versione di Gradle installata può generare le versioni wrapper
Progetti Gradle con wrapper
- Script bash eseguibile (/):
gradlew
- Script batch eseguibile ():
gradlew.bat
- File di configurazione con indicata la versione di Gradle:
gradle/wrapper/gradle-wrapper.properties
- Software Java che scarica la versione di Gradle descritta nel file di configurazione:
gradle/wrapper/gradle-wrapper.jar
Wrapper pronto per esser scaricato:
Utilizzo di Gradle in un progetto Java
Se abbiamo il Gradle wrapper configurato in un progetto,
possiamo usarlo attraverso uno dei due script:
gradlew
(/)
o gradlew.bat
(),
a seconda della nostra piattaforma
- seguito da un elenco di comandi detti task
In Gradle, un task è una particolare attività del processo di costruzione del software
Esiste un task che elenca i task, chiamato tasks
.
Quando configurato per compilare Java fra i vari task troviamo anche compileJava
Ottenere l’elenco dei task disponibili
./gradlew tasks
(sistemi e )
gradlew.bat tasks
(sistemi )
Compilazione Java
./gradlew compileJava
(sistemi e )
gradlew.bat compileJava
(sistemi )
È sempre comunque possibile lanciare i nostri eseguibili a mano dal terminale!
java -cp build/classes/java/main nome.qualificato.della.ClasseDaEseguire
Appendice – Varianza
Sia $n$ il numero di elementi dell’array ed $x_i$ l’elemento all’indice $i$ dell’array, e $\mu$ la media dei valori del suddetto array. La varianza $\sigma^2$ può essere calcolata come:
$$\sigma^2 = \frac{\displaystyle\sum_{i=0}^{n-1}(x_i - \mu)^2} {n}$$