<- Installazione e configurazione di un server Linux - Indice Generale - Copertina - Indice -> |
PLUTOWare
L'articolo...Nella programmazione non si può evitare di scontrarsi,
prima o poi, con strumenti per la gestione di progetti. Chi ha una
minima esperienza con linguaggi come il C avrà avuto modo
di fare i conti con gli autotools, così come chi ha sposato
la causa Java avrà probabilmente avuto a che fare con Ant.
Maven si propone come una valido sostituto di quest'ultimo, senza
limitarsi ad offrire le funzioni basilari rese appetitose
condendole con artefatti di dubbia utilità, ma cambiando
radicalmente il modo di vedere la gestione di un progetto
Java. |
The #1 programmer excuse for legitimately slacking off: "my code's compiling"
Cosa è Maven? A questa domanda non è facile dare una
risposta precisa. Maven fornisce un approccio completamente nuovo
alla questione della gestione di progetti Java che spazia a 360°,
quindi la risposta alla domanda di cui sopra varia in relazione a chi
viene posta e all'uso che questa persona fa di Maven.
Si può
però facilmente dire cosa non è Maven. Maven non è
solo uno strumento per compilare e testare il proprio codice, è
molto di più. Maven non è solo uno strumento per
impacchettare e distribuire il proprio codice, è molto di più.
Con Maven il nostro progetto può godere ad esempio della
generazione automatica della documentazione e di pagine per un
potenziale sito web, può usufruire del supporto allo sviluppo
in un team e della generazione di report, così come di molte
altre caratteristiche che raramente si trovano concentrate in un
unico strumento per la gestione di progetti.
Come riportato in [2], ecco una definizione formale per Maven:
Maven è uno strumento per la gestione di progetti che prevede un modello a oggetti, un insieme di standard, trattazione per il ciclo di vita di un progetto, un sistema di gestione delle dipendenze e logiche per l'esecuzione di obiettivi in forma di plugin in fasi specifiche del ciclo di vita. Usando Maven si descrive un progetto usando un ben definito modello ad oggetti, sul quale Maven stesso può applicare una logica trasversale a partire da un insieme di plugin condivisi o personalizzati.
Cosa è, quindi, Maven?
Maven può essere la
risposta per chi cerca un semplice strumento per la compilazione
automatica del proprio software così come per chi ha bisogno
di un approccio più complesso ed articolato alla gestione di
un progetto, riuscendo a sopperire alle richieste e alle esigenze del
singolo in un modo tanto semplice quanto completo. Non deve
spaventare la sua apparente complessità, di fatto infondata,
così come è necessario superare la sensazione di
perdita di controllo che qualcuno ha di fronte a Maven e al suo
comportamento. Una volta imparato ad apprezzarne le caratteristiche e
le funzionalità ogni sviluppatore non vorrà più
fare a meno di Maven, neanche nel più classico degli ''Hello
World!''.
In [1] è presente una breve introduzione, Maven in 5 Minutes che rende fede alla semplicità e immediatezza di questo strumento guidando il lettore nella sua prima, breve esperienza. Il consiglio è, ovviamente, quello di darci un'occhiata. Purtroppo, per problemi di spazio, non sarà possibile dilungarsi attraverso troppi esempi in questo articolo, quindi verranno citati laddove possibile riferimenti utili in tal senso. Allo stesso pari può essere illuminante leggere Getting Started Tutorial, sempre reperibile in [1], una sorta di guida che approfondisce e completa le tematiche lasciate aperte nella breve introduzione precedente.
Maven descrive il singolo progetto attraverso un file POM
(Project Object Model), senza il quale Maven non può
fare niente. Il file POM guida l'esecuzione in Maven e definisce in
modo chiaro l'identità e la struttura di un progetto in ogni
suo aspetto e sfaccettatura.
Un esempio di file pom.xml
in [3] è il seguente:
<project> <modelVersion>4.0.0</modelVersion> <groupId>com.mycompany.app</groupId> <artifactId>my-app</artifactId> <packaging>jar</packaging> <version>1.0-SNAPSHOT</version> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>3.8.1</version> <scope>test</scope> </dependency> </dependencies> </project> |
In un progetto gestito con Maven tutto è descritto in un
file POM: dipendenze, processo di compilazione, artefatti e fasi
secondarie come la generazione di documentazione. Questo è
l'analogo dei Makefile per gli autotools o del file
build.xml per Ant. Ma a differenza dei suoi illustri
colleghi non racchiude codice, non riporta direttive di alcun genere,
è un file dichiarativo che racchiude in poche righe un grande
potere espressivo sollevando lo sviluppatore dalla necessità
di scendere nei dettagli delle diverse fasi.
Il file POM è
diviso principalmente in quattro parti, ovvero:
Informazioni generali sul progetto, dove possono essere riportati ad esempio nome e URL, lista degli sviluppatori, licenza e così via.
Impostazioni per la compilazione, ovvero dichiarazioni per la personalizzazione del processo di compilazione di Maven come l'aggiunta di plugin, posizione dei sorgenti, parametri di generazione delle pagine per un potenziale sito e via dicendo.
Ambienti per la compilazione, ovvero profili utili a differenziare le diverse fasi di lavoro e il comportamento ad esse associato.
Relazioni fra POM per l'inclusione di moduli, l'ereditarietà fra progetti legati e quindi attraverso POM multipli, ma non solo...
Nella pratica ogni POM estende quello che è chiamato il Super POM, contenuto nel file maven-x.y.z-uber.jar all'interno del sistema ed ereditato automaticamente, il quale fornisce un insieme di dichiarazioni standard condivise da ogni progetto. Per brevità non è riportato ma si consiglia di dargli un'occhiata, a partire dal proprio sistema o come riportato in [2] per Maven 2.0.9. Nel Super POM è riportato ad esempio il repository remoto da cui ogni client attingerà per completare ed aggiornare la base locale, la struttura per l'albero delle directory come indicata dallo Standard Directory Layout e molto altro ancora.
Nella sua semplicità, anche il solo POM riportato nel riquadro precedente mette in campo alcuni dei campi chiave di questo oggetto. Ovviamente non è questo il luogo per discutere la sintassi di un file pom.xml ma questa è ampiamente illustrata sia a partire da [1] che in [2] e [3], ai quali si può fare riferimento per approfondimenti. Ci si accorgerà col tempo che la stesura di file POM è cosa immediata e molto semplice, ma può farsi anche complicata seguendo comunque in modo naturale la curva d'apprendimento dell'utente di Maven.
Il build lifecycle è il concetto centrale intorno al
quale si sviluppa Maven. Consiste in una serie di fasi durante le
quali si possono avere più operazioni, dette goal, come
ad esempio durante la fase di compilazione si avranno una serie di
chiamate per compilare appunto un insieme di classi.
È
utile capire fin da subito che alcune fasi sono strettamente legate
ad altre e quindi l'invocazione delle prime causerà
necessariamente anche l'esecuzione delle seconde. In altri termini,
laddove l'esecuzione di una fase sia logica conseguenza di un'altra
(come la creazione di un package che segue alla compilazione dei
sorgenti, obbligatoriamente) verranno prese in considerazione
nell'ordine corretto tutte le fasi che portano a quella richiesta.
L'aggiunta di funzionalità nel circuito è possibile
tramite l'uso di plugin, i quali possono andare a collocarsi in un
punto qualsiasi della filiera produttiva a seconda delle
necessità.
Maven si propone con un lifecycle predefinito
che prevede diverse fasi, la validazione del progetto, la
compilazione, il test, la creazione di pacchetti e così via.
Allo stesso tempo è fornito di un gran numero di plugin per le
necessità più disparate, ufficiali e non, i quali
contribuiscono ad allargare il parco fasi e aggiungono a quelli
appartenenti al core di Maven tutta una serie di
caratteristiche come la possibilità di creare file war,
automatizzare la generazione della documentazione basata su JavaDoc,
creare una firma digitale e tanto altro ancora (si veda a tal
proposito [4]).
A questo punto, fornita un'idea di base di cosa è Maven,
sarebbe forse opportuno dare anche un esempio che, attraverso alcune
semplici istruzioni, illustri come si può facilmente creare un
progetto basato su Maven. Questo è però un argomento
trattato in più e più articoli apparsi sulla rete ed è
ampiamente documentato in ogni suo passo tanto in [2] e [3] quanto in
[1], nelle due guide Getting Started in 5 Minutes e Getting
Started in 30 Minutes; tutta documentazione facilmente e
legalmente reperibile su Internet.
Per uscire un po' dal coro e al
contempo dare un esempio di un progettino basato su Maven, che
rispetti la struttura di directory standard proposta e si articoli in
un pom.xml completo, viene descritto come approcciare il
problema delle applicazioni web. Supponiamo quindi che si voglia dare
luogo ad un immancabile Hello World! sul web basato su Maven.
La struttura della directory come consigliata in [3] e prima ancora
in [1], un po' rimaneggiata e ridotta per soddisfare le necessità
in base ai problemi di spazio, è la seguente:
project-name |--> src | |--> main | |--> java | | |--> org | | |--> company-name | |--> webapp | |--> WEB-INF | | |--> web.xml | |--> index.jsp |--> pom.xml |
Il file pom.xml associato può assomigliare al seguente:
<project> <modelVersion>4.0.0</modelVersion> <groupId>org.company-name</groupId> <artifactId>project-name</artifactId> <packaging>war</packaging> <version>1.0-SNAPSHOT</version> <name>project-name</name> <description>project description</description> <url>http://www.company-name.org/project-name</url> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>3.8.1</version> <scope>test</scope> </dependency> </dependencies> <organization> <name>company-name</name> <url>http://www.company-name.org</url> </organization> <build> <finalName>${artifactId}-${version}</finalName> </build> </project> |
Con queste premesse dovrebbe essere sufficiente eseguire Maven package per trovarsi impacchettato sul proprio sistema il file project-name-1.0-SNAPSHOT.war. Il tutto dovrebbe avvenire dopo un po' di tempo durante il quale viene rifocillato il repository locale con i pacchetti mancanti, i quali vengono scaricati da una locazione remota predefinita (questa fase avviene solo al primo utilizzo di Maven, dopo il quale i pacchetti saranno già presenti sul proprio sistema e non si avrà la necessità di scaricarli ancora), e quindi vengono attraversate un certo numero di fasi che portano di fatto alla compilazione.
Nell'ultima sezione si vuole dare una panoramica dello sviluppo di
plugin in Maven, ovvero di come sia possibile estendere in modo
semplice e veloce le funzionalità di questo strumento
adattandolo alle proprie esigenze. Maven, come citato sul sito
ufficiale, è di fatto un framework per l'esecuzione di plugin
ed effettivamente anche il suo funzionamento di base si appoggia ad
alcuni di questi oggetti distribuiti in maniera predefinita col
pacchetto.
Per ampliare le funzionalità di Maven si ha già,
nonostante il progetto sia relativamente giovane, una nutrita lista
di plugin extra che spazia su ogni tipologia di tematica e ambiente,
come si può notare in [4].
Per tutti i plugin, ufficiali e non, si ha una breve documentazione che rende quindi del tutto vano il tentativo di darne un'introduzione in questa sede, poiché sono in realtà molto semplici da usare e configurare. Più interessante, invece, è l'aspetto di sviluppo di questi oggetti, così da poter aggiungere qualcosa di personale al proprio progetto.
Nello sviluppo di plugin è utile capire come funziona in
realtà Maven al suo interno, il che semplifica non poco il
resto del compito. Il cuore di Maven si basa su Plexus, un
container per gestire e mettere in relazione fra loro i
diversi componenti, nato come progetto indipendente e adottato da
Maven durante il concepimento poiché altri strumenti dello
stesso tipo (anche ad oggi più noti, come lo spring
framework) non erano ancora maturi.
Plexus mette in pratica i
principi dell'inversione di controllo (Inversion of
Control, o IoC), una modalità di progettazione del
software in cui il flusso di controllo è invertito rispetto ai
metodi usuali. Come spesso riportato parlando di IoC, esso si basa
sul principio di Hollywood: "non ci chiami, la chiameremo
noi"; al di là della definizione forse un po'
scherzosa, questo significa che in framework di questo genere non si
è soliti chiamare i metodi messi a disposizione (come ad
esempio nell'uso di librerie) ma piuttosto il proprio software viene
invocato sulla base di determinate interfacce, offrendo i propri
servizi all'ambiente che lo circonda. Non sarà quindi il
proprio codice ad andare a dipendere pesantemente dalla libreria o
dal framework utilizzato, quanto piuttosto sarà favorito lo
sviluppo di componenti riutilizzabili che vanno ad integrarsi in modo
trasparente e senza nessun riferimento esplicito all'interno di un
ambiente che provvederà alla loro invocazione ed
esecuzione.
Spostandoci quindi su Plexus, questo lascia all'utente
il compito di dichiarare le relazioni esistenti fra insiemi di
componenti, i quali si limitano a fornire specifiche interfacce di
input/output. Gli oggetti da esso trattati non saranno e non devono
essere istanziati dall'utente ma sarà Plexus a farlo e allo
stesso modo sarà Plexus a farsi carico della gestione del loro
stato e del loro ciclo di vita. Questo, come detto, favorisce il
disaccoppiamento fra oggetti e framework e incoraggia lo sviluppo di
software riutilizzabile.
L'idea sostanziale è quindi quella di rimuovere
completamente dal codice il trattamento per la creazione e la
gestione del ciclo di vita degli oggetti, evitando al contempo ogni
sorta di dipendenza dal container in cui si va ad operare. Un altro
degli aspetti interessanti è poi quello del Dependency
Injection. In container come Plexus è spronata la
programmazione basata su interfacce, tale da permettere la
configurazione dei componenti e la cattura delle dipendenze che fra
loro intercorrono, il tutto in un semplice file xml che definisca chi
partecipa e come collabora. L'intuizione, senza scendere
ulteriormente in dettagli, è che si possa gestire il ciclo di
vita degli oggetti, ad esempio istanziandoli in copia unica (evitando
il proliferare dei tanto amati e al contempo criticati Singleton),
con conseguente capacità di passarli come argomenti
all'invocazione di metodi per altri oggetti, il tutto configurato
solo ed esclusivamente via xml (quindi senza interferire col codice).
In altri termini, si possono scrivere elementi che non sanno niente
l'uno dell'altro e vengono legati fra loro tramite direttive via
xml.
Nei container Java tipici si hanno più tipi di
iniezione delle dipendenze ma Maven si appoggia solamente a due di
questi:
iniezione basata su metodi setter: viene usato un metodo setter di un Java Bean per popolare l'oggetto in base alle sue dipendenze.
iniezione basata su scrittura su proprietà: per evitare la chiamata di metodi pubblici inevitabile con l'iniezione basata su metodi setter, si può popolare un componente andando ad impostare un campo di un oggetto direttamente.
Quanto sopra non può e non vuole essere esaustivo e fatica a tratti anche ad essere chiaro, ma vuole dare un'infarinatura sul cosa sta alla base di Maven e qual è il motore che permette ad esso di funzionare. Già adesso forse è possibile avere un po' più chiaro il funzionamento, capire intuitivamente come vengono trattati i plugin e quindi i mojo in Maven (ovvero da Plexus, che sta di fatto alla base di tutto) e farsi un'idea di come sarà orientato lo sviluppo di nuovi componenti.
La componente fondamentale in applicazioni basate su Maven è il Mojo (Maven plain Old Java Object), che va a collocarsi nella filiera produttiva rappresentando un singolo passo per il trattamento del software. Nello specifico non è il singolo mojo ma più mojo che concorrono per uno stesso obiettivo a dar luogo ad un plugin, come ad esempio nel caso del plugin maven-compiler-plugin che comprende i due mojo compile e testCompile. Intuitivamente, guardando la cosa dall'altro lato, se un mojo individua un singolo passo in un processo di generazione allora si può vedere quest'ultimo come l'esecuzione in un ordine fissato di una quantità di mojo per raggiungere un prefissato obiettivo (ogni mojo contribuirà permettendo il raggiungimento di una parte di esso, in base al proprio ruolo).
All'interno di un plugin, intuitivamente, così da
permettere a Maven di utilizzarlo in modo corretto all'interno della
filiera produttiva, si ha un descrittore che fornisce indicazioni
sulla sua struttura e funzione, ovvero il file
META-INF/maven/plugin.xml.
Per la verità, nello
sviluppare plugin personalizzati non si avrà quasi mai la
necessità di scrivere descrittori, poiché questi
possono essere generati automaticamente a partire da annotazioni
presenti direttamente nel codice del plugin.
Senza scendere ulteriormente in particolari, quanto introdotto
dovrebbe essere sufficiente a dare un'idea di come sia al contempo
flessibile e semplice da usare il modello a plugin di Maven e,
quindi, come sia facilmente estendibile con strumenti personalizzati
a seconda dei propri desideri e delle proprie necessità. La
stesura di un plugin si riassume di fatto nello sviluppo di una serie
di mojo (ovvero di singole classi Java contenenti una serie di
annotazioni per la generazione automatica dei descrittori) e poco
più, un'operazione che con tutta probabilità non
spaventerà ma, piuttosto, stuzzicherà l'interesse e
motiverà gli sviluppatori che si avvicinano a Maven.
Un
esempio di mojo, senza una descrizione e spiegazione accurata ma solo
ed esclusivamente a titolo informativo, come riportato in [2] è
il seguente:
package org.sonatype.mavenbook.plugins; import org.apache.maven.plugin.AbstractMojo; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugin.MojoFailureException; /** * Echos an object string to the output screen. * @goal echo * @requiresProject false */ public class EchoMojo extends AbstractMojo { /** * Any Object to print out. * @parameter expression="${echo.message}" default-value="Hello World..." */ private Object message; public void execute() throws MojoExecutionException, MojoFailureException { getLog().info( message.toString() ); } } |
Come si può notare, tanto chiaro quanto semplice!
Questa breve gita nel mondo di Maven è finalmente o
purtroppo terminata. Qualcuno potrà forse obiettare che in
questo articolo si è detto tanto ma non si è detto
niente e proprio questo, in realtà, era lo scopo.
Maven è
un mondo relativamente nuovo e abbastanza articolato, può
mostrare risvolti complessi ma allo stesso tempo guidare con grazia e
semplicità gli utenti che vi si avvicinano in un percorso
attraverso un uso immediato, intuitivo e completo fin da subito
arrivando ad una consapevolezza più dettagliata delle sue
potenzialità. Maven non è forse lo strumento definitivo
nel suo campo ma senza dubbio ha tutte le caratteristiche per poter
dire la sua e ritagliarsi una discreta fetta di utenza che, per
quanto esigua possa essere al giorno d'oggi, sarà contagiosa
con la sua soddisfazione.
La speranza è quella, con questi pochi cenni, di aver trasmesso la completa soddisfazione di chi vi scrive nell'usare Maven in ogni nuovo progetto, da alcuni mesi ad oggi. La speranza è che sia stuzzicata la curiosità e attraverso i riferimenti indicati in bibliografia, liberamente scaricabili dal web come riportato anche sul sito stesso di Maven, il lettore possa muovere i primi passi nel mondo di Maven e chiedersi (come in una nota pubblicità) perché nessuno gliene avesse mai parlato prima...
[1] Apache Maven Project:
http://maven.apache.org
[2] Maven - The Definitive Guide:
Readable
HTML and Free PDF Download
[3] Better Builds with Maven:
Free
PDF Download
[4] Apache Maven Project (Available
Plugins):
http://maven.apache.org/plugins/index.html
[5] Plexus:
http://plexus.codehaus.org/index.html
[6] Maven
Repository:
http://mvnrepository.com/
L'autoreMichele Caini è
studente nel corso di laurea specialistica in Ingegneria
Informatica presso l'Università degli Studi di
Firenze. |
<- Installazione e configurazione di un server Linux - Indice Generale - Copertina - Indice -> |