La nozione di componenti con e senza stato è particolarmente importante nello sviluppo di applicazioni e sistemi
distribuiti, sebbene solo di recente sia entrata a far parte del vocabolario comune. Essenzialmente, la nozione è che
se due componenti o servizi stanno comunicando ed esistono alcuni stati gestiti dal componente del server per la durata
della conversazione con il client, un arresto anomalo nel componente del server (o un errore di rete) potrebbe
significare che il client non è in grado di completare la conversazione ed è necessario ricominciare. Inoltre, rende
meno difficile il reindirizzamento delle richieste del client ad uno di un insieme di componenti a meno che l'insieme
di componenti non condivida alcuni archivi comuni per lo stato della conversazione. Ciò è diventato un problema ben
noto nello sviluppo delle applicazioni web in cui lo stato relativo è gestito attentamente in modo da essere evitato
dove possibile e gestito dal client, dalla stessa conversazione (passando lo stato in ciascun messaggio) oppure nei
componenti dal lato server con lo stato, progettati attentamente. Ad esempio, lo stato comune per l'interazione web con
stato è il carrello degli acquisti. Gli utenti si aspettano che il carrello degli acquisti persista mentre si
allontanano brevemente dal computer, ma com'è possibile realizzare ciò con 100,000 utenti correnti?
Con ciò non si intende che i componenti con stato siano inefficienti, rappresentano semplicemente un'area possibile di
errore delle prestazioni e di rimbalzo, a meno che non vengano gestiti attentamente e sviluppati secondo gli standard
più rigorosi. Infatti, tutte le applicazioni del business contengono servizi che per propria natura gestiscono o
rappresentano entità inerentemente con stato o contengono servizi a cui è necessario accedere secondo determinate
sequenze logiche. Infatti l'architettura J2EE definisce bean di sessione separati con stato e senza stato per indicare
in modo esplicito questi problemi e definire determinate restrizioni sui componenti. Ciò conduce ad una classificazione
semplice per i servizi con stato, le ragioni per cui non è possibile non metterli al primo posto. E' possibile che un
servizio sia con stato per uno dei motivi seguenti:
Il servizio contiene lo stato per conto del client; questo è l'esempio del carrello degli acquisti. In
qualche modo, alcuni dati devono essere stati persistenti tra le chiamate tra il client ed il servizio, questi dati
sono parte della conversazione e perciò, senza una particolare attenzione, è possibile collegare un client ad una
risorsa del server fornita.
Il servizio gestisce una risorsa con stato; in questo caso il servizio tende a gestire un insieme di risorse
o di entità, ciascuna delle quali con stato. Ad esempio un ordine dell'utente ha lo stato, uno scambio di rete ha lo
stato e così via. Pertanto, l'interfaccia per un servizio che gestisce un tale oggetto chiudendo o rimandando un ordine
o riavviando uno scambio, è modificare lo stato di un'entità particolare.
Il servizio ha un protocollo con stato; in questo caso le operazioni che fornisce hanno un ordinamento
logico. Ad esempio le operazioni login(), dostuff() e logoff(), che è possibile significano che è impossibile
chiamare l'operazione dostuff() o logoff() senza l'operazione login().
Un'altra forma di stato è stata trovata in molte architetture dei componenti, ma non è applicabile al mondo dei
servizi, è la nozione di stato transazionale. E' possibile nel mondo dei componenti indicare che un metodo get() e
update() potrebbero essere chiamati su un componente da un client all'interno dell'ambito di una transazione creata e
mantenuta dal client. Si presume che il metodo update() modifichi alcuni degli archivi transazionali sottostanti. Ciò
richiede quasi sempre l'intervento della piattaforma del middleware per coordinare le transazioni e garantire che i
metodi che richiedono le transazioni vengano chiamati da un client con una transazione aperta. Per i servizi, non è
considerato appropriato o desiderabile seguire un modello in cui le transazioni nel senso del commit classico a due
fasi vengano tenute aperte su alcune chiamate del servizio. Sono ora in fase di sviluppo degli standard per le
transazioni attraverso le chiamate del servizio, ma seguono un paradigma fondamentalmente diverso (compensazione) e
vengono supportati differentemente dalle piattaforme del middleware.
La tecnica più ovvia, suggerita precedentemente, per lo sviluppo corretto dei servizi con stato è quella di esternare
lo stato del servizio, rendendo così non solo esplicito che il servizio ha uno stato, ma che è possibile identificare
questo stato come parte della specifica di servizio. Ciò verrà trattato per le due classi di servizi con stato, di
seguito.
Poiché la maggior parte dei servizi del software verrà sviluppata in cima ad una piattaforma esistente del middleware
come J2EE o Microsoft .NET, all'interno di tali architetture dono descritte tecniche di implementazione di aiuto per la
gestione dello stato. Pertanto, questa linea guida focalizza l'attenzione sulle tecniche di progettazione per
determinate classi di servizi con stato. E' senz'altro importante notare che questa non è affatto una nuova area
problematica. Nello sviluppo del mainframe, lo sviluppo di transazioni conversazionali o non conversazionali in CICS
(IBM Customer Information Control System) con i client con schermo verde (in realtà 3270 terminali) è stato appreso e
descritto da sviluppatori, progettisti ed architetti per molti anni.
Questo è il caso in cui il suggerimento più semplice è quello, in primo luogo, di evitare la situazione. Laddove
possibile, se una progettazione richiede la gestione dello stato durante una conversazione tra un servizio e gli
utenti, è meglio decidere di intraprendere un altro approccio. In caso contrario, esternare questo stato passando tutti
i dati sullo stato richiesti tra il servizio e l'utente con ogni messaggio che riporti l'intera conversazione. Questo
approccio potrebbe significare che la dimensione dei messaggi è aumentata in modo significativo, ma il servizio stesso
ora è interamente senza stato. Un altro approccio è di portare un identificativo di conversazione all'interno di
ciascun messaggio e di conservare tutti gli stati delle conversazioni in un archivio permanente come un database. Se
ciò ha conseguenze significative per le prestazioni dal lato server, potrebbe invece contrastare le prestazioni della
rete e del client salvate con i messaggi di dimensioni minori.
Uno degli scopi principali del rendere questi servizi senza stato è quello di essere capaci di fornire un insieme di
servizi identici che possano servire qualsiasi richiesta utilizzando le tecniche di bilanciamento del carico per
distribuire i client. Questo bilanciamento del carico è possibile se tutto lo stato viene esternato completamente o
persiste in un archivio comune.
In questo caso, viene trattata la gestione delle risorse stesse che hanno uno stato esplicito. Infatti, lo stato
rappresenta un aspetto importante della stessa risorsa. E' possibile che venga descritto lo stato della risorsa,
l'ordine dell'utente o lo scambio di rete su menzionati utilizzando una macchina di stato, descrivendo non solo gli
stati validi ma anche il modo in cui le operazioni fornite dal servizio interessano lo stato delle risorse sottostanti.
Tuttavia nel realizzare questa descrizione, è importante notare che questo stato è una parte intrinseca della risorsa.
Tuttavia, ciò potrebbe non essere espresso in modo esplicito nel modello delle informazioni che lo rappresenta. E'
inoltre importante notare che nella gestione di ogni insieme di entità, è possibile identificare se ogni risorsa
singola che si sta utilizzando dispone o meno di un identificativo esplicito.
Si noti che dove un servizio rappresenta un accesso o una query allo stato di un'entità fisica come uno scambio di rete
o un elemento di controllo del processo, non è possibile considerare di esternare lo stato dell'entità. Lo stato di una
valvola è noto solo interrogando la valvola. Sebbene sia possibile costruire e rispondere con un messaggio che descrive
lo stato corrente della valvola, questa non sarà una situazione permanente. Lo stato della valvola può cambiare durante
la trasmissione o l'elaborazione di questo messaggio.
Nell'area dei servizi web, esiste un insieme di standard emergenti noti come WSRF (Web Services Resource Framework) che
trattano i modelli dei servizi con stato e gli approcci allo stato di codifica, particolarmente nel caso dei servizi
che rappresentano la gestione delle risorse con stato. Per ulteriori informazioni, consultare il sito IBM WS-ResourceFramework.
L'esempio su menzionato coinvolge un servizio che dispone di sequenze logiche per le operazioni che fornisce. Molti
servizi forniranno interfacce simili. In alcuni casi, ciò riporta alle risorse con stato tranne nel caso in cui
l'ordinamento delle operazioni è basato sullo stato della risorsa gestita. In questo caso, l'ordinamento è basato sulla
stessa conversazione. L'esempio seguente mostra una specifica di servizio con alcuni protocolli associati, verranno
mostrate prima la specifica strutturale quindi una macchina di stato che descrive la specifica comportamentale.
L'ordine di acquisto può essere in uno degli stati {Open, Canceled, Fulfilled, Closed} e modifica lo stato in
base alle operazioni fornite nella specifica precedente. Viene inoltre indicato che nel caso dell'auto transizione
sullo stato Open, si esegue l'operazione OrderChanged inviando le notifiche della modifica.
In molti casi in cui i servizi vengono sviluppati all'interno di un business singolo e di un ambito tecnico, potrebbero
non venire sviluppate le specifiche comportamentali dettagliate o potrebbero essere descritte meno formalmente in un
testo. Dove i servizi sono esposti al di fuori di un tale scopo, ad esempio tra le partizioni, rappresentano una
specifica logica per l'interazione tra le partizioni e dovrebbero essere sviluppati molto dettagliatamente. Inoltre, le
specifiche dettagliate consentono un riutilizzo più efficace ed efficiente da parte degli utenti quando si prevede di
utilizzare i servizi frequentemente.
|