Utilizzare
J2EE: un problema pratico
La piattaforma J2EE ha costituito, sin dal suo primo apparire,
una vera rivoluzione nell'ambito dello sviluppo di software
a livello enterprise. Ciò è testimoniato sia
dal gran numero di applicazioni che con essa sono state sviluppate,
sia dalla continua e costante evoluzione della piattaforma
medesima, dato che nel corso del tempo sempre più numerose
sono le tecnologie che sono andate a confluirvi. D'altra parte,
è anche vero che approcciare J2EE non è banale,
e chi affronta la progettazione di una nuova applicazione
si trova a confrontarsi con una serie di problematiche che
derivano dalla complessità intrinseca di J2EE stessa.
A questo va aggiunto che apprendere le tecnologie J2EE viene
spesso confuso con imparare a progettare con le tecnologie
J2EE, e non si tratta di una differenza da poco. Esiste molta
documentazione di qualità che permette di conoscere
a fondo la piattaforma J2EE ma esiste d'altra parte non molta
chiarezza su come lavorarci in pratica.
Il problema di fondo è quindi essenzialmente di tipo
pratico: come passare da una fase di design - per quanto bene
sia stata effettuata - ad una implementazione affidabile,
robusta e performante.
I
Pattern
Quello che occorre è un insieme di regole che permettano
di risolvere in modo sicuro i principali problemi che possono
presentarsi, e che siano altresì riapplicabili in contesti
analoghi.
Questa è, più o meno, proprio la definizione
di Pattern.
Se andiamo indietro nel tempo, troviamo la parola Pattern
per la prima volta nella letteratura scientifica nel 1970,
e, curiosamente, non nel mondo informatico. Viene utilizzata
da un tale Christopher Alexander nei suoi libri per descrivere
regole di progettazione e costruzione nella ingegneria civile
e nella architettura.
Il mondo informatico, nei tempi successivi, fa suo il termine
Pattern e lo utilizza nella medesima accezione e cioè:
fornire soluzioni affidabili a problemi ricorrenti.
E' proprio con questo obiettivo che un gruppo di esperti,
al secolo noti come Gang of Four, ossia La Banda dei Quattro,
pubblica un testo fondamentale (rif [2]), nel quale documenta
la propria esperienza in ambito sviluppo software e descrive
una serie di soluzioni riutilizzabili.
Tali soluzioni, denominate appunto Pattern, sono valide per
lo sviluppo del codice, e non specifiche per una data piattaforma.
Questa
è l'origine della storia, vediamo di arrivare ora a
una definizione rigorosa di Pattern.
Nella letteratura specialistica ne troviamo diverse, alcune
a volte quasi pittoresche.
Un esempio fra tutte: "Un pattern è un'idea che
si è rivelata utile in un dato contesto e probabilmente
lo sarà ancora in altri" (rif [3]). Se si legge
con attenzione questa definizione, una delle prime cose che
viene da pensare è che un Pattern non è affatto
qualcosa di inventato ex-novo, è piuttosto qualcosa
che discende dalla pratica e dall'esperienza.
E' infatti proprio nella pratica e nella esperienza che è
possibile affinare la ricerca e la messa in opera delle soluzioni
migliori e, tra di esse, di quelle riutilizzabili.
Come procedere per identificarle? Il
primo passo consiste nell'individuare tre elementi fondamentali,
e cioè:
- un
problema: cosa devo fare?
- una
soluzione: come lo faccio?
- un
contesto di riferimento: qual'è l'ambito in cui affronto
il problema?
Il
secondo passo ci porta a individuare invece una relazione
tra i tre elementi sopra evidenziati.
Di qui la definizione di Pattern (quella rigorosa): Un Pattern
è una soluzione comune ad un problema comune in un
contesto ricorrente.
Viene
quindi in mente di impiegare i Pattern in un ambito complesso
come quello J2EE, proprio per avere a disposizione un ricco
insieme di "best practices" e poter affrontare in
modo affidabile le fasi di implementazione a partire da un
progetto.
Nascono
quindi i Pattern J2EE (rif [1]), pattern architetturali specifici
per applicazioni complesse multi-tier, proprio quelle della
piattaforma J2EE.
Chi
li ha sviluppati non ha fatto altro che "racchiudere"
in una descrizione formale e quanto più possibile "pronta
all'uso" (corredata di diagrammi, esempi e implementazioni),
una serie di soluzioni generalizzate, frutto di anni di esperienza
nello sviluppo di applicazioni J2EE.
Tali soluzioni generalizzate sono state messe a punto e focalizzate
su aspetti chiave quali l'immediatezza d'uso, la scalabilità,
la perfomance, la riutilizzabilità.
Il
risultato di tutto questo lavoro è il cosiddetto J2EE
Pattern Catalog, che raggruppa i diversi Pattern sostanzialmente
in tre categorie, Presentation Tier, Business Tier, Integration
Tier (fig.1).
Figura 1 - J2EE Pattern Catalog
Esistono
regole precise su come utilizzare i Pattern J2EE. A tale scopo,
essi sono stati raggruppati in una roadmap formattata in modo
tabellare che riassume in modo estremamente pratico e immediato
le diverse problematiche che un architect J2EE può
trovarsi ad affrontare, con l'indicazione esplicita dei Pattern
che contengono la soluzione cercata.
In figura 2 un frammento di tale roadmap, tratta proprio da
rif [1].
Figura 2 - Roadmap d'uso dei Business Tier Patterns
Un esempio
Proviamo a pensare ad un caso concreto, tanto per fissare
le idee. Immaginiamo di essere alle prese con una applicazione
multi-tier e di dove affrontare la questione della complessità
della comunicazione remota tra le componenti client e le componenti
che forniscono i servizi di business.
Ci occorre una soluzione, ma è altresì importante
che sia anche affidabile.
Dobbiamo
quindi prima di tutto tracciare sia il problema che il contesto
di riferimento.
Il contesto è quello di un sistema distribuito multi-tier
in cui i dati vengono trasmessi tramite invocazione remota
lungo i diversi "strati" (tier). Durante tale processo
le componenti client devono affrontare la complessità
dell'architettura sottostante.
Il problema è costituito quindi dalla necessità
di disaccoppiare i componenti lato presentation-tier con quelli
demandati ai servizi di business, e ciò sia per ragioni
di manutenibilità (i componenti presentation andranno
modificati ogni qualvolta sia necessario apportare modifiche
ai servizi di business) sia di efficienza (carico di lavoro
eccessivo sulla rete, in mancanza di adeguati meccanismi di
aggregazione o caching).
La soluzione che ci viene proposta in rif [1] si chiama Business
Delegate, e consiste nell' utilizzo di un semplice POJO (Plain
Old Java Object) per incapsulare l'accesso ai servizi remoti,
e nascondere quindi al client i dettagli sui servizi richiesti
(lookup, meccanismi di accesso etc).Tale POJO si servirà
poi di un Service Locator per reperire i servizi richiesti
(si noti l'uso combinato dei Pattern, giacchè anche
Service Locator lo è)
In
pratica, la problematica di business è stata "delegata"
ad apposito componente, questo è il motivo per cui
nasce la definizione Business Delegate.
Il Class Diagram della soluzione proposta è riportato
in figura 3.
Figura 3 - Class Diagram della Business Delegate
(clicca sull'immagine per ingrandire)
Troppo
complicato? Proviamo a pensare a una comitiva di amici che
decide di andare a cena tutti insieme. Ammettiamo anche che
siano d'accordo sul ristorante dove recarsi. Se ciascuno di
essi telefonasse per effettuare la propria prenotazione, si
avrebbe una grande confusione e un gran numero di chiamate.
Se, alla stessa maniera, si decidesse all'ultimo momento di
cambiare ristorante, tutti dovrebbero effettuare una nuova
serie di telefonate, quella per disdire, e quella nuova per
prenotare nel ristorante nuovo. Senza contare che tale ristorante
nuovo dovrebbe anche essere individuato, e dovrebbe andare
bene a tutti. Come semplificare le cose?
Incaricando (delegando, appunto) una delle persone della comitiva
a svolgere, per tutti, il compito di gestire la prenotazione,
e di occuparsi, nell'eventualità di un problema, di
cercare un altro ristorante dove trascorrere la serata. E
il Service Locator? Beh, tutti conosciamo le Pagine Gialle
no?
Prescindendo dal tono apparentemente scherzoso di questo esempio,
concentriamoci sul messaggio che esso intende trasmettere:
i Pattern non sono qualcosa di nuovo, ma qualcosa che discende
dalla esperienza pratica.
Pattern
e Modelli
Nel gennaio 2002 Giga Group ha presentato uno studio (rif
[4]) in cui sottolinea l'estremo valore, in termini di produttività,
efficacia ed efficienza che può avere uno scenario
caratterizzato dall'uso combinato di Pattern e Modelli:
- Modelli
per catturare in modo astratto gli aspetti rilevanti del
business da implementare
- Pattern
per gestire le trasformazioni da un modello ad un altro.
Lo
standard proposto da Object Management Group denominato Model
Driven Architecture (MDA) è basato proprio su questo
concetto: Modelli e Pattern usati in modo congiunto e sinergico.
Nei precedenti numeri di Mokabyte (vedi rif [10]) ) viene
presentata MDA, e definito e descritto un apposito insieme
di Modelli, ciascuno dedicato ad un ambito specifico, e destinati
ad offrire differenti livelli di astrazione nel corso dello
sviluppo di una applicazione.
Si parte da un Platform Independent Model (PIM), che contiene
esclusivamente aspetti di business, si passa poi ad un Platform
Specific Model (PSM), che cattura in modelli applicativi le
specificità della tecnologia scelta (J2EE, ad esempio,
ma potrebbe anche essere .NET o un'altra ancora), e si arriva
infine ad un Code Model, che traduce in codice tutto quanto
definito nel PSM (figura 4).
Figura 4 - I Modelli definiti dalla Model Driven Architecture
(clicca sull'immagine per ingrandire)
Il
problema è che ad oggi Object Management Group ha definito
i mapping tra i diversi modelli, ma non ha ancora definito
come implementare le trasformazioni da un modello ad un altro.
Questo compito è lasciato ai diversi vendor che supportano
MDA, ad esempio Compuware (www.compuware.it) che, assieme
a Sun e ad altre aziende, sta lavorando con OMG per definire
queste trasformazioni e renderle parte dello standard MDA.
Nelle
attività di definizione di tali standard, l'idea centrale
è di definire due famiglie di Pattern per gestire le
trasformazioni da un Modello ad un altro, e precisamente:
- Technology
Patterns, responsabili di tradurre automaticamente il PIM
nei diversi PSM
- Implementation
Patterns, che trasformano in codice le definizioni presenti
nei PSM
Nella
figura 5 sono schematizzate appunto tali trasformazioni.
Figura 5 - Le Trasformazioni nella Model Driven Architecture
(clicca
sull'immagine per ingrandire)
Nello
strumento OptimalJ di Compuware (www.optimalj.com e anche
rif [5]) sono presenti entrambe queste famiglie, con un ricco
repository di Pattern editabili da parte dell'architect che,
se lo desidera, può anche definire i propri.
Tutto il codice che viene generato come risultato da essi
aderisce completamente ai J2EE Patterns (per maggiori informazioni,
vedere rif [6]).
Technology
Patterns
Sono responsabili del mapping tra le specifiche di business
definite a livello PIM (Modello UML) e i modelli applicativi
che costituiscono i diversi PSM (vedere anche rif [7] per
maggiori dettagli).
I Technology Patterns non generano codice Java, sono utilizzati
piuttosto per definire a livello logico i diversi componenti
negli ambiti DBMS, Business Logic e Presentation.
Un
esempio concreto? Si pensi all'ambito DBMS.
Pensiamo ad una classe UML definita nel PIM, essa in generale
possiede un insieme di attributi che si desidera rendere persistenti.
Si utilizzano allora i Technology Patterns per creare, a partire
da tali attributi, un framework relazionale completo di struttura
tabellare, con le relative definizioni di primary key, foreign
key e colonne.
In figura 6 è mostrato appunto un frammento di Technology
Pattern che esegue le azioni descritte. L'architect potrà
poi, se lo ritiene opportuno, intervenire sulla struttura
di tale Pattern e modificarlo secondo le proprie esigenze.
Figura 6 - Esempio di Technology Pattern
(clicca sull'immagine per ingrandire)
Implementation Patterns
Nel momento in cui i modelli PSM, specifici della piattaforma
tecnologica scelta (J2EE nel nostro caso) sono definiti, vengono
ad essi applicati gli Implementation Patterns, che permettono
la generazione del codice.
Anche qui è bene riferirsi ad un esempio concreto.
Partiamo da un elemento EJB presente nel corrispondente PSM
(attenzione: un elemento EJB in un PSM non è codice,
è la definizione tramite stereotipo UML di un elemento
EJB, vedere per dettagli sempre rif[10].
A
partire da esso, l'Implementation Pattern costruisce un insieme
completo di classi Java, vale a dire una key class, una home
interface, una remote interface e una browse class, oltre
alla classe Entity Bean o Session Bean corrispondente al tipo
di elemento EJB di partenza.
Nella figura 7 si può notare l'insieme delle classi
Java risultanti da un EJBEntity Component definito in un PSM.
Figura 7 - Codice generato a partire dal PSM EJB
(clicca sull'immagine per ingrandire)
Anche
qui, come nel caso dei Technology Patterns, l'architect può
creare i propri Implementation Patterns.
A tal fine, vengono messe a disposizione una serie di funzionalità,
in particolare:
- un
modello per la definizione degli Implementation Patterns
(detto OptimalJ Meta-model)
- un
linguaggio specifico per implementarli (detto Template Pattern
Language, o TPL).
L'OptimalJ
Meta-model è basato sul formalismo UML e sulla specifica
MOF per descrivere repository ed oggetti ivi contenuti - modelli,
appunto - assieme alle regole per poterli utilizzare (rif
[8]).
L'OptimalJ Meta-model permette di "vedere" in modo
astratto sia il PIM, sia i diversi PSM. L'architect che lo
desideri, può definire qualunque Meta-model secondo
le proprie esigenze.
In figura 8 una schermata illustrativa.
Figura 8 - OptimalJ Meta-model: tree view e Meta Class
Diagram
(clicca sull'immagine per ingrandire)
Per
scrivere materialmente un Implementation Patten, il default
è ovviamente servirsi del linguaggio Java.
Al fine di poter offrire una alternativa più semplice
a questo, è stato sviluppato e messo a disposizione
all'interno di OptimalJ un linguaggio specifico per i Pattern,
denominato TPL (Template Pattern Language).
Si tratta di un linguaggio basato su template, ossia su dichiarazioni
e corpo, costituito da un ristretto ma potente insieme di
statement, con le quali è possibile dichiarare cicli,
condizioni e skeleton code, così come invocare altri
script TPL.
In figura 9 un frammento di TPL.
Figura 9 - Template Pattern Language
(clicca sull'immagine per ingrandire)
Gli
script TPL vengono successivamente tradotti da un apposito
TPL-Compiler in plain Java Classes, che costituiscono proprio
quegli implementation patterns che partendo da un PSM MOF-based
generano i corrispondenti file Java, JSP, XML e SQL.
Nella
figura 10 viene messo a confronto il medesimo Implementation
Pattern, in versione plain Java e TPL. Si può notare
come l'uso di TPL renda il lavoro dell'architect molto più
semplice, schermandolo dalla maggiore complessità dell'approccio
basato su Java.
Figura 10 - Implementation Pattern - versione Java e TPL
(clicca sull'immagine per ingrandire)
Conclusioni
Come sottolineato in rif [9], l'uso dei Pattern ha permesso
di mantenere gran parte di quelle affascinanti promesse che
i Pattern stessi avevano lasciato intravedere, sin dal loro
primo apparire; sviluppo veloce e affidabile, produttività
ed efficienza, tutte caratteristiche che sono state ampiamente
dimostrate sul campo. Si è visto d'altra parte anche
come un significativo passo avanti in termini di produttività,
affidabilità ed efficienza si ottenga facendo un uso
combinato di Pattern e Modelli, e più ancora arrivando
a definire le proprie regole, le proprie best practices, quindi
i propri Pattern, con in più la possibilità
di metterli a fattor comune per trarne il massimo beneficio
in modo sinergico. E' in tal modo che si riesce a raggiungere
il "do more with less", pensando cioè in
termini di evoluzione, non di rivoluzione.
Bibliografia
[1] Deepak Alur, John Crupi, Dan Malks - "Core J2EE Patterns
- Best Practices and Design Strategies", Java 2 Platform
Enterprise Edition Series, 2001
[2]
Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides,
"Design Patterns:Elements of Reusable Object-Oriented
Software", Addison Wesley, 1994
[3] Martin Fowler, "Analysis Patterns: Reusable Object
Models", Addison Wesley, 1997
[4]
GigaTel Report, "Application Development Tool Trends
for .NET, J2EE and Web Services", Giga Group, 2002
[5]
Compuware Lab "OptimalJ Community" - http://javacentral.compuware.com
[6]
John Crupi, Frank Baerveldt "Implementing Sun Microsystems
Core J2EE Patterns", http://javacentral.compuware.com/members/downloads/pdf/OJSunpatterns.pdf,
Compuware White Paper Series, 2004
[7]
Wim Bast "MOF 2.0 Query/View/Transformation (QVT) RFP"
http://www.omg.org/cgi-bin/doc?ad/03-03-24
[8]
Meta Object Facility (MOF) Specification, 1999
[9]
Ton Blankers - "Combining Models and Patterns: delivering
on the promise of increased IT productivity", Compuware
White Paper Series, 2004
[10]
Mokabyte - "Uso della Model Driven Architecture nello
Sviluppo di Applicazioni J2EE", parte 1 http://www.mokabyte.it/2004/07/mda-1.htm
e parte 2 http://www.mokabyte.it/2004/09/mda-2.htm)
|