Architettura
Usare TDD ovunque, testare un servizio WCF - TDD everywhere, testing a WCF service

Il Test Driven Development è un’altra delle metodologie secondo me vincenti, specialmente in alcuni contesti, in alcuni, perchè non è detto che siano sempre adatte.

TDD o meglio Test Driven Design è particolamente utile quando si scrive una nuova applicazione o nuove feature nella fase di design della soluzione, partire dal test permette di tradurre al meglio la User Story o la feature (Feature Driven Development) nel codice che la implementa, si rimane concentrati sul cosa e non sul come, si scrive lo stretto necessario senza over-ingegnerizzare => “over-complicare”.

Scrivendo prima il test si identificano le classi/membri esattamente nel momento in cui servono, inoltre con i test ovviamente… si hanno i test :), si possono verificare più use-case e rendere il codice più robusto. Infine grazie agli stub ed ai mock non è indispensabile lavorare sulle classi reali anzi meglio lavorare su fake con Unit Test, invece che scrivere Integration Test. Ovviamente sono utili anche gli Integration Test ed i System Test per evitare allo sviluppatore di eseguire continuamente l’applicazione. Nonstante questo gli User Acceptance Test rimangono indispensabili, uno o più utenti devono testare l’applicazione e la UI specialmente (se esiste) perchè ovviamente è la parte maggiormente a contatto con il “ProductOwner” e probabilmente la più difficile da testare in automatico attualmente.

Arriviamo al titolo del post :). In un progetto a cui lavoro ho avuto la necessità di creare una key per una entity che fosse in realtà un’insieme di valori eterogeneo, il motivo è che lo storage è più di uno ed ogni storage può definire differenti chiavi naturali (i loro progettisti, Topolino e Paperino, non conoscono le chiavi surrogate e i Guid :D).
Topolino e Paperino DB designers

Quindi partendo dal test:

   1: public void CreateAKeyExpectedCorrectNameAndCorrectValueAreSetted()
   2: {
   3:     var concreteKey = new ConcreteKey(KnownKeys.Key);
   4:  
   5:     concreteKey
   6:         .Id
   7:         .ShouldEqual(KnownKeys.Key, "IdKey has not the expected value.");
   8: }


Quindi la classe Key:

   1: public abstract class Key : IEnumerable<KeyValue>
   2: {
   3:     private readonly IEnumerable<KeyValue> keysDictionary;
   4:  
   5:     protected Key(params KeyValue[] keyValues)
   6:     {
   7:         if ((keyValues == null) || (keyValues.Length == 0))
   8:         {
   9:             throw new ArgumentException("Must define at least a KeyValue.", "keyValues");
  10:         }
  11:  
  12:         keysDictionary = keyValues;
  13:     }
  14:  
  15:     public IEnumerator<KeyValue> GetEnumerator()
  16:     {
  17:         return 
  18:             keysDictionary
  19:             .OrderBy(keyValue => keyValue.Key)
  20:             .GetEnumerator();
  21:     }
  22:  
  23:     IEnumerator IEnumerable.GetEnumerator()
  24:     {
  25:         return GetEnumerator();
  26:     }
  27:  
  28:     protected T GetKeyValue<T>(string keyName) where T : struct
  29:     {
  30:         var value =
  31:             keysDictionary
  32:                 .Where(e => e.Key == keyName)
  33:                 .First()
  34:                 .Value;
  35:  
  36:         return (T) value;
  37:     }


Ho quindi scritto un DTO per trasportare le entity attraverso WCF e qui nasce il problema, non volendo creare un servizio WCF fittizio solo per verificare che il design sia corretto ho cercato come hostare il servizio direttamente dal test, ed ecco la soluzione: Testable WCF ServiceHost.

In sostanza grazie alla classe scritta dall’autore è possibile questo test:

   1: [TestMethod]
   2: public void CallGetAllOfWcfServiceExpectedWorksAndKeysAreSetted()
   3: {
   4:     using (var messageServiceHost = new WcfTestHost<Service, IService>())
   5:     {
   6:         var client = messageServiceHost.CreateProxy();
   7:         var dtoSet = client.GetAll().ToList();
   8:  
   9:         var keyValue = dtoSet[0]
  10:             .Key
  11:             .First();
  12:  
  13:         keyValue
  14:             .Key
  15:             .ShouldEqual(ConcreteKey.IdKeyName, "Expected a key that is not present.");
  16:  
  17:         ((int)
  18:         keyValue
  19:             .Value)
  20:             .ShouldEqual(KnownKeys.Key, "Wrong key value.");
  21:     }
  22: }


Un pezzo della classe WcfTestHost:

   1: public WcfTestHost(Binding binding)
   2: {
   3:     host = new ServiceHost(serviceImplType);
   4:     this.binding = binding;
   5:  
   6:     url = string.Format("{0}://localhost/{1}", binding.Scheme, Guid.NewGuid());
   7:     host.AddServiceEndpoint(serviceIntType, binding, url);


Nell’esempio allegato si trova il progetto della key e la classe per testare un servizio WCF completa, grazie a qualche email scambiata con l’autore, di error handling e trace che permette di intercettare qualsiasi exception scatenata “lato server”.
Solution TDD WCF 

Scarica qui.

Matteo Migliore.

Technorati Tags: ,,,
Add Comment Filed Under [ Architettura ]
Le solite letture per l’estate

Ordinati settimana scorsa e stamattina sono arrivati nuovi fiammanti:
Architecture Books

1. Patterns Of Enterprise Application Architecture (datato ma sempre valido) -  510 pagine
2. Domain Driven Design - 509 pagine
3. Enterprise Integration Patterns - 648 pagine

[Update]
Si aggiungono alla lista altre tre letture, anche se il libro di Andrea e Dino è piu' una formalita' :) :
4. Microsoft® .NET: Architecting Applications for the Enterprise - 304 pagine
5. Test-Driven Development in Microsoft® .NET - 304 pagine
6. Continuous Integration: Improving Software Quality and Reducing Risk - 336 pagine


Totale pagine da leggere dense di concetti: 1667 [Update: 2611]. C’è da divertirsi.

Matteo Migliore.

6 Comments Filed Under [ Architettura ]
Esempio di DependencyInjection per gestire la security di ASP.NET usando WCF e Unity

Su CodePlex ho pubblicato un semplice esempio su come rendere l’applicazione “dipendente” dalle DipendencyInjection :-). Bel controsenso. Scherzi a parte l’applicazione (mantenuta come sempre il più semplice possibile) pone il fuoco su come adottare un framework di IoC, wrappandolo, e quindi rendendo trasparente anche quello, e su come risolvere uno dei tanti problemi delle applicazioni web, come ad esempio cambiare i Membership e Role provider. In questo caso ci sono due implementazioni, la più interessante è quella che sfrutta WCF per gestire le credenziali. Intanto la trovate qui. Appena ho un attimo di tempo scriverò un po’ di documentazione e magari ne sviluppo una seconda versione più “real-world”, sfruttando anche Silverlight e il porting Silverlight di Unity.

