MokaByte 89 - 8bre 2004 
Perchè usare i Pattern
Un design affidabile non basta al successo di una applicazione
di
Doriano
Gallozzi

La piattaforma J2EE, così ricca di svariate tecnologie che in essa sono andate - e vanno tuttora - a confluire, presenta a chi deve utilizzarla in pratica una serie di problematiche su come impiegarla al meglio. Tale questione è molto più generale, e trae le proprie origini da ambiti anteriori a J2EE: approcciare una problematica complessa riuscendo a fornire soluzioni valide - perchè frutto dell'esperienza di chi le ha messe a punto e provate - e soprattutto riutilizzabili, qualora il medesimo contesto di riferimento si ripresenti. Tali soluzioni generalizzate sono dette Pattern, e sono oggetto di questo articolo. Esamineremo cosa sono i Pattern, analizzandoli in dettaglio e mostrando come possono effettivamente costituire un potente mezzo nelle mani di chi progetta e sviluppa software. Successivamente verrà mostrato come trarne il massimo beneficio, quando si utilizzino assieme ai Modelli, secondo quanto previsto dalla Model Driven Architecture, la metodologia di sviluppo proposta da Object Management Group. Nella parte conclusiva, infine, parleremo di personalizzazione dei Pattern, ossia della possibilità di definire e sviluppare i propri.

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)

 


MokaByte® è un marchio registrato da MokaByte s.r.l. 
Java®, Jini® e tutti i nomi derivati sono marchi registrati da Sun Microsystems.
Tutti i diritti riservati. E' vietata la riproduzione anche parziale.
Per comunicazioni inviare una mail a info@mokabyte.it