Qualche giorno fa mi è arrivata una mail di domande riferite alla sessione architetturale che ho avuto modo di tenere recentemente all'evento di Firenze, il Real Code Day 2. L'autore della mail è Andrea Angella, studente di ingegneria informatica all'Università di Pisa. Dal momento che la mail è bella corposa e affronta molti aspetti, credo che la risposta possa essere di interesse pubblico, considerando anche il grande numero di mail che oltre a questa mi sono giunte con richieste di chiarimenti e approfondimenti. Le domande si riferiscono all'applicazione scritta in diretta durante la sessione e disponibile all'indirizzo: http://www.dotnetcircle.it/firenze07.aspx.
Nota: il testo della mail è in italico, le domande sono in grassetto, infine le risposte sono in testo normale.
Ho seguito con molta attenzione la sessione che hai fatto a Firenze sull'architettura (diciamo che quella ero uno degli scopi principali per cui ero venuto al Real Code Day 2) e dopo aver analizzato il codice della soluzione vorrei farti alcune domande:
Ho visto che utilizzi il pattern Abstract Factory per costruire istanze concrete (con o senza cache) di IEntityService<T>
1) Puoi spiegarmi meglio le relazioni per esempio tra le classi BookService e Books?
Books è una classe di facciata (facade) che ha lo scopo di instradare le richieste ai servizi applicativi interni mascherando all'utilizzatore i dettagli della chiamata del servizio. Tutti i servizi implementano l'interfaccia IEntityService<T>
2) Quali vantaggi mi offre questa gerarchia un pò intricata?
Il vantaggio è quello di poter gestire la complessità in modo mirato, ripartendo le responsabilità tra più oggetti. L'alternativa sarebbe quella di avere una serie di oggettoni (uno per tipologia) che fanno tutto, che hanno una serie di comportamenti statici e predefiniti (non modificabili senza che la cosa abbia ripercussione altrove) e che siano fonte di un forte accoppiamento. In termini di manutenibilità e flessibilità la struttura ad oggetti presentata dà grossi vantaggi e permette di creare un meccanismo di isolamento e protezione del codice, evitando ripercussioni in caso di modifica.
3) In cosa consiste e come funziona il LazyLoad ?
In certi frangenti può esistere la necessità di voler caricare parzialmente le informazioni di una classe, magari perchè sono particolarmente onerose in termini di occupazione di memoria. In tali casi si può scegliere di operare un caricamento dilazionato, in base al quale i dati "pesanti" vengano caricati solo nel momento in cui effettivamente sono utilizzati. Il Lazy Loading consiste proprio in questo. L'entità a caricamento parziale è LazyBook che sta nel BLL per non creare accoppiamento con lo strato di accesso ai dati. In LazyBook la proprietà Authors carica gli autori all'interno del metodo protetto LoadAuthors, chiamando un metodo specifico all'interno del DAL.
4) Perchè creare IServiceFactory e poi la classe concreta ServiceFactory? Dovrebbe essere implementata come una classe Singleton?
La classe ServiceFactory è singleton e usa internamente un riferimento privato di tipo IServiceFactory.
5) Qual è l'utilità di creare e utilizzare l'attributo EntityTypeAttribute per decorare le classi Entity? in che parte del codice viene utilizzato EntityType della classe base Entity?
Come ho avuto modo dire a Firenze, la caratteristica principale delle entità è quella di essere provviste di una identità (ID). Non tutti gli oggetti dell'Object Model sono provvisti di identità, infatti non tutti gli oggetti sono necessariamente entità, come per esempio Price (in tal caso si chiamano value object). Oltre all'identità occorre fornire un meccanismo di confronto tra le istanze di entità. Per fare questo occorre fare l'override del metodo Equals di Object. Se ponessimo il metodo Equals in ogni classe entità, avremmo la stessa implementazione ripetuta n volte. Ha quindi senso considerare l'opportunità di creare un supertipo Entity dove inserire la proprietà ID e il metodo Equals. Dal momento che due entità di tipo diverso possono avere lo stesso ID, occorre poter identificare la tipologia dell'entità oltre al suo ID. L'uguaglianza sarà data dalla coincidenza di ID e tipologia. Associando un attributo custom ad ogni entità, è possibile marcarla in modo distinguibile. La proprietà EntityType di Entity legge gli attributi custom dell'entità e ricava in questo modo la tipologia. La stessa cosa può essere ottenuta inserendo nel tipo Entity una proprietà astratta da implementare obbligatoriamente in ogni tipo derivato affinchè ritorni un valore distinguibile.
Ho visto che hai creato un classe PageBase attraverso la quale costruire le varie pagine. Essa permette di implementare un meccanismo comune per la validazione della querystring.
6) Puoi spiegarmi in particolare come funziona il metodo Validate() e quali classi ed attributi nella cartella Validation entrano in gioco ?
Quello di validazione è un servizio infrastrutturale dell'applicazione che permette di gestire in modo automatico la validazione della QueryString associata ad una richiesta HTTP. Il servizio sfrutta una serie di attributi custom per definire le modalità di validazione e, in base ai valori ottenuti dalle operazioni di verifica, decide quali azioni intraprendere in caso di input non valido. In questo caso l'utilizzatore del servizio di validazione è la classe PageBase, ma avrebbe potuto tranquillamente essere utilizzato un HttpModule specifico. L'implementazione del modulo è spiegata nell'articolo di Stefano Mostarda pubblicato recentemente su ASPItalia.com.
Ho avuto modo di utilizzare il designer dei dataset tipizzati di VS2005 e l'ho trovato molto interessante. Ho sviluppato un'applicazione windows form utilizzando il modello a oggetti offerto dal designer e dai TableAdapter ma ho da subito notato la scarsa flessibilità dello stesso soprattutto di fronte a modifiche anche lievi al database nonchè la lentezza. Io in pratica ho usato una sorta di architettura a due livelli DAL + UI che utilizza direttamente istanze di TableAdapter. Avevo visto tempo fà articoli che proponevano soluzioni di questo tipo in ASP.NET.
5) Cosa pensi a riguardo di questa possibilità?
Non sono un grande amante dei container di dati quali sono DataSet e DataTable, ma è innegabile che in talune circostanze sono davvero utili. In termini di praticità i container di dati di ADO.NET sono ottimi, non si può dire la stessa cosa in termini di performance, anche se rispetto alla versione 1.x sono stati migliorati.
6) In Orcas sono stati fatti miglioramenti?
Vedi la risposta alla domanda 7.
7) Inoltre in cosa consiste la tecnologia LINQ che sento tanto spesso nominare e quali vantaggi permette di ottenere?
Ti rimando agli articoli dedicati al .NET Framework 3.5 che usciranno nei prossimi giorni su ASPItalia.com e WinFXItalia.com in occasione dello speciale dedicato ad Orcas. Tra gli articoli ce n'è uno dedicato alle query expressions (LINQ).
Ho sentito che è molto diffuso l'utilizzo di uno strumento come NHibernate per la costruzione di un modello a oggetti sul DB. (Premetto che non l'ho mai utilizzato sò solo cosa permette di fare)
8) Utilizzando la tua architettura quali vantaggi offrirebbe il suo utilizzo e quali modifiche richiederebbe?
Un ORM consente la mappatura tra i dati e le entità del dominio applicativo, fornisce funzionalità avanzate per l'accesso ai dati e la gestione della persistenza, include meccanismi quali la gestione di contesti transazionali (UoW), la gestione del caricamento parziale dei dati (Lazy Loading) e l'ottimizzazione nel fetching e nell'updating. NHibernate è sicuramente l'ORM più apprezzato e usato dagli sviluppatori .NET, molto indicato (se non indispensabile) quando l'approccio è quello che è conosciuto come Domain Model, dove la rappresentazione in memoria delle informazioni necessita di efficienza e di ottimizzazioni continue. In generale per le applicazioni web trovo l'uso degli ORM meno vantaggioso di quanto non sia con le applicazioni Windows. In ogni caso occhio sempre all'over-engineering e alle performance.
Infine una semplice domanda di stile di codifica:
9) Perchè tu come molti altri utilizzate _ per indicare i membri privati di un oggetto? A me non piace molto vorrei sapere se ci sono alternative o se riesci a convincermi che è opportuno fare così.
Utilizzo l'underscore per i campi privati per due motivi:
- elimina qualsiasi possibile ambiguità di naming con gli eventuali parametri di un metodo (sia campi che parametri usano la camel notation);
- permette di non utilizzare la keyword "this" rappresentando di fatto un suo alias e una "scorciatoia".
OK, io mi fermerei qui... ;) Spero di aver aver risposto esaurientemente alle domande. Un saluto e un ringraziamento a tutti coloro che mi hanno scritto in questi giorni per farmi domande relative a quanto visto al Real Code Day 2. Alla prossima...
Per inserire un commento, devi avere un account.
Fai il login e torna a questa pagina, oppure registrati alla nostra community.
- A volte ritornano!, l'8 febbraio 2010 alle 23:45
- Guide sull'architettura delle applicazioni, il 14 dicembre 2008 alle 19:13
- Attacco XSS combinato con SQL-Injection, il 25 luglio 2008 alle 13:00
- Articoli in MSDN su Architettura e OOD, il 18 luglio 2007 alle 10:40
- Architetto? Chi era costui?, il 26 aprile 2007 alle 16:29