Eccola qui, DependencyInjection sample to build a security system using-WCF, Unity, ASP.NET.

Se avete domande sparate pure.

Matteo Migliore.

[Architecture] DataSet vs Entity e il LazyLoading
Come sempre il NG è fonte di ispirazione... L'argomento DataSet vs Entity è ormai trito e ritrito, ma per chi è agli inizi non è banale. Prima di tutto voglio chiarire, secondo me, in quale scenario i DataSet possono essere utili: i DataSet sono la rappresentazione in memory del DB, quindi "sono dei rettangoli" (cit. Andrea) e sono stati creati per rappresentare fedelmente i DB (non uno storage qualsiasi), pertanto sono presenti righe, colonne, relation etc..., ma niente di più. Se è necessario fare un travaso di dati, eventualmente elaborarli e poi aggiornare il DB, possono essere utili, non avrebbe molto senso perdere tempo a scrivere un Domain Model e rispettivo Data Layer per fare un'operazione di questo tipo. I DataSet possono anche essere utili in "applicazioni che non vedranno mai la versione 2.0" (cit. Raffaele), anche se in questo caso il beneficio mi sembra minimo, considerando che l'unica cosa che si evita è di scrivere il DAL, perchè anche le classi hanno un designer!

In tutti gli altri casi è necessario scrivere un Domain Model (le entity e le loro relazioni), un Data Access Layer (possibilmente astratto, vedi NSK), un Service Layer che contiene l'application logic (regole di business, validazione, security etc...) ed eventualmente il Presentation (in varie tecnologie: Windows, Web, Web + Silverlight, Mobile). Un'applicazione monolitica è difficilmente aggiornabile e non risponde all'esigenze del mercato, che richiede reattività e versatilità.


Domain Model

Domain Model

