Nella nostra serie sulla architettura e sulle tecnologie per la realizzazione di applicazioni Java EE, cominciamo ad affrontare lo studio del business service layer, spiegando collocazione e funzionamento di questo strato e introducendo i concetti alla base del framework Spring.
Introduzione
Nel presente articolo proseguiamo il nostro ideale viaggio tra gli strati dell’applicazione, fermandoci a quello immediatamente adiacente allo strato di persistenza di cui si è parlato nei precedenti numeri: il business service layer. Inutile dire che questo layer è quello forse di maggiore importanza in quanto proprio qui vengono implementate le business rules, la logica applicativa, in poche parole, le regole del nostro sistema. È evidente come una progettazione e una implementazione corretta di questo strato applicativo sia una delle chiavi del successo di un sistema.
Nello stile della serie, eviteremo di addentrarci nei minimi dettagli implementativi ma piuttosto cercheremo di fornire alcuni elementi di riflessione e alcune linee guida che aiutino l’architetto e lo sviluppatore ad affrontare nella maniera corretta il loro compito. Come per qualsiasi layer applicativo, esistono anche per quello di business molteplici modalità di implementazione. Partiremo da una analisi teorica dei principi alla base di una buona architettura, per poi mostrare come questi principi possano essere soddisfatti mediante l’utilizzo di Spring, uno dei framework più in voga al momento. Va subito chiarito che Spring, a differenza di altri noti framework, non indirizza esclusivamente lo sviluppo dello strato di business, essendo un framework che può essere usato in tutti i layer applicativi, presentation compreso. La trattazione che faremo riguardo Spring è calata per ora solo ed esclusivamente all’implementazione dello strato di business visto che è di questo che ora ci occupiamo.
I componenti fondamentali dell’architettura
Negli articoli VI e VII della serie, dedicati agli aspetti architetturali [4] [5], si è già parlato di pattern e dell’utilizzo di questi per la definizione di una corretta architettura applicativa, per cui si faranno in questa sede solo alcuni accenni a concetti di base indispensabili per la comprensione di quanto viene dopo.
L’architettura di un’applicazione enterprise può essere molto complessa e prevedere l’utilizzo di numerosi pattern in base alle esigenze e alle caratteristiche del sistema che si va a costruire. Ma schematizzando, per quanto complessa possa essere un’architettura applicativa, essa prevede sempre tre layer fondamentali:
- il presentation layer
- il business service layer
- il data access layer (o persistence layer)
Non a caso in questa serie di articoli stiamo seguendo un percorso che ci porta ad affrontare le problematiche relative a questi layer applicativi uno dopo l’altro. In ciascun layer ci potrà essere ovviamente ulteriore complessità ed eventualmente una ulteriore scomposizione, ma è evidente che questi sono i tre elementi costitutivi di qualsiasi applicazione costruita secondo principi architetturali validi.
Sullo strato di persistenza abbiamo già detto: esso si compone di oggetti che hanno il compito di interagire con uno storage di persistenza, quasi sempre un database relazionale.
Il layer di business è quello invece che espone a un utilizzatore esterno la logica applicativa del sistema sotto forma di interfacce ben definite. L’utilizzatore dello strato di business è tipicamente il layer di presentation, indipendentemente da come esso sia realizzato.
È evidente che, da quanto detto, alcuni concetti come quello di pensare a una architettura a layer sono dati per scontati. È ben provato che questo approccio, per sistemi complessi, conferisce al sistema le caratteristiche di scalabilità , modularità, riuso , che una architettura non-layered non può garantire.
A parte ciò appare altresì evidente come la corretta progettazione del layer di business service è fondamentale e deve corrispondere ad alcuni principi di base indipendenti dalle modalità di implementazione.
Tra i numerosi principi di base, di seguito ne sono elencati alcuni che a mio avviso sono assolutamente imprescindibili per il layer di business service:
- indipendenza dal layer di presentation e da quello di persistenza
- definizione in termini di interfacce e non di classi
- semplicità e completezza
Lo strato di business deve essere assolutamente indipendente dalla implementazione dello strato di persistenza e deve poter essere utilizzato senza modifiche con diverse implementazioni dello stesso; allo stesso modo deve essere indipendente da quello di presentation e quindi non deve essere assolutamente legato ad alcuna tecnologia di presentazione ma anzi deve poter essere utilizzato in maniera completamente indipendente da queste.
Affinche’ questo obiettivo possa essere raggiunto il layer deve seguire quello che è poi un principio di corretta progettazione object-oriented, ovvero quella di esporre tutti i servizi di business del sistema mediante interfacce e non classi concrete. In questo modo, una volta definiti correttamente i “contratti” tra i diversi layer applicativi, essi saranno indipendenti dalla loro implementazione ed utilizzabili in sistemi e contesti diversi.
Non da meno è importante la completezza, nel senso che il business service layer deve esporre tutte le funzionalità del sistema e la semplicità nel senso che la complessità del layer non deve derivare dalla complessità della sua modalità di implementazione ma solo dalla complessità delle regole di business che occorre implementare.
Oltre a questi principi di base esistono ovviamente numerose altre caratteristiche che un layer di business deve rispettare; deve ad esempio gestire operazioni transazionali, deve essere scalabile, e quindi possibilmente stateless, e facile da sviluppare e testare.
Il framework Spring
Come per lo strato di persistenza, esistono ovviamente molti modi di implementare lo strato di business e l’utilizzo di Spring è solo una delle possibilità. Le ragioni alla base della nascita di Spring si collocano nel periodo in cui lo standard J2EE per l’implementazione dello strato di business, gli EJB, mostrava alcune problematiche che ora proprio grazie all’impulso di framework nati nella comunità open-source si stanno superando.
Gli EJB, sin dalle loro prime specifiche, hanno sempre suscitato nel mondo degli sviluppatori J2EE molte controversie perche’, pur costituendo una tecnologia ricca di ottime caratteristiche, il suo utilizzo conduceva inevitabilmente a un incremento di complessità a volte inutile per la gran parte delle applicazioni.
Le motivazioni che hanno portato alla nascita di Spring sono contenute nel famoso libro [1] nel quale Rod Johnson illustra i concetti architetturali che sono alla base di Spring. Il progetto open source nacque a partire dal codice infrastrutturale pubblicato insieme al libro e da quel momento in poi Spring è divenuto senza ombra di dubbio il framework di maggior successo e oggi il più utilizzato nel mondo Java EE.
In estrema sintesi, l’idea alla base era quella di mostrare come fosse possibile costruire sistemi affidabili e scalabili senza EJB e senza ricorrere ad architetture distribuite, dimostrando che con l’utilizzo sapiente di semplici POJO si potevano ottenere i medesimi risultati di quanto allora si potesse fare con gli EJB (che oggigiorno vanno anche essi verso una semplificazione).
Nel paragrafo seguente introdurremo brevemente il pattern di base su cui Spring è fondato ma il suo innegabile successo è stato determinato proprio dal fatto che esso nasceva già con l’obiettivo di soddisfare tutti quei principi di cui si parlava prima:
- Spring è completo e modulare. Ha un architettura a layer che ci permette di scegliere solo quello che serve del framework senza dover per forza fare una scelta del tipo “o tutto o niente”.
- Spring è semplice. Spring utilizza puri e semplici POJO, ovvero normali classi Java. Non impone quindi l’implementazione di astruse interfacce ne’ vincola ad esso il proprio codice applicativo. È semplice da testare a differenza di quanto accade con molti framework a componenti.
- Spring è disegnato in modo da imporre le minime dipendenze alla propria applicazione.
- Spring è leggero ma fornisce tutti i servizi necessari a una applicazione enterprise.
- Spring impone uno stesso stile architetturale a diverse aree di sviluppo.
Tra tutte le caratteristiche elencate, quella che forse colpisce immediatamente chi per la prima volta si avvicina a Spring è la sua semplicità. A differenza di altri framework, Spring si può apprendere davvero in tempi rapidissimi e conduce alla scrittura di codice semplice e comprensibile. Nonostante questa intrinseca semplicità, i vantaggi che si ottengono dal suo utilizzo sono davvero molteplici e ciò a mio parere è la ragione del suo grande successo: grandi benefici e grande semplicità.
Inversion of Control
Come sappiamo una applicazione di livello enterprise necessita di numerosi servizi quali la gestione delle transazioni, la sicurezza, l’object-pooling e altri. In generale quindi una applicazione viene eseguita in un container ossia dentro un “contenitore”, un ambiente di esecuzione che fornisce tutti i servizi infrastrutturali necessari al nostro codice applicativo. Un esempio di ciò è un Web Container che è l’ambiente di esecuzione di Servlet e JSP oppure un EJB Container nel quale viene effettuato il deploy degli EJB.
Spring è essenzialmente un tecnologia che consente di costruire applicazioni usando semplici oggetti Java, anche detti POJO (Plain Old Java Object). Anche nel caso di Spring gli oggetti sono gestiti da un container che per sue caratteristiche è però più leggero e per questo viene indicato come lightweight container.
Lo stesso Rod Johnson in [2] indica cosa si intenda per container leggero:
- un container che abbia la minima invasività e quindi che non introduca dipendenze negli oggetti da esso gestiti;
- che sia veloce nello start-up;
- che non necessiti di procedure di deployment degli oggetti;
- che sia utilizzabile in contesti applicativi differenti quali applicazioni web e stand-alone;
- che abbia un minimo footprint sulla propria applicazione.
Tutte queste caratteristiche sono pienamente soddisfatte da Spring e dal suo IoC container, dove IoC sta per “Inversion of Control”, il pattern di base sul quale è costruito Spring e che consente di ottenere l’indipendenza del codice dal container che abbiamo elencato come requisito fondamentale.
L’IoC è un principio utilizzato da molti framework , in base al quale è il codice del framework che invoca il codice applicativo secondo quello che viene anche chiamato l’Hollywood Principle “Don’t call us, we call you” (che deriva dalla tipica frase detta da registi e produttori agli attori che si presentano ai provini: “Le faremo sapere…”).
Il tipo di IoC su cui Spring si fonda è la cosiddetta Depenedency Injection ovvero quel principio in base al quale le dipendenze tra gli oggetti della nostra applicazione vengono create dal container e non dagli oggetti stessi.
Tutti gli oggetti di una applicazione hanno bisogno di altri oggetti per svolgere i propri compiti. Ciò significa che comunemente un singolo oggetto deve andare a crearsi le dipendenze con gli altri eseguendo operazioni di lookup. Queste operazioni di lookup inevitabilmente introducono delle dipendenze scolpite nel codice che rendono gli oggetti del nostro sistema dipendenti dagli altri e quindi scarsamente riutilizzabili. Con il concetto di Dependency Injection, il meccanismo si ribalta (qui sta l’inversione di controllo) in quanto le dipendenze tra gli oggetti vengono configurate esternamente al codice, ad esempio in file XML, e successivamente inietatte dal container IoC allo start-up. Questo significa che posso sviluppare il mio sistema utilizzando dei semplici POJO, dotati di opportuni costruttori e metodi setter, senza dovermi preoccupare delle dipendenze con altri oggetti. Sarà il container mediante la setter injection o la constructor injection a costruire tutte le dipendenze necessarie.
Questi concetti si chiariranno quando daremo nei prossimi articoli alcuni esempi, ma è importante sottolineare che questo approccio favorisce la costruzione di sistemi nei quali gli oggetti siano altamente disaccoppiati e quindi realmente riutilizzabili in contesti diversi dal sistema per il quale sono stati sviluppati.
Vedremo come tutto ciò, che sembra forse molto astruso e complicato, si traduca a livello di implementazione e di scrittura di codice in qualcosa di talmente semplice che quasi si stenta a credere come un principio così semplice possa portare a simili benefici.
Conclusioni
Nel presente articolo abbiamo iniziato la trattazione del business service layer, lo strato applicativo nel quale vengono implementate le regole di business del sistema. Abbiamo introdotto alcuni concetti di base per una buona implementazione di questo layer applicativo per poi iniziare a introdurre il framework Spring come possibile tecnologia di implementazione. Da questo articolo introduttivo, ahimè molto teorico ma necessario, andremo a vedere come si possano implementare con Spring i pattern architetturali presentati negli articoli della serie e forniremo un esempio di implementazione che chiarirà, speriamo, il perche’ Spring abbia avuto un simile successo nel mondo dei framework Java EE.
Riferimenti
[1] Rod Johnson, “Expert one-on-one. J2EE Design and Development”, 2002 Wrox Press
[2] Rod Johnson – Juergen Holler, “Expert one-on-one. J2EE Development without EJB”, 2004, Wrox Press
[3] Rod Johnson, “Introduction to the Spring Framework 2.5”, The ServerSide.Com, ottobre 2007
[4] Giovanni Puliti, “Il programmatore e le sue API – VI Parte: L’architettura del sistema”, MokaByte 132, settembre 2008
[5] Giovanni Puliti, “Il programmatore e le sue API – VII Parte: Ancora sull’uso dei pattern nell’architettura”, MokaByte 133, ottobre 2008