Introduzione
Possiamo
definire un'architettura come "un insieme di decisioni
significative sull'organizzazione di un sistema software,
sulla selezione degli elementi strutturali e sulle interfacce
di cui il sistema è composto, insieme con i comportamenti
così come specificati nelle collaborazioni tra questi
elementi (...)"[1]. Di conseguenza uno stile architetturale
deve specificare un insieme di regole per il disegno dei componenti,
per la definizione delle relative interfacce e per la definizione
delle modalità di interazione tra essi.
SOA
è uno stile architetturale basato sul concetto di Servizio,
che rappresenta quindi l'elemento strutturale su cui le applicazioni
vengono sviluppate. Occorre quindi definire cosa si intende
per servizio.
Servizi
Un
servizio è, in prima analisi, una funzionalità
di business realizzata tramite un componente che rispetta
un'interfaccia. Ma qual'è la differenza tra applicazioni
sviluppate a servizi rispetto a
quelle sviluppate seguendo "normali" paradigmi di
programmazione distribuita o tecnologie già ampiamente
utilizzate?
In passato, infatti, sono stati presentati spesso modelli
di sviluppo incentrati su componenti con l'obiettivo del riuso.
La finalità di di queste tecnologie è stata
di cercare di creare un mercato di componenti per favorirne
la diffusione. Questo tipo di politica ha in parte fallito
soprattutto perchè i modelli di programmazione proposti
hanno portato alla definizione di componenti la cui possibilità
di utilizzo era limitata ad un certo ambito tecnologico. Dal
punto di vista della logica funzionale che questi moduli dovrebbero
implementare per essere commerciabili, questa deve essere
sufficentemente complessa per giustificarne l'aquisto: spesso
si è verificato che rispetto a prendere un componente
prodotto esternamente, capirne l'interfaccia e adattarlo ai
propri scopi e ai propri processi è preferibile svilupparsi
il componente da zero.
Inoltre,
mentre oggi è chiaro che la necessità di sistemi
informativi complessi è quella di avere componenti
in grado di comunicare tra loro in maniera eterogenea e disaccoppiata,
le tecnologie orientate al "mercato dei componenti"
hanno spesso dato più importanza alla possibilità
di riconfigurare i moduli sviluppati per essere utilizzati
su applicazioni diverse piuttosto che a sottolineare le possibilità
di integrazione.
SOA
parte dalle considerazioni che hanno portato al fallimento
del riuso dei componenti in ambito enterprise e definisce
una serie di proprietà che i servizi devono soddisfare
per essere realmente riusabili e facilmente integrabili in
ambiente eterogeneo:
- I
Servizi devono essere ricercabili e recuperabili dinamicamente.
Chi
necessita di un servizio deve essere in grado di ricercarlo
sulla base dell'interfaccia e di chiamarlo a tempo di esecuzione.
Questo tipo di meccanismo permette un forte disaccoppiamento
tra chi richiede la funzionalità e chi la fornisce,
permettendo inoltre di cambiare l'entità che esegue
il servizio a tempo di esecuzione in maniera trasparente
rispetto al chiamante.
- I
Servizi devono essere autocontenuti e modulari.
Per
essere realmente riusabili, è importante che i servizi
non siano legati al contesto o allo stato di altri servizi.
Ovviamente le applicazioni richiedenti necessitano di avere
stato persistente tra le invocazioni ma questo deve essere
separato dal fornitore di servizio. In pratica non dovrebbe
esserci uno stato conversazionale nelle chiamate tra chi
richiede il servizio e chi fornisce il servizio o, per usare
una terminologia più precisa, i servizi dovrebbero
essere stateless.
- I
Servizi devono definire delle interfacce esplicite e indipendenti
dall'implementazione
Deve
essere possibile invocare servizi in maniera indipendente
dal linguaggio e dalla piattaforma. Questo si può
ottenere definendo delle interfacce che possono essere invocate
tramite protocolli compresi da tutti.
- I
Servizi devono essere debolmente accoppiati (loosely coupled).
L'accoppiamento
si riferisce al numero di dipendenze tra i moduli. Ogni
tipo di architettura ben definita è orientata ad
avere accoppiamento debole, cioè un numero di dipendenze
tra le entità basso e ben controllato. Un sistema
formato da componenti fortemente accoppiati è più
rigido e difficilmente modificabile.
- I
Servizi devono avere un'interfaccia distribuita e devono
essere accessibili in maniera trasparente rispetto all'allocazione.
Un
servizio con un'interfaccia distribuita può essere
pubblicato sulla rete, diventando così disponibile
ai componenti che lo vogliano utilizzare. L'accesso tramite
la rete permette inoltre di avere trasparenza rispetto alla
reale allocazione del servizio.
- I
Servizi devono avere preferibilmente un'interfaccia a "grana
grossa" (coarse-grained).
Un
servizio che corrisponda ad un'unica chiamata e un'unica
esecuzione complessa ha in genere dei vantaggi rispetto
a una serie di chiamate a tanti servizi più piccoli.
In questo modo infatti vengono fatte meno chiamate remote
(tipicamente poco efficienti), non c'è bisogno di
trovare un sistema per mantenere lo stato tra più
chiamate ed è più semplice gestire problematiche
legate al fallimento della comunicazione remota. Comunque
può essere sensato definire servizi "piccoli"
soprattutto se questi servizi possono essere utilizzati
per essere composti in altri servizi, infatti...
- I
Servizi devono essere componibili.
Dal
punto di vista SOA le applicazioni sono aggregazione di
servizi. E' quindi importante disegnarne le interfacce in
modo che corrispondano a funzioni di business riusabili,
ovvero a servizi indipendenti e autocontenuti. La composizione
di servizi per la produzione di applicazioni o di servizi
più complessi viene indicata con il termine Service
Orchestration.
Una architettura SOA è quindi una architettura software
che definisce un modo di descrivere i componenti con caratteristiche
ben specifiche orientate al riutilizzo e all'integrazione.
E' importante notare che a livello implementativo la tecnologia
utilizzata per lo sviluppo dei servizi non è determinante
finchè vengono rispettate queste caratteristiche.
Ricerca
e invocazione di servizi
Abbiamo
detto che un servizio deve definire un'interfaccia pubblicabile
sulla rete, ricercabile e invocabile in maniera indipendente
dal linguaggio e dalla piattaforma.
Per ottenere questi requisiti, le applicazioni SOA definiscono
dei ruoli:
- Service
Requester : l'entità che richiede il servizio; può
essere un modulo di un'applicazione o un altro servizio.
- Service
Provider: l'entità che fornisce il servizio e che
ne espone l'interfaccia.
- Service
Contract : definisce il formato per la richiesta di un servizio
e della relativa risposta.
- Service
Broker : Direttorio in rete dei servizi consultabili.
Poichè
i servizi devono essere ricercati e recuperati dinamicamente,
il Service Contract deve essere pubblicato su un Service Broker
dal Service Provider. Il Service Requester deve richiedere
al Service Broker il Contract relativo al servizio richiesto,
che utilizzerà per eseguire il servizio tramite un
protocollo di trasporto.
Figura 1 - Ricerca e invocazione di servizi
Questo modello si può estendere con l'utilizzo di un
Service Proxy, che non è altro che un'implementazione
del pattern proxy [2] per i servizi. In questo caso il proxy
può essere messo a
disposizione dal Service Provider per i Service Requester
e può essere utile per nascondere l'operazione di ricerca
del servizio e mantenere una cache dei risultati delle ricerche
già fatte.
La comunicazione in questo caso è a carico del proxy,
che può inoltre implementare dei meccanismi di failover-recovery.
Ad esempio a seguito di un fallimento della comunicazione
con un servizio, il Service Proxy può cercare un'altra
entità che espone lo stesso servizio e chiederne l'esecuzione,
tutto questo in maniera trasparente per il Service Requester.
Figura 2 - Service Proxy
Una
volta che il Service Requester ha un riferimento al servizio
che vuole utilizzare, come avviene la chiamata? Sia il requester
che il provider devono utilizzare un protocollo di comunicazione
che sia comprensibile per entrambi. Questo protocollo deve
essere deciso sulla base dell'ambiente di utilizzo e dei requisiti
in termini di efficienza e robustezza. Ad esempio nel caso
di integrazione
spesso la soluzione più interessante è utilizzare
protocolli di messaging asincrono [3].
Nulla
vieta inoltre che un servizio possa supportare la possibilità
di essere invocato tramite più protocolli (Multiprotocol
Service Invocation). In linea di principio, un servizio potrebbe
essere definito una sola volta tramite l'interfaccia e avere
molte implementazioni che supportano diversi protocolli di
accesso. In parole povere, se un servizio è "ordina
una pizza", avere Multiprotocol Service Invocation equivale
a avere la possibilità di ordinare una pizza tramite
telefono, e-mail, telegramma, fax, ecc... Questo è
importante in un ambiente in cui occorre fornire funzionalità
a componenti che "parlano" lingue diverse.
SOA
e Web Services
I
concetti definiti da SOA non sono legati ad una tecnologia
particolare, tuttavia i Web Services rappresentano un modo
molto adatto e basato su standard di esporre servizi.
In
questo tipo di implementazione le interfacce dei servizi sono
definite tramite WSDL (Web Services Description Language)
che possono essere pubblicate tramite UDDI (Universal Description
Discovery and Integration). La comunicazione avviene normalmente
tramite messaggi SOAP scambiati tramite HTTP. WSDL comunque
supporta la possibilità di utilizzare anche altri protocolli
di comunicazione permettendo quindi di avere Multiprotocol
Service Invocation.
Riassumendo,
il mapping tra le entità SOA definite e i WS è
molto semplice:
Conclusioni
In
questa breve presentazione abbiamo definito le caratteristiche
che i servizi di un'applicazione SOA devono soddisfare. Si
sono inoltre brevemente introdotti i Web Services come soluzione
utile a sviluppare applicazioni service-oriented.
Nei prossimi articoli verranno presentate le tecnologie che
rappresentano lo stato dell'arte dell'integrazione a servizi
con Web Services in ambito J2EE e verranno proposti esempi
pratici.
Bibliografia
[1]
Booch, Rumbaugh, and Jacobson - "The UML Modeling Language
User Guide", Addison-Wesley
[2] Gamma, Helm, Johnson, Vissides - "Design patterns
: elements of reusable object-oriented software" , Addison-Wesley
[3] Hohope, Woolf - "Enterprise Integration Patterns",
Addison-Wesley
[4] BEA su SOA: http://dev2dev.bea.com/technologies/soa/index.jsp
[5] IBM su SOA: http://www-106.ibm.com/developerworks/webservices/newto/
[6] Microsoft su SOA: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnmaj/html/aj2service.asp
|