Creare un Domain Model con classi e custom collection produce dei grossi vantaggi rispetto ai DataSet:
- è possibile sfruttare pienamente il paradigma OOP
- le classi rappresentano data & behavior, i DataSet molto difficilmente
- le performance migliorano notevolmente (si possono creare dei DTO ad-hoc, per ogni servizio esposto dall'application server)
- il Data Access Layer può creare delle classi proxy (NHibernate lo può fare anche dinamicamente) che consentono di caricare i dati in modo lazy, cioè solo quando necessario (e.g. nel "get" di una property pesante, come un'immagine, non alla crezione dell'oggetto) 


Layering

E' necessario stratificare correttamente i blocchi funzionali dell'applicazione, e renderli indipendenti fra di loro, perchè l'applicazione sia versatile e si riescano a riflettere i cambiamenti alle logiche in modo tempestivo, e per rendere scalabile quanti più blocchi possibili, in modo che all'aumentare delle richieste sia possibile migliorare le performance aggiungendo risorse.

In questo scenario ad esempio il Data Access Layer, il livello che si occupa della persistenza dei dati (su DB, file-system o servizi esterni), può essere sostituito a seconda dello storage sul quale si vuole andare, senza modificare nessun altro blocco dell'applicazione, che non conosce assolutamente i dettagli implementativi, ma solo i contratti che ha a disposizione per persistere i dati.

Altra cosa importante è non implementare tutta la logica applicativa nel Business Layer perchè è possibile che più applicazioni lavorino sugli stessi dati, ma con logiche differenti, oppure che anche la stessa applicazione lavori sullo stesso dato ma con vincoli e logiche differenti a seconda del contesto.

Esempio.
Un portale consente la registrazione degli utenti in due modalità:
- light: viene richiesto solamente l'indirizzo email per l'invio della news letter
- full: sono richiesti dati di fatturazione, per l'acquisto di beni/servizi

La classe Person viene utilizzata in entrambi i contesti ma ovviamente le logiche di validazione sono differenti. Se queste fossero cablate in un ipotetico metodo IsValid all'interno della classe stessa, sarebbe difficile (non impossibile) soddisfare.


That's All Falks 

Matteo Migliore.
Add Comment Filed Under [ Architettura ]
[Architecture] Aforismi per l'architettura

A mio modo di vedere (confermato dagli infiniti post a riguardo) l'architettura e le metodologie software possono essere riassunte nella testa di un buon architetto con cinque o sei aforismi fondamentali, Fowler stesso sforna in continuazione "aforismi" per riassumere al meglio i suoi preziosi consigli. Chi è un buon architetto? La sua astrazione non è banale, i punti di vista sono molti, ma se è vero che una delle definizioni di intelligenza è "la capacità di adattare a proprio vantaggio il mondo circostante", forse, un buon architetto software è colui che riesce ad "ottenere la soluzione più vantaggiosa dati: il progetto, le tecnologie e il team a disposizione". In quest'ottica il project manager e l'architetto tendono ad una sfumatura di ruolo. La frase che mi ha colpito, e che purtroppo tengo troppo poco come faro nella nebbia è: "è più facile unire le stupidità che far collaborare le intelligenze". Pensandoci, questo aforisma è vero in molti casi, nei team in cui lavoro, specialmente nella fase iniziale, si tendono a produrre molte "collisioni" su chi si deve occupare di cosa e a stabilire quale sia la soluzione più intelligente, tendendo spesso a voler far vincere la propria. Lo sforzo maggiore invece si dovrebbe investire nel capire come orchestrare al meglio il cervello di tutti per produrre una sinfonia di capacità che diano il massimo nella risoluzione del problema centrale: il progetto. Come sempre, tutte queste riflessioni, anche banali, sono espresse modestamente, senza alcuna pretesa, forse sono più un memorandum per me che le scrivo, per ricordarle la prossima volta che mi affaccerò ad un nuovo scenario, ad una nuova sfida :-).

Matteo Migliore.

Add Comment Filed Under [ Architettura ]
[Tip] Versioning degli Assembly di una stessa solution

Un semplice tip che mi ha consigliato Mauro per il versioning degli assembly a cui non avevo pensato, ma utile per avere un repository comunue delle informazioni relative alla società, nome e versione del prodotto e altre informazioni. In pratica anzichè definire un file AssemblyInfo.cs (o .vb) per ogni progetto, si crea un file condiviso in tutta la soluzione (o più soluzioni) e lo si referenzia in ogni project come link.

In questo modo tutti gli assembly avranno associate le stesse informazioni, potendo ovviamente redefinire quelle specifiche e legate al project.

Qui trovate come fare:
http://weblogs.asp.net/lorenh/archive/2004/09/20/232200.aspx

La condivisione delle informazioni è utile specialmente se utilizzata nella metodologia del Continuous Integration, uno dei pilastri dell'Extreme Programming. Uno dei sostenitori? Il mitico Martin Fowler, amato da Andrea (anche se lui dice di no ).

Un tool che assiste la pratica del Continuos Integration è Cruise Control .NET.

Matteo Migliore.

Add Comment Filed Under [ Tip Architettura ]