Architettura http://blogs.ugidotnet.org/rgm/category/Architettura.aspx Architettura it-IT Gian Maria Ricci Subtext Version 2.6.0.0 CQRS ed Event Sourcing su Windows Azure: applicazioni distribuite, scalabilit&agrave; e security http://blogs.ugidotnet.org/rgm/archive/2013/03/26/cqrs-ed-event-sourcing-su-windows-azure-applicazioni-distribuite-scalabilitagrave.aspx <p>Spero che il titolo vi abbia stuzzicato, perchè non è altro che il titolo dell’ultimo workshop targato DotNetMarche che si terrà questo venerdi ad Ancona. </p> <p>I dettagli dell’evento ed il modulo di iscrizione sono disponibili a questo indirizzo <a title="http://dnm-cqrs-azure.eventbrite.com/" href="http://dnm-cqrs-azure.eventbrite.com/">http://dnm-cqrs-azure.eventbrite.com/</a>. </p> <p>Per quanto riguarda speaker ed agenda, per stuzzicare il vostro appetito la riporto qui: VI ATTENDIAMO!!!! :D</p> <p> </p> <p>In questo workshop <a href="http://blog.codiceplastico.com/melkio/">Alessandro Melchiori</a> e <a href="http://milestone.topics.it/">Mauro Servienti</a> ci mostreranno come hanno implementato su Windows Azure delle soluzioni distribuite e scalabili, in contesti in cui la sicurezza gioca un ruolo molto importante, grazie a tecniche e strumenti come CQRS ed Event Sourcing e sfruttando l'infrastruttura stessa della soluzione cloud offerta da Microsoft.  </p> <p><strong>Agenda del workshop</strong></p> <p><strong>13.30 Ingresso partecipanti</strong></p> <p><strong>14.00 Keynote</strong></p> <p><strong>14.15 Introduzione a Windows Azure</strong> <br />Un veloce escursus sulle feature messe a disposizione dalla piattaforma Azure, analizzando le principali differenze tra i concetti di IaaS e PaaS.</p> <p><strong>15:00 Scalabilità, Scalabilità e ancora scalabilità</strong> <br />Quando si parla di "Cloud" la parola scalabilità viene sempre citata: ma cosa vuol dire veramente scalare orizzontalmente? Quali sono i servizi che Azure ci mette a disposizione e come li possiamo sfruttare? Dobbiamo veramente scrivere della applicazioni "per" Azure o possiamo limitarci a seguire le regole generali che seguiremmo nello scrivere un'applicazione state-less?</p> <p><strong>16:00 Pausa</strong></p> <p><strong>16:15 I dialetti del ServiceBus: scalare comunicando</strong> <br />Se pensiamo a tutti i servizi messi a disposizione da Azure, alle caratteristiche degli stessi e alla loro inevitabile distribuzione e disponibilità ci rendiamo conto che per farli comunicare non è detto che basti il "solito" servizio WCF, abbiamo anche in questo scenario bisogno di stare nel paradigma imposto dalla scalabilità: il ServiceBus, in quanto broker, risolve tutte queste problematiche ma ovviamente cambia radicalmente l'approccio che dobbiamo avere nello strutturare l'applicazione.</p> <p><strong>17:15 Gestione delle sicurezza in un sistema distribuito: Windows Azure ACS</strong> <br />Adesso che abbiamo il nostro bel sistema distribuito ci rendiamo conto che processi e macchine diverse devono però in molti casi condividere lo stesso contesto di sicurezza: è quindi necessario che sia possibile far fluire il contesto di sicurezza tra processi e ambienti eterogenei, vedremo come l'ACS di Azure risolva brillantemente il problema e vedremo anche come ci permetta di liberarci completamente di tutto il "problema" dell'infrastruttura di sicurezza.</p> <p> </p> <p>Gian Maria</p><img src="http://blogs.ugidotnet.org/rgm/aggbug/101487.aspx" width="1" height="1" /> Gian Maria Ricci http://blogs.ugidotnet.org/rgm/archive/2013/03/26/cqrs-ed-event-sourcing-su-windows-azure-applicazioni-distribuite-scalabilitagrave.aspx Tue, 26 Mar 2013 10:49:00 GMT http://blogs.ugidotnet.org/rgm/archive/2013/03/26/cqrs-ed-event-sourcing-su-windows-azure-applicazioni-distribuite-scalabilitagrave.aspx#feedback 2 http://blogs.ugidotnet.org/rgm/comments/commentRss/101487.aspx http://blogs.ugidotnet.org/rgm/services/trackbacks/101487.aspx CQRS e i dati stale sono ovunque http://blogs.ugidotnet.org/rgm/archive/2012/07/14/cqrs-e-i-dati-stale-sono-ovunque.aspx <p>Quando inizi a lavorare in ottica CQRS, ma più in generale quando ammetti che tra l’esecuzione di un comando e l’aggiornamento dell’UI presentata all’utente possa passare del tempo per cui <strong>la UI non riflette <em>immediatamente</em> il risultato del comando</strong>, ti chiedi se questa “<em>limitazione”</em> sia “<em>vendibile” e “accettabile”</em>  dagli utenti ed in generale agli stakeholder del progetto.</p> <p>Molto spesso si parte prevenuti dicendo che non è ammissibile che un utente esegua l’operazione X e l’interfaccia rifletta l’effettivo risultato in ritardo, anche se solo dopo pochi secondi, oppure ancora peggio, che mostri i dati vecchi, ma è veramente cosi??? Durante il vostro normale utilizzo da Utenti software fate caso a quanti siti importanti utilizzano questo paradigma. Prendiamo E-bay; stamattina mi connetto, debbo lasciare due feedback, uno degli item è arrivato, quindi lascio il feedback solo su quello poi torno sul “il mio ebay” e … ho ancora due feedback da lasciare, vabbè, faccio un paio di ricerche, passano cinque minuti buoni, torno sul “il mio ebay” e la pagina è ancora cosi</p> <p><a href="http://blogs.ugidotnet.org/images/blogs_ugidotnet_org/rgm/Windows-Live-Writer/CQRS-e-i-dati-stale-sono-ovunque_A642/image_2.png"><img style="border: 0px currentcolor; display: inline; background-image: none;" title="image" border="0" alt="image" src="http://blogs.ugidotnet.org/images/blogs_ugidotnet_org/rgm/Windows-Live-Writer/CQRS-e-i-dati-stale-sono-ovunque_A642/image_thumb.png" width="848" height="600" /></a></p> <p>A questo punto magari mi sorge il sospetto che il sistema prima non abbia accettato il feedback (nonostante mi abbia detto che era stato preso in carico) per cui clicco per lasciarlo ancora, ma il sistema mi notifica che qualche cosa non va.</p> <p><a href="http://blogs.ugidotnet.org/images/blogs_ugidotnet_org/rgm/Windows-Live-Writer/CQRS-e-i-dati-stale-sono-ovunque_A642/image_4.png"><img style="border: 0px currentcolor; display: inline; background-image: none;" title="image" border="0" alt="image" src="http://blogs.ugidotnet.org/images/blogs_ugidotnet_org/rgm/Windows-Live-Writer/CQRS-e-i-dati-stale-sono-ovunque_A642/image_thumb_1.png" width="803" height="178" /></a></p> <p>In ottica DDD molto probabilmente la <strong>UI che visualizza “il mio ebay” non è stata ancora notificata dell’avvenuto feedback</strong>, per cui mi presenta ancora il link per farlo, chiaramente quando tento di farlo ancora e vado su una UI che probabilmente è pertinente del Bounded Context dei Feedback mi trovo che la UI è aggiornata e mostra chiaramente che l’operazione richiesta non è disponibiole. Probabilmente il denormalizzatore che gestisce “il mio ebay”, (il cui compito è attendere il DOMAIN EVENT FeedbackDone, ed in base ad esso aggiornare il numero di feedback che l’utente deve lasciare) ha priorità minore, forse il sito era carico, forse fisicamente il feedback ha richiesto tempo per essere eseguito, etc etc. Non mi interessano i dettagli, ma piuttosto che il sistema utilizzi chiaramente paradigmi CQRS e che mi stia mostrando dati <em>vecchi (stale)</em></p> <p><img src="http://maximizeu.com/wp-content/uploads/2010/07/moldy_bread-225x187.jpg" /></p> <p>Ora torniamo a quello che dicevo prima sul fatto che questa “limitazione” sia “vendibile” e “accettabile”. La prima considerazione è che questa non è una limitazione, anzi è una funzionalità che aumenta la scalabilità. Se mi soffermo a pensare perché “il mio ebay” mostri ancora 2 feedback mi viene da pensare che magari il sistema sia molto carico al momento, oppure magari la “tabella dei feedback” è in lock per un upgrade.. o chissà cosa, ma <strong>il mio feedback è stato preso comunque in carico dal sistema</strong>, anche se il resto del sistema non è stato notificato/aggiornato. Se volessi un sistema che non ammette la visualizzazione di dati <em>stale</em>, dovrei attendere durante il postback del feedback che tutte le UI siano aggiornate  e magari farlo in transazione, questo fa si che dopo 5 minuti ancora vedrei la pagina caricarsi perchè non riesce ad aggiornare “il mio ebay”? Oppure non posso lasciare feedback se per qualche ragione ho un lock nella tabella dei feedback per un upgrade: inaccettabile. Un sistema che non ammette di mostrare dati vecchi (se è in un picco di carico o in un upgrade oppure ha dei lock perchè in quel momento sta girando un processo o per qualsiasi ragione) è un sistema che prima o poi diventerà lento, l’utente premerà il bottone “lascia il feedback”, dopo 30 secondi ancora la pagina è in caricamento ed avremo un utente frustrato</p> <p><img src="http://bandalarga.ilcannocchiale.it/mediamanager/sys.user/49469/paperino_arrabbiato.gif" /></p> <p>L’ammettere che le UI possano essere stale permette al sistema di rispondermi immediatamente dicendo “il tuo feedback è stato preso in carico”, punto. Il fatto che poi tutto il sistema Ebay si accorga di questo in ritardo per me non è importante, importa che il comando e la mia azione siano state prese in carico ed in modo molto veloce. Ragionare a Command / Handler in ottica CQRS rende il mio sistema molto scalabile e soprattutto molto User Task oriented. L’utente deve essere semplicemente “avvertito” di questo funzionamento, in modo che quando guarda i dati, è conscio che su qualcuno di essi si possa essere formata della muffa (dati stale). </p> <p>Appurato che questa struttura non è una “limitazione” ma semplicemente una struttura per aumentare la scalabilità ragioniamo sull’”accettabile” da parte degli utenti. Il mio consiglio è che <strong>prima di dire “non è accettabile” si faccia uno studio reale dei requisiti</strong>, per capire se è compatibile con i suddetti e soprattutto si intervistino gli utenti per capire come la pensano e come verrà usato il sistema. In un sistema su cui lavoro, il fatto di fare un upgrade in background ed essere notificati in differita sul risultato è stato una grande miglioria, perché il sistema era più responsivo. Il vedere per un po’ di secondi dati vecchi non era assolutamente un problema, ma invece di <strong>attendere 10 secondi per l’esecuzione di complesse operazioni di business su un dato, il sistema risponde in pochi millisecondi dicendo all’utente “ho inziato l’elaborazione”</strong> e l’utente viene avvertito in modo esplicito solamente in caso di fallimento (raro) perchè deve prendere azioni correttive. L’utente è più contento, accetta che il risultato sia visibile in differita, ed è più felice.</p> <p>Insomma, siamo nel 2012, e sempre più  i sistemi informatici attorno a noi sono realizzati su questi paradigmi ed ammettono che <strong>sia normale visualizzare dati vecchi</strong> <strong>e sempre più gli utenti saranno abituati a questo paradigma</strong>, e anzi, forse riterranno inaccettabile un sistema che blocca la UI per 4 secondi scrivendo “updating” commentando: “che schifo, perché non potrebbe fare sto lavoro in background e notificarmi in differita in caso di problemi?”, quindi probabilmente saranno le strutture “tradizionali” ad essere “inaccettabili” :). </p> <p>Meditate gente, meditate.</p> <p>Gian Maria</p><img src="http://blogs.ugidotnet.org/rgm/aggbug/101110.aspx" width="1" height="1" /> Gian Maria Ricci http://blogs.ugidotnet.org/rgm/archive/2012/07/14/cqrs-e-i-dati-stale-sono-ovunque.aspx Sat, 14 Jul 2012 13:09:33 GMT http://blogs.ugidotnet.org/rgm/archive/2012/07/14/cqrs-e-i-dati-stale-sono-ovunque.aspx#feedback http://blogs.ugidotnet.org/rgm/comments/commentRss/101110.aspx http://blogs.ugidotnet.org/rgm/services/trackbacks/101110.aspx Dove metto cosa? http://blogs.ugidotnet.org/rgm/archive/2011/11/28/dove-metto-cosa.aspx <p>Spesso noto che i problemi delle applicazioni, non sono da ricercarsi in una architettura poco strutturata o inefficiente o quant’altro, ma proprio nelle basi di come strutturare un progetto.</p> <p>Ad esempio, indipendentemente da che architettura/struttura utilizziamo, se stiamo usando o meno ORM WCF o quant’altro, una delle regole principali è: Quando voglio aggiungere un file sorgente e quindi solitamente una classe, dove la metto?</p> <p>Non c’è nulla che uccida di più la manutenibilità di un software di trovare ad esempio dto sparsi un po in ogni dove, oppure classi di accesso al database un po qui ed un po’ là. Il mio consiglio è sempre quello di pensare un poco prima di “tirare il codice dentro ai progetti”, ovvero scrivere codice nel primo punto dove capita. Spendere del tempo a strutturare ed organizzare il codice sorgente paga sempre ;).</p> <p>Gian Maria.</p><img src="http://blogs.ugidotnet.org/rgm/aggbug/100565.aspx" width="1" height="1" /> Gian Maria Ricci http://blogs.ugidotnet.org/rgm/archive/2011/11/28/dove-metto-cosa.aspx Mon, 28 Nov 2011 11:53:20 GMT http://blogs.ugidotnet.org/rgm/archive/2011/11/28/dove-metto-cosa.aspx#feedback 4 http://blogs.ugidotnet.org/rgm/comments/commentRss/100565.aspx http://blogs.ugidotnet.org/rgm/services/trackbacks/100565.aspx Entity Framework e la corrispondenza con il modello ad oggetti. http://blogs.ugidotnet.org/rgm/archive/2009/02/20/entity-framework-e-la-corrispondenza-con-il-modello-ad-oggetti.aspx <p>Questo post nasce da un fatto strano che ho notato sviluppando un progetto con Entity Framework, considerate il seguente spezzone di codice.</p> <p> </p><div class="wlWriterSmartContent" id="scid:57F11A72-B0E5-49c7-9094-E3A15BD5B5E7:355431f8-5cfd-457d-8043-de33d12feb71" style="padding-right: 0px; display: inline; padding-left: 0px; float: none; padding-bottom: 0px; margin: 0px; padding-top: 0px"><pre style="background-color:White;;overflow: auto;"><div><!-- Code highlighting produced by Actipro CodeHighlighter (freeware) http://www.CodeHighlighter.com/ --><span style="color: #008080;"> 1</span> <span style="color: #0000FF;">using</span><span style="color: #000000;"> (NorthwindEntities context </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #0000FF;">new</span><span style="color: #000000;"> NorthwindEntities()) </span><span style="color: #008080;"> 2</span> <span style="color: #000000;">{ </span><span style="color: #008080;"> 3</span> <span style="color: #000000;"> IEnumerable</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">Customers</span><span style="color: #000000;">&gt;</span><span style="color: #000000;"> customers1 </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #008080;"> 4</span> <span style="color: #000000;"> context.Customers </span><span style="color: #008080;"> 5</span> <span style="color: #000000;"> .Where(c </span><span style="color: #000000;">=&gt;</span><span style="color: #000000;"> c.CustomerID.Contains(</span><span style="color: #800000;">""</span><span style="color: #000000;">)); </span><span style="color: #008080;"> 6</span> <span style="color: #000000;"> Console.WriteLine(customers1.Count()); </span><span style="color: #008080;"> 7</span> <span style="color: #000000;"> </span><span style="color: #008080;"> 8</span> <span style="color: #000000;"> IEnumerable</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">Customers</span><span style="color: #000000;">&gt;</span><span style="color: #000000;"> customers2 </span><span style="color: #000000;">=</span><span style="color: #000000;"> </span><span style="color: #008080;"> 9</span> <span style="color: #000000;"> context.Customers </span><span style="color: #008080;">10</span> <span style="color: #000000;"> .ToList() </span><span style="color: #008080;">11</span> <span style="color: #000000;"> .Where(c </span><span style="color: #000000;">=&gt;</span><span style="color: #000000;"> c.CustomerID.Contains(</span><span style="color: #800000;">""</span><span style="color: #000000;">)); </span><span style="color: #008080;">12</span> <span style="color: #000000;"> Console.WriteLine(customers2.Count()); </span><span style="color: #008080;">13</span> <span style="color: #000000;">}</span></div></pre><!-- Code inserted with Steve Dunn's Windows Live Writer Code Formatter Plugin. http://dunnhq.com --></div> <p>Il codice è veramente banale, nel primo caso si effettua una query LINQ to entities chiedendo tutti i clienti il cui id contiene stringa nulla, nel secondo caso si effettua un'operazione molto simile, si caricano in memoria tutti i clienti (perchè nella linea 10 il ToList() essendo un not-deferred operator effettua la query nel database e carica gli oggetti in memoria) e poi si effettua un filtro sugli oggetti in memoria con la stessa condizione precedente, ovvero filtrare tutti i clienti il cui id contiene stringa nulla.</p> <p>Il risultato di questo snippet è </p> <p><em><strong>0 <br />91</strong></em></p> <p>ovvero filtrando sul database si ottengono zero oggetti mentre filtrando gli oggetti in memoria otteniamo 91 oggetti. Naturalmente il secondo risultato è quello corretto, dato che ogni stringa contiene logicamente la stringa nulla e quindi mi aspetto che vengano tornati tutti i clienti che non hanno un CustomerID nullo. Questo problema deriva da una pagina asp.net che deve soddifare queste spefiche. E' necessario mostrare tutti i clienti che contengono nel CustomerId una stringa digitata dall'utente con la condizione che se l'utente non digita nulla vengano tornati tutti i clienti. </p> <p>Ora, senza entity framework basta fare una query sql con una condizione del tipo <em><strong>CustomerId like '%' + stringaricerca + '%'</strong></em> ed ottenere il comportamento previsto; EF invece traduce la query nel modo seguente</p> <p> </p><div class="wlWriterSmartContent" id="scid:57F11A72-B0E5-49c7-9094-E3A15BD5B5E7:c87ea6c5-60cc-456f-b6a1-86fce4743834" style="padding-right: 0px; display: inline; padding-left: 0px; float: none; padding-bottom: 0px; margin: 0px; padding-top: 0px"><pre style="background-color:White;;overflow: auto;"><div><!-- Code highlighting produced by Actipro CodeHighlighter (freeware) http://www.CodeHighlighter.com/ --><span style="color: #000000;">SELECT [Extent1].[Address] AS [Address], [Extent1].[Checked] AS [Checked], ... FROM [dbo].[Customers] AS [Extent1] WHERE (CAST(CHARINDEX(N</span><span style="color: #800000;">''</span><span style="color: #000000;">, [Extent1].[CustomerID]) AS </span><span style="color: #0000FF;">int</span><span style="color: #000000;">)) </span><span style="color: #000000;">&gt;</span><span style="color: #000000;"> </span><span style="color: #800080;">0</span></div></pre><!-- Code inserted with Steve Dunn's Windows Live Writer Code Formatter Plugin. http://dunnhq.com --></div> <p>per il contains viene utilizzata la funzione CHARINDEX che purtroppo se si passa una stringa nulla fallisce sempre. Questo significa che con Entity Framework le query sul modello concettuale non mappano fedelmente le query fatte su oggetti in memoria. Dato che EF dovrebbe costituire un layer (repository) per il quale io "lavoro" solo su oggetti mentre EF si occupa di gestire le query da fare al database, mi attendo sempre che <em>il comportamento di una query linq to entity produca gli stessi risultati della corrispondente linq to object fatta su oggetti in memoria</em>. Sebbene questo possa sembrare un peccato veniale, dal punto di vista concettuale è fondamentale che questo requisito sia mantenuto. </p> <p>Alk.</p><img src="http://blogs.ugidotnet.org/rgm/aggbug/95518.aspx" width="1" height="1" /> Gian Maria Ricci http://blogs.ugidotnet.org/rgm/archive/2009/02/20/entity-framework-e-la-corrispondenza-con-il-modello-ad-oggetti.aspx Fri, 20 Feb 2009 18:22:59 GMT http://blogs.ugidotnet.org/rgm/archive/2009/02/20/entity-framework-e-la-corrispondenza-con-il-modello-ad-oggetti.aspx#feedback 5 http://blogs.ugidotnet.org/rgm/comments/commentRss/95518.aspx http://blogs.ugidotnet.org/rgm/services/trackbacks/95518.aspx