Versioni
| Pubblicato nella Rubriki Numero 4 - 14 Dic 2006 da RobertoMessoraUna delle aree di intervento della figura dell'architetto è quella che riguarda le questioni non funzionali ed i requisiti. In questo senso diventa importante avere una conoscenza di merito per quanto riguarda quegli strumenti che possono portare valore alle architetture e alla loro implementazione concreta. In generale, come enuncia il vecchio adagio, fra il dire e il fare ci sta di mezzo il mare ed è questo che si è portati a pensare le prime volte che si tenta di occuparsi di architetture software durante lo sviluppo reale di un'applicazione. La considerazione che si e' portati a fare è quella per cui la necessaria conoscenza nozionistica dei temi architetturali (design ed enterprise patterns, layering, domain model, security, ecc.) non è affatto sufficiente. La motivazione è piuttosto semplice: la complessità che queste tematiche portano con se è tale da non poter essere gestita facilmente progettandone una implementazione da zero. Da una parte la numerosità delle questioni in ballo è elevata, dall'altra è sempre più importante riuscire a ridurre i tempi di realizzazione, senza contare che spessissimo i vari ruoli professionali (analista, architetto, sviluppatore, tester, ecc.) sono ricoperti contemporaneamente da più persone se non addirittura dalla stessa. Non solo: troppo spesso la visione architetturale di un sistema informatico distoglie troppo presto l’attenzione da quello che è il problema di business, creando una deleteria commistione fra l’una e l’altro, quindi venendo a mancare quella necessaria separazione. In questo senso nasce una necessità fondamentale di semplificazione almeno per quanto riguarda la parte architetturale, fortunatamente in questo senso ci vengono incontro alcuni framework che favoriscono la strutturazione di un’applicazione sollevando lo sviluppatore da tutta una serie di oneri implementativi. I framework in questione vengono chiamati generalmente “container” e si occupano di tutte quelle attività di configurazione e wiring fra le varie parti di un sistema. Per wiring si intende semplificando quell’attività a runitme che dato un servizio generico da consumare (tipicamente un’interfaccia) offre l’oggetto concreto che implementa tale servizio, senza che ovviamente esista una qualsiasi dipendenza fra l’oggetto che consuma il servizio ed appunto quello che lo offre. Come è facile intuire il wiring ha molto a che spartire con i due pilastri di una buona programmazione per componenti e di una architettura a layer: Inversion of Control e Dependency Injection (traduzione in italiano ). In effetti tutte quelle attività di “factory” che spesso ci troviamo ad implementare a mano, risultano del tutto trasparenti mediante l’utilizzo di uno di questi framework, in quanto tutte le informazioni riguardo le classi concrete che implementano un particolare servizio sono in genere definite in un file di configurazione. In effetti, sempre mantenendo un certo livello di semplificazione adatto ad una panoramica generale, il principio su cui si basano i container è quello di utilizzare un file di configurazione per risolvere tutte le implementazioni concrete dei servizi utilizzati in un’applicazione, servizi che possono andare dal logging, all’accesso ai dati fisico, alla security, alla validazione, ecc.. Tutto ciò che lo sviluppatore dovrà scrivere per ottenere un riferimento ad un servizio sarà qualcosa del tipo: IMyService myService = container.Resolve(IMyService); Facile no? Dietro quel “Resolve” si muove il container che tramite il file di configurazione istanzia la classe specificata che implementa IMyService e la offre a chiunque abbia la necessità di invocare uno dei metodi che il servizio stesso offre. In questo modo l’unica dipendenza che il client deve considerare è quella dall’assembly che definisce il contratto del servizio (chiamarla dipendenza a questo punto diventa anche eccessivo se non addirittura scorretto), il client non avrà alcuna conoscenza dell’effettiva implementazione del servizio stesso, realizzando in questo modo una effettiva separazione eliminando qualsiasi tipo di dipendenza. Senza scendere troppo nel particolare, la sofisticazione dell’engine di wiring in realtà si può spingere molto più in là, ma questo diventa poi un dettaglio che ogni framework gestisce in maniera diversa. L’uso del wiring come effetto secondario ha quello di “costringere” a pensare e progettare fortemente per componenti, per contratti e per separazione delle responsabilità.. Ovviamente i container in questione non si fermano qui, è già molto, ma l’appetito vien mangiando ovviamente. Un altro aspetto molto interessante che viene offerto dai framework container è quello dell’intercettazione. In questo caso si ritorna al concetto di AOP e cioè la possibilità di intercettare la chiamata ad un metodo al fine di eseguire operazioni “infrastrutturali” prima e dopo l’esecuzione del metodo in oggetto. Il tutto senza che l’oggetto chiamante (cioè quello che implementa il metodo chiamato) abbia alcuna conoscenza, nonché dipendenza, degli oggetti che realizzano l’intercettazione della chiamata. L’esempio classico è quello del logging o della validazione: volessi eseguire il log di una chiamata ad un metodo, tramite AOP ho la possibilità (sempre attraverso un file di configurazione e mediante una sintassi specifica) di specificare quale metodo di quale classe verrà gestito dal servizio di logging che potrà effettuare le proprie operazioni di scrittura sia prima che dopo l’esecuzione del metodo. In questo senso il container offre in generale un’integrazione con il proprio engine di AOP che in maniera del tutto trasparente genera oggetti proxy in sostituzione di quelli intercettati (e che ovviamente in tutto e per tutto si comportano esattamente come gli originali), proxy che poi vengono passati come reference all’intercettatore. Normalmente nel file di configurazione viene indicato qual è la classe che gestisce l’intercettazione ed in quale metodo questo viene fatto (gli advice), su quale classe e su quali metodi (join points) viene applicata l’intercettazione (tramite la sintassi di AOP è possibile selezionare cosa si vuole intercettare, i cosiddetti pointcut). Al metodo di gestione dell’intercettazione viene poi passato appunto il reference all’oggetto proxy intercettato e le informazioni del metodo da chiamare (qualcosa molto vicino ad un oggetto System.Reflection.MethodInfo). In questo modo sarà possibile, a seguito di una certa logica, esguire o meno il metodo (sempre tramite qualcosa di molto simile a System.Reflection.MethodInfo.Invoke()). Ad esempio, riprendendo il logging, banalmente si potrebbe avere qualcosa come:
public object Log(IMethodInfo methodInfo)
{
logger.Info(“start {0}”, methodInfo.Name);
object result = methodInfo.Proceed(); //invoca il metodo
logger.Info(“stop {0}”, methodInfo.Name);
return result; //ritorna il risultato del metodo
}
Si può intuire da questa breve descrizione come tramite un container l’inserimento di un nuovo “intercettore” diventi semplicemente l’attività di implementazione della logica di intercettazione, e la modifica del file di configurazione, senza che l’obiettivo dell’intercettazione (ad esempio una classe di accesso ai dati, come un repository tramite i suoi metodi di CRUD), abbia minimamente conoscenza sia del container, sia degli intercettatori. Wiring e AOP con questi due strumenti fondamentali i framework container permettono di gestire lo sviluppo di una qualsiasi applicazione in maniera molto più produttiva, facilitando la concentrazione su quello che è il problema di business, soprattutto se l’approccio di design è quello Domain Driven . Per il mondo .NET i due framework più utilizzati e conosciuti sono Castle Windsor e Spring.NET , ovviamente entrambi offrono molto di più di quanto esposto brevemente qui (ad esempio Castle Windsor offre un motore MVC basato su una versione per .NET di Ruby on Rails, tanto per fare un esempio), ma nel loro complesso l’obiettivo generale che si prefiggono è lo stesso. | UGIdotNETWikiUGIdotNETWiki è il WikiWiki italiano dedicato a .NET Se è la prima volta che senti parlare di Wiki, leggi il BenvenutoAiVisitatori e WikiInUnMinuto, oppure il ManualePassoPassoDelWiki. Argomenti Recenti | ||||||||||||||||||||||||||||||||||||||
| © 2008 User Group Italiano UGIdotNET. Tutti i diritti riservati. Note legali | ||||||||||||||||||||||||||||||||||||||||