Analizzata la parte relativa alla richiesta di acquisto vedremo, in questo articolo, come progettare la parte relativa alla gestione degli ordini di acquisto avvalendoci ancora di alcuni importanti pattern d‘integrazione.
Nello scorso articolo (vedere [1]) si è visto come utilizzare in modo organico alcuni pattern d‘integrazione (vedere [2] e [3]) al fine di ottimizzare il design dell‘applicazione e-commerce d‘esempio riguardante la vendita di articoli sportivi on-line.
Analizzata la parte relativa alla richiesta di acquisto vedremo, in questo articolo, come progettare la parte relativa alla gestione degli ordini di acquisto avvalendoci ancora di alcuni importanti pattern d‘integrazione.
Gestione dell‘ordine di acquisto
Una volta ricevuti i messaggi relativi agli ordini di acquisto bisogna processarli per verificare:
- la disponibilità dei prodotti richiesti nell‘ordine di acquisto
- l‘opportuna disponibilità economica dell‘acquirente
Di fatto le attività di verifica della disponibilità dei prodotti e della disponibilità economica del richiedente, piuttosto che farle in sequenza, possono essere effettuate in contemporanea e quindi in modo più efficiente.
Per “parallelizzare” le due operazioni sfruttiamo le caratteristiche del canale Publish Subscribe in modo tale da inviare le medesime informazioni a più destinatari.
Il pattern Publish-Subscribe Channel prevede l‘invio del medesimo messaggio a più destinatari.
Nel nostro esempio questo si traduce nell‘inviare il messaggio dell‘ordine di acquisto sia alla componente applicativa che deve verificare l‘effettiva possibilità di acquisto da parte del client, sia alla componente che deve invece verificare l‘effettiva disponibilità degli elementi da comprare.
L‘ordine può contenere più elementi (item) da acquistare. Ogni singolo item deve quindi essere controllato per verificarne l‘effettiva disponibilità nel magazzino.
Si può quindi procedere con un unico controllo dell‘ordeine o a parallelizzare ulteriormente l‘operazione dividendo (split) il messaggio contenente gli N item in N messaggi diversi per poi controllarli in contemporanea. Ovviamente la seconda soluzione è più conveniente da un punto di vista di performance ma richiede di dividere l‘ordine in N sotto-ordini, cioè un ordine per ogni item. Inoltre bisogna essere sicuri che una volta diviso il messaggio (Pattern Splitter) si possa essere in grado poi di aggregarlo (Pattern Aggregator) secondo una opportuna logica di correlazione.
Supponendo che l‘ordine abbia come identificativo un customer id (l‘identificativo del client acquirente) bisogna provvedere ad inserire nel messaggio un nuovo identificativo order id (l‘id dell‘ordine di acquisto) al fine di potere correlare i singoli item all‘ordine dell‘acquirente. Questo ci permetterà di effettuare lo split del messaggio e la relativa successiva aggregazione.
Aggiungiamo quindi delle informazioni al messaggio originario provvedendo ad un arricchimento dello stesso al fine di potere permettere una gestione parallela del check di ogni item.
Il pattern Content Enricher prevede di arricchire le informazioni contenute in un messaggio con dati aggiuntivi al fine di inserire nel messaggio le informazioni mancanti per essere correttamente processato dal destinatario.
A questo punto è possibile suddividere l‘ordine in tanti sotto-ordini quanti sono gli elementi contenuti nell‘ordine.
Il pattern Splitter divide un messaggio composito contenente diversi elementi in una serie di messaggi individuali, ognuno contenente I dati relativi al proprio elemento.
Suddiviso l‘ordine in tanti sotto-ordini correlate tra loro mediante un order-id, bisogna provvedere ad inoltrare il messaggio all‘opportuno controllore in base alla tipologia dell‘item.
Per fare questo introduciamo il pattern Content-based Router.
Il pattern Content-based Router permette di recapitare il messaggio al corretto destinatario attuando l‘opportuna logica di routing analizzando il contenuto del messaggio.
L‘algoritmo di routing può avvenire in base all‘esistenza o meno di specifici dati o in base a determinati valori di taluni campi o addirittura in base al contenuto del payload del messaggio.
Nel nostro esempio, il CBR dovrà inoltrare, in base alla tipologia dell‘elemento da acquistare (maglietta di Football Americano o di Basket), il messaggio all‘opportuno controllore (NFL o NBA).
Il controllore dovrà verificarne l‘effettiva disponibilità dell‘articolo (item) richiesto in magazzino.
Una volta analizzati tutti gli item dell‘ordine, bisogna riaggregare le informazioni per ricavare la situazione globale dell‘ordine.
Per fare questo si usa una Aggregatore.
Il pattern Aggregator combina i messaggi relativi a operazioni individuali in un unico messaggio composito. Di fatto il messaggio finale è un “distillato” di N messaggi individuali. L‘aggregatore è un componente Stateful che “colleziona” i vari elementi fino a che la composizione del messaggio finale non è completa per poi inviarlo all‘opportuno destinatario che si aspetta di ricevere un unico messaggio composto.
Da notare come il messaggio che il Content-Based Router invia al sistema di controllo inventario non è un Document Message ma bensì un Command Message. Infatti in questo caso si incapsula nel messaggio la richiesta di attuare l‘azione di controllo disponibilità dell‘item.
Il pattern Command Message prevede di incapsulare in un messaggio la descrizione di un comando da impartire ad un‘altra applicazione come ad esempio la richiesta di invocazione di una procedura / servizio remoto.
Siamo arrivati ormai alla conclusione dell‘esempio.
Abbiamo parallelizzato i controlli di ogni singolo elemento (item) dell‘ordine ed il controllo della disponibilità economica dell‘utente.
Abbiamo quindi capito se il client ha le possibilità economiche per l‘acquisto di tutti gli item dell‘ordine e se gli item richiesti sono disponibili.
Dobbiamo quindi procedere ad aggregare un‘ultima volta queste informazioni in un unico messaggio (ancora Pattern Aggregator) e valutare se è possibile inoltrarlo o meno (ancora Pattern Content-based Router).
La combinazione del pattern Splitter, Router e Aggregator viene anche chiamato Composed Message Processor Pattern.
Il pattern Composed Message Processor Pattern effettua lo split di un messaggio, il routing dei sotto messaggi ottenuti alle appropriate destinazioni e la relativa aggregazione finale in un unico messaggio.
Ecco la situazione finale relativa al processo dell‘ordine descritta fino ad ora.
Da questo esempio si è visto come applicare ben dodici pattern.
Questo a dimostrare di come sia importante conoscere i pattern sia da un punto di vista di applicabilità che da un punto di vista architetturale .
Come si vede la soluzione presenta una certa complessità . Utilizzando i sistemi di Messaging risulta particolarmente difficile ottenere una “big-picture” dell‘architettura data la natura prettamente asincrona dei sistemi di messaging.
E‘ quindi importante tracciare a runtime lo stato di ogni ordine all‘interno del sistema per nn perdere di vista il flusso dei messaggi e lo stato complessivo del sistema.
Per ottenere questo è utile applicare il pattern Message Store al fine di permettere un tracciamento dei messaggi nelle varie destinazioni.
Il pattern Message Store permette di tracciare lo stato del flusso dei messaggi all‘interno del sistema di messaging.
In una situazione in cui si utilizza il canale di tipo Publish Subscribe questo si ottiene facilmente aggiungendo un subscriber interessato al messaggio senza “intralciare” il normale flusso di dati.
Nel caso invece di canali P2P (code) bisogna aggiungere una nuova destinazione su cui duplicare il messaggio da inviare.
Per fare questo si può utilizzare il pattern Wire Tap.
Il pattern Wire Tap prevede l‘introduzione di un elemento che viene interposto tra il sender del messaggio ed il receiver. Ricevuto il messaggio dal sender, lo inoltra (senza modificarne il contenuto) oltre che al receiver (primary channel) anche al componente di message store (secondary channel).
Questo permette il monitoring e l‘ispezione dei messaggi anche per canali P2P.
Altro pattern utile è sicuramente il Message History.
Il pattern Message History permette la storicizzazione dei messaggi transitati nel sistema di messaging.
Questo permette di mantenere la lista dei componenti attraverso cui un messaggio è transitato. Ogni componente che processa il messaggio aggiunge un‘entry alla lista di history.
Il Message History deve essere incluso nella parte header del messaggio perché contiene informazioni prettamente di controllo e non nel payload che deve contenere dati di tipo applicativo.
E vediamo di introdurre un ultimo pattern molto importante per quanto riguarda il test.
Il pattern Test Message permette di verificare lo “stato di salute” del sistema di messaging.
Inserendo degli opportuni test-generator e dei test-verfier lungo il sistema è possibile verificare lo stato del corretto funzionamento del sistema e rilevare eventuali malfunzionamenti.
Conclusioni
Dal semplice esempio proposto si è visto come, quando e dove applicare ben quindici pattern!
Questo a dimostrare di come sia importante conoscere i pattern sia da un punto di vista di “applicabilità ” che da un punto di vista architetturale.
Riferimenti
[1] S.Rossini “Integration Patterns (II)” Mokabyte 100 Ottobre 2005
[2] Gregor Hohpe, Bobby Woolf “Enterprise Integration Patterns: Designing, Building, and Deploying Messaging Solutions”, Addison-Wesley 2004
[3] Gregor Hohpe Enterprise Integration Pattern web site
http://www.eaipatterns.com/index.html
[4] Alur, Crupi, Malks “Core J2EE Patterns: Best Practices and Design Strategies”
[5] Floyd Marinescu “EJB Design Patterns: Advanced Patterns, Processes and Idioms”
[6] Sun Java Center J2EE Patterns http://developer.java.sun.com/developer/restricted/patterns/J2EEPatternsAtAGlance.html
[7] Gamma, Helm, Johnson, Vlissides “Design Patterns: Elements of Reusable Object-Oriented Software”
Stefano Rossini è nato a Giussano (MI) il 29/10/1970 e ha conseguito il diploma universitario in Ingegneria Informatica presso il Politecnico di Torino. Ha maturato più di venti anni di esperienza in diversi progetti Enterprise mission-critical ricoprendo i ruoli di IT Program Manager, Project Manager & Software Architect presso importanti gruppi bancari, pubblica sanità, pubblica amministrazione e software house.
Attualmente ricopre il ruolo di Sofware Factory Manager, Lean Change Agent ed Enterprise Architect presso Capgemini.
Esperto in ambito di sanità pubblica come Project/Program Manager per la governance dei progetti IT strategici di Cartella Clinica Elettronica (CCE) e Fascicolo Sanitario Elettronico (FSE).
Esperto in ambito bancario dove ha ricoperto per una decina d'anni il ruolo di Project Manager e Leader Software Architect (BPM, IWBank e BPS) occupandosi della pianificazione e gestione del progetto, del coordinamento del gruppo di sviluppo software sia InHouse che Nearshore/Offshore. Esperto nella conduzione di progetti secondo metodologia di Project Management PMBok e metodologia agile Scrum.
Si occupa di Java dal 1999 arrivando da precedenti esperienze in C e C++ in ambito Telco (Alcatel & Siemens). Ha pubblicato più di un centinaio di articoli su argomenti di IT Governance, Project Management, architetture enterprise e problematiche di Integrazione e SOA. È coautore dei libri "Manuale pratico di Java" (2001) e "La programmazione della piattaforma J2EE" (2005) editi da Hops/Tecniche Nuove. Certificazioni IT Governance: COBIT V.4.1 Foundation Certificate; certificazioni IT Service Management: ITIL V.3 Foundation Examination; certificazioni Project Management: CSM - Scrum Master, CSPO - Scrum Product Owner, PMI: 35 contact hours.
Profilo linkedin: http://www.linkedin.com/pub/stefano-rossini/30/977/242