Programming Languages Hacks

Importanti regole per linguaggi di programmazione rilevanti come Java, C, C++, C#…

  • Subscribe

  • Lettori

    I miei lettori abituali

  • Twitter

DDD semplificato nel mondo reale

Posted by Ricibald on July 29th, 2014

Il DDD è un ottimo pattern ma se si implementa al 100% si rischia di ottenere troppa complessità rispetto a domini quasi sempre non così complessi da giustificarne una totale aderenza.

Basti riflettere infatti sul numero di astrazioni introdotte per fare una semplice insert:

  1. Application inizializza lo Unit of work e coordina i vari Domain Service
  2. Domain Service ottiene dal suo Repository il proxy del Aggregate che ha attivo il change tracking. Se necessario esegue logica specifica del caso d’uso che non si rimappa nel dominio
  3. Aggregate coordina il comportamento desiderato delegando le varie sottofunzioni alle varie Entity o Value Object in stile OO
  4. Entity o Value Object alterano il proprio stato, registrato dal change tracking verso lo Unit of work
  5. Application richiede il commit dello Unit of work
  6. Unit of work apre una micro-transazione che riversa su db lo stato alterato tracciato

Domain Service: perché??

Riporto di seguito una frase di Martin Fowler su cui mi trovo d’accordo:

Any logic that’s particular to a single transaction or use-case is normally placed in Transaction Scripts, which are commonly referred to as use-case controllers. Behavior that’s used in more than one use case goes on the domain objects which are called entities.
Although the controller entity approach is a common one, it’s not one that I’ve ever liked much. The use-case controllers, like any Transaction Script tend to encourage duplicate code. My view is that if you decide to use a Domain Model at all you really should go the whole hog and make it dominant

Il Domain Service è sostanzialmente uno use-case controller che incoraggia alla duplicazione di codice. Se veramente un’operazione è specifica di un caso d’uso bisogna comunque sforzarsi di farla entrare a pieno titolo del dominio. In altre parole: il Domain Service non deve esistere…

Repository e Unit of Work: necessari??

Il Repository pattern consente di ottenere dati da un data source layer mimando una collezione in memoria nascondendo la complessità del sottostante accesso ai dati facendo uso internamente di uno o più oggetti DAO e del pattern Query Object. Nel pattern è importante notare che è normalmente assente il concetto di Update: questo viene inferito automaticamente dallo Unit of work grazie al change tracking sulle entità restituite dal Repository.

Il pattern è efficace poiché tratta il db come aspetto secondario e permette in una prima fase di concentrarsi esclusivamente su GUI, business e TDD. Il pattern è però applicabile solo in presenza di framework ORM che gestiscano in modo efficace il change tracking e il relativo Data Mapper.

A volte il Repository pattern non è però applicabile poiché il data source layer sottostante non è un db, bensì un web service REST o SOAP o una lista Sharepoint. Implementare un meccanismo custom di change tracking diventa veramente complesso e rischioso e non è praticabile.

Bisogna dire addio quindi al DDD e tornare al classico Transaction Script? In realtà si possono implementare versioni semplificate del Repository pattern.

Repository con Unit of Work “a grana grossa”

Ciò che rende complesso il change tracking è la granularità fine: ogni singola modifica viene registrata per contribuire in modo puntuale alla query finale.

Si potrebbero ridimensionare le aspettative e semplicemente marcare l’intera Entity o Aggregate come “dirty” e quindi da aggiornare. Questo può essere implementato in modo esplicito o trasparente:

  • (esplicito) Entity esegue ove richiesto il metodo UnitOfWork.Current.SetDirty(this)
    • tramite PostSharp si può implementare in modo automatizzato su tutte le proprietà
    • tramite T4 si possono autogenerare le Entity rimappando da un modello dati (db, xml, …) arricchendo le Entity con i vari SetDirty
  • (trasparente) Repository crea un proxy delle Entity e decora ove richiesto i metodi con UnitOfWork.Current.SetDirty(this)
  • (trasparente) Entity implementa ove richiesto l’interfaccia INotifyPropertyChanged e Repository gestisce gli eventi PropertyChanged registrando la modifica UnitOfWork.Current.SetDirty(item)

Al momento del Commit dello Unit of work questo avrà la lista delle entità da aggiornare. Sarà compito del nostro Unit of work custom di rimappare gli stati “dirty” con i rispettivi metodi nei vari DAO.

Repository senza Unit of Work: update espliciti

L’approccio precedente è una soluzione buona ma richiede persone esperte che sappiano rimappare lo Unit of work con i vari DAO. Un approccio più facilmente comprensibile è quello di annullare del tutto lo Unit of work e aggiungere nel Repository un metodo Update che opera sull’intero aggregato.

Non avendo nessun meccanismo di notifica dei cambiamenti, Application dovrà ricordarsi di invocare Update per riversare le informazioni contenute nelle Entity nel data source corrispondente altrimenti si otterrebbe un’inconsistenza.

Inoltre non avendo uno Unit of work dovremo farci carico della consistenza del blocco di aggiornamenti:

  • se si tratta di un singolo aggiornamento di un Aggregate in un Repository (caso comune) è sufficiente che la transazione sia definita dentro il Repository stesso
  • se si tratta di aggiornamenti di molteplici Aggregate di diversi Repository è necessario aprire una TransactionScope in Application prima di eseguire i vari Update
  • se si tratta di aggiornamenti di molteplici Aggregate con data source eterogenei è invece necessario prevedere un sistema di compensazione implementando il Command Pattern. Si potrebbe anche valutare l’uso del Distributed Transaction Coordinator

Lo svantaggio di questo approccio è che si delega al programmatore garantire che i metodi di update verso il repository siano 1) invocati correttamente 2) implementati correttamente. Per ridurre tale svantaggio si potrebbe trattare un solo singolo update per l’intero aggregato richiamato dall’Aggregate stesso (applicabile finquando salvare l’intero aggregato si mantiene in limiti di complessità accettabili e finquando abbiamo tutte le informazioni su cosa è cambiato).

Quale usare?

Questa tabella non scientifica cerca di riassumere i pro/contro dell’approccio

Repository standard Repository grana grossa Repository con update
Applicabilità Solo db, buon ORM Code gen (PostSharp, T4) Poco refactoring (no XP)
Skill Alto Medio Basso
Investimento Alto Medio Basso
Manutenibilità Alta Media Bassa

Mettiamo insieme i pezzi…

Vediamo come si rimappa il flusso esposto all’inizio con la soluzione “Repository con update” facendo a meno del Domain Service e immaginando il caso in cui nel caso d’uso si debba aggiornare molteplici Aggregate:

  1. Application ottiene dai Repository i vari Aggregate richiesti
  2. Aggregate coordina il comportamento desiderato delegando le varie sottofunzioni alle varie Entity o Value Object in stile OO. Se necessario esegue logica specifica del caso d’uso
  3. Entity o Value Object alterano il proprio stato
  4. Application apre un TransactionScope e richiede a seconda del caso d’uso l’update o add/remove dai Repository
  5. Repository esegue la corrispondente query
  6. Application richiede il commit del TransactionScope e lo chiude

Se invece ci limitiamo a considerare il semplice caso di aggiornamento di un singolo Aggregate il flusso si riduce come segue:

  1. Application ottiene dai Repository i vari Aggregate richiesti
  2. Aggregate coordina il comportamento desiderato delegando le varie sottofunzioni alle varie Entity o Value Object in stile OO. Se necessario esegue logica specifica del caso d’uso
  3. Entity o Value Object alterano il proprio stato
  4. Application richiede a seconda del caso d’uso l’update o add/remove dai Repository
  5. Repository esegue la corrispondente query nella transazione del DAO sottostante
    • Se coinvolge più aggregati si potrebbe sempre creare un unico metodo nel repository Update(AggregateA a, AggregateB b) che aggiorna entrambi gli aggregati senza dover introdurre lo Unit of work o il TransactionScope

Tramite questa strategia si riesce a ottenere il DDD anche in condizioni non ideali (data source eterogenei, ORM non possibili, team non skillato) senza appesantire eccessivamente la gestione, pur pagando in prospettiva in costi di manutenibilità. Questo implica che un modello di programmazione agile come l’XP non è proponibile poiché non è possibile essere aggressivi con il refactoring.

Appendice: esempio di codice

Si riporta un esempio di codice della soluzione “Repository con update” senza unit of work, con un metodo nel Repository che coinvolge più aggregati e che fa uso del Dependency Injection senza interfacce come illustrato nel precedente articolo:

Posted in .net | 5 Comments »

Performance in Left Join e Condizioni Multiple (COALESCE)

Posted by Ricibald on February 25th, 2014

A volte SQL Server produce degli execution plan, come dire… discutibili??

Un esempio è dato dall’operatore COALESCE e LEFT JOIN. Quando si lavora con tabelle molto grandi la query si traduce in un TableScan di milioni di righe laddove non previsto.

Esempio concreto:

SELECT *
    FROM BigTable X
    LEFT JOIN BigTable Y ON X.Id = COALESCE(Y.ParentId, Y.Id)
    WHERE X.Name = 'Something'

La query produce un execution plan che prevede un TableScan su una tabella di milioni di record. Il risultato sono minuti e minuti di attesa…

La stessa query potrebbe essere riscritta come segue per migliorare il risultato:

SELECT *
    FROM BigTable X
    LEFT JOIN BigTable Y ON
        (Y.ParentId IS NOT NULL AND X.Id = Y.ParentId)      -- condizione 1
        OR
        (Y.ParentId IS NULL AND X.Id = Y.Id)                -- condizione 2
    WHERE X.Name = 'Something'

A volte questo workaround funziona, altre volte no. In questi casi sfortunati dovremmo scrivere la query come segue:

SELECT *
    FROM BigTable X                                         -- condizione 1
    JOIN BigTable Y ON Y.ParentId IS NOT NULL AND X.Id = Y.ParentId
    WHERE X.Name = 'Something'
UNION ALL
SELECT *
    FROM BigTable X                                         -- condizione 2
    JOIN BigTable Y ON Y.ParentId IS NULL AND X.Id = Y.Id
    WHERE X.Name = 'Something'
UNION ALL
SELECT X.*, Y1.*                                            -- no match
    FROM BigTable X
    LEFT JOIN BigTable Y1 ON Y.ParentId IS NOT NULL AND X.Id = Y1.ParentId
    LEFT JOIN BigTable Y2 ON Y.ParentId IS NULL AND X.Id = Y2.Id
    WHERE X.Name = 'Something' AND Y1.Id IS NULL AND Y2.Id IS NULL

Riscrivendo in questo modo (semplicissimo) la query avremo delle ottime performance. E meno male che dicono che SQL è un linguaggio dichiarativo…!!

Posted in .net | No Comments »

Quick Debug a Value (Chaining)

Posted by Ricibald on January 24th, 2014

This code fails on method Pay:

Customer customer = repository.GetCustomer(id);
customer.GetOpenOrders().GetLatestOrderItem().Pay();

You have to debug the result value of the method GetOpenOrders. To accomplish this you have to add one row to split the statement:

Customer customer = repository.GetCustomer(id);
IEnumerable<Order> openOrders = customer.GetOpenOrders();   // BREAKPOINT HERE
openOrders.GetLatestOrderItem().Pay();

Having one more row we can now add a breakpoint on row 2. This approach requires to rewrite the statement.
Just adding this extension method we can now debug every value:

[System.Diagnostics.DebuggerStepThrough]
public static T Break<T>(this T t) {
    Debugger.Break();
    return t;
}

Just use in this way:

Customer customer = repository.GetCustomer(id);
customer.GetOpenOrders().Break().GetLatestOrderItem().Pay();

No new rows, just chaining :-) !!

Posted in .net | 9 Comments »

Log4Net Custom Properties

Posted by Ricibald on November 8th, 2013

Log4Net Log Custom Properties

From Tim Lewis’s answer on stackoverflow:

Since ASP.NET does not guarantee that the entire page request will be processed on the same thread, I prefer getting the answer from HttpContext.Current as log4net processes the logging event.

The following GetCurrentPage class implements what the log4net manual calls an “Active Property Value” by overriding its ToString method:

public class GetCurrentPage
{
  public override string ToString()
  {
      if (null != HttpContext.Current)
      {
          return HttpContext.Current.Request.AppRelativeCurrentExecutionFilePath;
      }
      return string.Empty; // or "[No Page]" if you prefer
  }
}

Register this class in Global.asax’s Application_Start in log4net’s GlobalContext.

protected void Application_Start(object sender, EventArgs e)
{
    XmlConfigurator.Configure();
    GlobalContext.Properties["page"] = new GetCurrentPage();
}

When log4net writes the %property{page} part of the line it will call the ToString method of our GetCurrentPage class which will lookup the value in the current request.

The same is possible to log the current HttpContext.

Posted in .net | 2 Comments »

Problemi del Dependency Injection: come migliorarlo?

Posted by Ricibald on October 11th, 2013

Le dipendenze dovrebbero essere ridotte per quanto possibile e seguire principi di basso accoppiamento e alta coesione.

Per aiutare questo nasce il pattern Inversion of Control e i vari framework di Dependency Injection, che consentono di mantenere astratte le dipendenze per poter sostituire i vari “blocchetti” a piacimento. Spesso è un prerequisito fondamentale ai test automatizzati unitari.

Problemi dell’IoC (DI)

Problema 1: troppa astrazione

Mantenere un’astrazione troppo elevata non è sempre un bene e potrebbe creare in realtà problemi al codice.
Spesso chi usa framework di DI rende qualunque dipendenza astratta (così stiamo riscrivendo il framework base!), in realtà dovrebbero esserlo solo quelle poche dipendenze di cui sappiamo che ci sarà una sostituibilità (per es. per i test) e per il resto ricordarsi sempre di seguire le buone regole Object Oriented e relativi Design Pattern (Strategy, Decorator, Adapter).

Ricordarsi buone regole di OO e Design Patern significa quindi ad es. implementare il pattern Strategy utilizzando il container IoC poiché altrimenti nel pattern il Context non istanzierebbe lui il ConcreteStrategy, alterando così un pattern consolidato. Il DI serve solo a risolvere le dipendenze non a implementare pattern. Detto in altri termini:

Il DI non sostituisce la buona POO e relativi Design Pattern!

Se si guarda bene, in realtà, il DI richiede che si abbia anche maggiore competenza nella programmazione OO poiché apre le porte a errori grossolani che normalmente verrebbero segnalati dal compilatore. Ad es. i riferimenti circolari non farebbero nemmeno compilare il progetto, ma se in un progetto abbiamo interfacce disaccoppiate tra loro e in un altro progetto le relative implementazioni, in un classico 3-layer potenzialmente il layer infrastruttura potrebbe invocare un metodo del layer presentation (OMG!).

Nota 1: il bisogno reale dell’astrazione

Il DI spinge come abbiamo detto a un’eccessiva astrazione: immagina di voler definire un’interfaccia ILog. Deve essere astratta, quindi indipendente dalla tecnologia e dalla destinazione, giusto? Se questi sono i criteri rischiamo di definire un’interfaccia ILog eccessivamente complessa quando tutto quello che dobbiamo fare è… loggare!

Sei d’accordo con il ragionamento? Concettualmente è valido vero? Ma nel componente ILog dell’esempio in realtà è un ragionamento sbagliato: bisogna fare un discorso più articolato.

Cercando di ricavare una regola, è necessario creare astrazioni (aumentandone quindi la complessità) se:

  • si deve sostituire completamente l’implementazione interna di un componente con un’altra implementazione completamente funzionante
  • si potrebbe sostituire completamente l’implementazione interna di un componente con un’altra implementazione completamente funzionante e tale componente viene invocato in tanti punti

Quindi se ad es. abbiamo un componente SecurityChecker acceduto solo alla login tutto sommato non ha senso astrarlo: andiamo sul concreto e se cambierà implementazione (da DB a LDAP) cambierà anche il contratto esposto dal componente. Richiederà il refactoring in un singolo punto: la login page, ma non sarà un grosso problema e ci saremo risparmiati tanta complessità in più.

Se viceversa abbiamo un componente ILog questo sarà utilizzatissimo in tutti i punti dell’applicazione. Avere un’interfaccia stabile è importantissimo o si pagherà la penalità di un refactoring costosissimo. Per tali componenti avere un’interfaccia astratta è fondamentale.

Se invece abbiamo un componente SecurityCheckerMock o SecurityCheckerStub è vero sì che sostituisce l’implementazione, ma tale sostituzione non ha pretese di essere completa. Per questo si possono evitare astrazioni e costruire un SecurityCheckerMock che semplicemente eredita da SecurityChecker.

Se infine abbiamo un’applicazione multipiattaforma che deve supportare diverse modalità di autenticazione (LDAP, OAuth, DB) allora nel componente SecurityChecker siamo costretti a definire un’interfaccia abbastanza astratta da comprendere le varie implementazioni.

Nota 2: quanta sostituibilità?

La prima regola appena citata nel creare astrazioni:

si deve sostituire completamente l’implementazione interna di un componente

Apre però uno scenario un po’ preoccupante nel mondo del TDD.

Si consideri la seguente classe, che fa internamente uso di WebClient, XmlSerializer e DateTime.Now per ottenere da un’url remota l’ultima Person salvata da una certa data:

public class Application : IApplication {
    public void GetLastUpdatedPerson() {
        WebClient webClient = new WebClient();
        string lastUpdateDate = DateTime.Now.ToString();
        string personXml = webClient.DownloadString("http://api.myapp.com/person?lastUpdateDate=" + lastUpdateDate);

        XmlSerializer xmlSerializer = new XmlSerializer(typeof(Person));
        using (TextReader reader = new StringReader(personXml))
        {
            return (Person)xmlSerializer.Deserialize(reader);
        }
    }
}

Per abilitare il TDD e quindi la testabilità unitaria della classe Application saremmo obbligati a rimpiazzare tutte le dipendenze con relative astrazioni sostituibili:

public class Application : IApplication {
    private IPersonService _networkManager;
    private ISerializationManager _serializationManager;
    private IDateManager _dateManager;

    public Application(INetworkManager networkManager, ISerializationManager serializationManager, IDateManager dateManager) {
        _networkManager = networkManager;
        _serializationManager = serializationManager;
        _dateManager = dateManager;
    }

    public void GetLastUpdatedPerson() {
        string lastUpdateDate = _dateManager.Now.ToString();
        string personXml = _networkManager.DownloadString("http://api.myapp.com/person?lastUpdateDate=" + lastUpdateDate);
        return _serializationManager.Deserialize<Person>();
    }
}

Questo però significa che in proiezione andremo a wrappare l’intero framework con interfacce sostituibili. Niente da dire, è un approccio formalmente corretto ma rischiamo di aggiungere veramente troppo codice per testare solo che la classe Application coordina correttamente le chiamate passando i parametri giusti: bisogna sempre pesare costi (quanto lavoro e complessità aggiungo) con relativi benefici (“quanto” si testa).

La mia opinione è questa: il software è composto da classi, da moduli e da layer. Secondo me gli unit test puri, che vanno a testare in modo isolato le singole classi, vanno ad aggiungere troppo overhead per consentire la sostituibilità effettiva di tutte le dipendenze.

Molto meglio testare in isolamento i singoli moduli o layer: ha quindi senso costruire un’astrazione attorno al layer di Persistence per testare in isolamento la coppia di layer Application e Domain. O ha senso costruire dei test per la nostra personale libreria di deserializzazione che poi verrà utilizzata direttamente, senza interfacce.

Inoltre ci si dimentica che spesso non si ha un reale bisogno di sostituire l’implementazione: basta configurare l’ambiente in modo opportuno. Prima di un test si possono ad esempio impostare realmente chiavi di configurazione, valori di sessione, condizioni a contorno, web service dummy, database da snapshot, orario del sistema operativo, snapshot di virtual machine con stati “interessanti”. Non bisogna esagerare né nella configurazione (si appesantisce preparazione ed esecuzione dei test) né nella sostituzione (si riscrive il framework), è necessario il giusto compromesso, risultato di tanta esperienza e di tanto refactoring!

Problema 2: l’applicazione, andando nel “concreto”… come diavolo funziona??

Ragionare logicamente su un codice le cui relazioni sono implicitamente legate attraverso configurazioni esterne sottopone a indirezioni in più che ostacolano il lavoro quotidiano. È come se il codice che vediamo avesse una dimensione in più, comprensibile solo ispezionando la configurazione delle dipendenze. Facendo una metafora, basta notare che i siti di e-commerce spesso cercano di ottenere un’esperienza di acquisto “one-click” perché aggiungere un ostacolo a tale processo può compromettere l’acquisto stesso. Per il codice è lo stesso: senza un’esperienza “one-click” per navigare il codice (stile CTRL+Click come Resharper o Eclipse) si rischia di ottenere un complessivo peggioramento della produttività.

L’effetto finale è che risulta complicato seguire il giro finale. Spesso l’unico modo che rimane per capire cosa fa praticamente il codice è… eseguirlo!

Se il codice senza DI è uno Spaghetti Code, il codice con DI diventa in questo modo un Ravioli Code: le classi sono sì disaccoppiate, ma per legarle logicamente tra loro bisogna ricostruire il giro, riproducendo a mente lo stesso Spaghetti Code di prima. In pratica, se le dipendenze sono troppe, potremmo arrivare a un raviolo con un ripieno di tanti spaghetti…

Problema 3: troppa frammentazione

Altro problema è che per ottenere un reale disaccoppiamento tramite DI saremo costretti a definire tante piccole interfacce con relative implementazioni. Sebbene questo sia formalmente valido, applicare buone tecniche nei posti sbagliati può far calare la produttività: far confluire più concetti nella stessa singola classe, sebbene diminuisca la coesione, può risultare per certi scenari più produttivo. Si pensi ad es. a una formula matematica complessa: una cosa è leggere la formula in un unico posto, un’altra è distrecarsi tra vari componenti interdipendenti (e astratti!).

Problema 4: chi istanzia le classi?

Se andiamo a leggere un codice tipico che fa uso di framework di DI:

public class Application : IApplication {
    private IPersonService _personService;

    public Application(IPersonService personService) {
        _personService = personService;
    }

    public void AddPerson(Person person) {
        _personService.Add(person);
    }
}

Il costruttore ottiene da qualcuno un’istanza di IPersonService. Prova a chiedere al tuo IDE chi invoca il costruttore. Come dici? Nessuno invoca il costruttore? L’IDE non è infatti in grado di determinare staticamente chi istanzierà IApplication. Questo complica sia la comprensione del giro, sia l’analisi statica del codice.

Problema 5: trappole nel ciclo di vita delle variabili

Grazie al DI è possibile configurare il ciclo di vita delle istanze. Possono essere Singleton, transient (ogni volta ricreate), thread-scope (legate al thread), request-scope (legate alla richiesta web).

Si veda lo snippet di codice precedente. Piccolo quiz: se IPersonService ha ciclo di vita thread-scope (legato al thread), quando si invoca AddPerson la variabile _personService sarà ricreata quando cambia il thread?

La risposta è… dipende dal ciclo di vita di Application:

Application Scope dichiarato _personService Scope effettivo
Transient Thread-Scope
Thread-Scope Thread-Scope
Singleton Singleton

Se Application è Singleton non importa come è configurato lo scope di IPersonService poiché una volta istanziata Application non verrà mai più risolto. Se quindi IPersonService porta con se uno stato (che dovrebbe essere legato al thread) in questo modo tale stato potrebbe essere invece Singleton, causando un effetto collaterale veramente ostico da rilevare.

Problema 6: analisi statica del codice

Se utilizziamo strumenti di analisi statica del codice come Visual Studio Code Metrics, NDepend o Nitriq otteniamo risultati sfalsati che si rileveranno migliori della realtà effettiva. Se ad es. abbiamo:

  • due interfacce: IPresentation e ICrossComponents. La direzione dovrebbe ovviamente essere: IPresentation vede ICrossComponents (mai viceversa)
  • due implementazioni iniettate: Presentation e CrossComponents
  • uno sviluppatore (moooolto junior) nel costruttore di CrossComponents inietta IPresentation
  • otteniamo un riferimento circolare (!)

Nella pratica avremo un riferimento circolare e un codice scritto male. Ma nei risultati dell’analisi questo non emergerebbe: le due classi Presentation e CrossComponents risulterebbero come mai usate e quindi verrebbero escluse dall’analisi mentre le due interfacce IPresentation e ICrossComponents risulterebbero autonome quando in realtà creano un riferimento circolare.

Si noti che lo stesso problema si ha per:

  • la compilazione: avremo molti warning che in realtà non sono veri problemi, portando presto a ignorare qualunque warning
  • il code analysis di Visual Studio genererebbe molti warning che in realtà non lo sono, costringendoci a ignorare tali warning e, alla lunga, a precluderci i benefici del code analysis in generale
  • i progetti di architettura, che hanno il compito di validare la comunicazione tra i layer, non sarebbero in grado di rilevare il codice che non rispetta i vincoli architetturali stabiliti
  • il Full Analysis di Resharper indicherà che molte classi non sono mai usate, rendendo lo strumento meno potente e a volte anche scomodo
  • il test impact analysis basato su analisi statica (sebbene quelli di Microsoft si basino invece da una baseline di test eseguita)
  • il nuovo CodeLens di VS2013 che si basa su analisi statica per offrire popup informative su metodi per mostrare relativi test e utilizzi
  • poiché molti IoC/DI si basano su configurazione dinamica delle dipendenze, il dead code elimination (come Resharper, Telerik, SmartAssembly o MonoLinker) rileverebbero codice non utilizzato che in realtà verrebbe caricato tramite reflection. I tool non sarebbero usabili.
  • poiché molti IoC/DI si basano su configurazione dinamica delle dipendenze, la pratica di obfuscation (tramite DotFuscator o SmartAssembly) rinominerebbero le classi che contengono le implementazioni, le quali non sono poi più ritrovabili in fase di ottenimento della classe dal container IoC/DI

Questi problemi sono tutti presenti se si usa un framework IoC/DI basato su configurazione (es. Unity). Quelli invece basati su compilazione tramite generics (es. Ninject) non soffrono di alcuni di questi problemi poiché il compilatore “sa” che le implementazioni verranno prima o poi utilizzate.

Problema 7: Design by Contract (DbC) non verificabile

Il Design By Contract si basa sull’idea che l’interfaccia debba funzionare correttamente solo se i chiamanti invocano tale interfaccia in modo corretto e che l’interfaccia non debba quindi ridondare la verifica di condizioni che già devono aver verificato i chiamanti. Il DbC è opposta al Defensive Programming in cui l’onere della verifica è invece del servente, non del chiamante.

Erroneamente si tende a pensare che quando si ha un’interfaccia automaticamente si ha un contratto, in realtà non è così. Per avere un contratto devono essere documentate e, se possibile, verificate automaticamente le caratteristiche corrette di input, precondizioni, postcondizioni e invarianti.

Esistono diversi sistemi per abilitare la verifica automatica dei contratti. La soluzione Microsoft per questo si chiama Code Contract e consente sia una verifica dinamica sia una verifica statica, cioè a tempo di compilazione.

Esempio pratico:

public class Main {
    public static void Main() {
        IoC myContainer = GetConfiguredIoC();
        IApplication app = myContainer.Get<IApplication>();
        app.AddPerson(null);
    }
}

public class Application : IApplication {
    private IPersonService _personService;

    public Application(IPersonService personService) {
        _personService = personService;
    }

    public void AddPerson(Person person) {
        Contract.Requires(person != null);
        _personService.Add(person);
    }
}

Guardando il codice, il metodo AddPerson viene invocato passando null e quindi il chiamante sta violando il contratto. Nonostante questo, l’errore non verrà segnalato a tempo di compilazione, poiché in realtà Main staticamente non sa che la classe sarà Application e quindi non può analizzare staticamente le relative precondizioni.

Ora potremmo anche stare a discutere dei limiti dei Code Contract ma fare retorica non risolve i limiti dei framework a cui dobbiamo adeguarci. La lezione da capire è semplicemente che molti tool che aiutano la produttività hanno bisogno di conoscere le dipendenze in modo statico e molti di questi tool sarebbero inevitabilmente penalizzati.

Problema 8: prestazioni

Avere tanti concetti indipendenti significa non doverci legare all’una o l’altra tecnologia. Se vogliamo fare le cose pulite, significa avere ad es. un progetto MyProject.Persistence con le interfacce e progetti con le implementazioni: MyProject.Persistence.InMemory, MyProject.Persistence.MySql, MyProject.Persistence.SqlAzure. Questo poiché se utilizziamo MySql come persistence non vogliamo portarci dietro le dll di Azure.

Il risultato è avere tanti progetti in VS e tante dll relative. Il progetto finale “reale” non avrà le reference a tutte le dll ma solo a quelle effettivamente necessarie (es. Persistence.MySql) mentre il progetto di “test” avrà le reference verso altre dll (es. Persistence.InMemory).

Il problema non è avere tanti progetti ma è la strategia di compilazione di VS (cioè di MSBuild). Il linguaggio C funziona come dovrebbe: ricompila solo le classi effettivamente impattate da una modifica. In linguaggio C, se quindi ho X che usa Y che usa Z e viene modificata l‘implementazione di Z (ma non l’interfaccia) il compilatore ricompila solo Z lasciando inalterato Y che si basa su un’interfaccia non modificata. Se invece viene alterata l’interfaccia di Z ricompila solo Y lasciando inalterato X. Questo significa che se nel kernel linux si va a modificare l’implementazione network.c la compilazione sarà immediata poiché l’interfaccia non è stata alterata. Una compilazione in un secondo, in un progetto di milioni di righe…

Come funziona invece VS? Se siamo nell’ambito dello stesso progetto… buone notizie, VS compila in modo efficiente seguendo (più o meno) gli stessi principi del compilatore C. Se però si tratta di progetti diversi… facciamo un esempio. Ho tre progetti: X che referenzia Y che referenzia Z e viene modificata l’implementazione di una classe di Z (ma non l’interfaccia): il compilatore ricompila Z e, a cascata, ricompilerà Y e X (!!!).

Nella pratica, se modificherò un dettaglio implementativo del progetto Infrastructure a cascata verranno ricompilati tutti i numerosi progetti che il Dependency Injection mi ha “obbligato” a definire. La ricompilazione può essere anche molto lunga se utilizziamo tool di postcompilazione (come PostSharp) o tool di analisi statica del codice (come i Code Contract) o tool di produttività personale (come Resharper).

Definire tanti progetti ha i suoi vantaggi (es. separazione delle parti e rimpiazzabilità della dll) ma spesso non ben compresi (se rimpiazzo una dll devo rimpiazzare anche le dipendenti?). Avere tante dll in un progetto con IoC/DI diventa quasi un obbligo ma il costo in termini di produttività quotidiana potrebbe essere alto.

Un “nuovo” approccio: sostituzione statica

Ora ragioniamo su un punto… ma è sempre stato così? Come veniva scritto il kernel di Linux?

Ricordiamo che “ai tempi” avevamo l’header file bluetooth.h e il relativo file bluetooth.c.
Il file bluetooth.h contiene i prototipi delle funzioni e il file bluetooth.c contiene le relative implementazioni. Questo significa che se kernel.c fa uso di bluetooth.h allora le funzioni invocate faranno uso dell’implementazione trovata in bluetooth.c. Ma se invece siamo in un sistema a 64 bit il kernel di Linux potrebbe compilare invece il file `bluetooth_64bit.c.

Questo significa, portandolo nel nostro mondo OO, che gli header file sono le nostre interfacce e i file .c sono le nostre implementazioni. Cosa cambia rispetto ai framework IoC-DI? Due semplici cose:

  1. la tecnica esisteva dal 1972 (!)
  2. avveniva tutto a tempo di compilazione

Il punto focale è l’ultimo: avveniva tutto a tempo di compilazione. Pensiamoci bene: rimpiazzare IApplication con ApplicationMock può essere utile per i test, ma non c’è bisogno che sia dinamico, può essere risolto a tempo di compilazione.

Come fare a ottenere questo? In due modi:

  1. sostituendo dll che mutano la risoluzione dinamica del tipo
  2. sostituendo il codice compilato internamente tramite direttive di compilazione condizionata

La prima soluzione diventerebbe:

// FILE Main.CS in Console.dll
public class Main {
    public static void Main() {
        Application app = new Application();
        app.AddPerson(person);
    }
}

// FILE Application.cs in Application.dll dal progetto Application.Real
public sealed class Application {   // real implementation
    public void AddPerson(Person person) {
        PersonService personService = new PersonService();
        personService.Add(person);
    }
}

// FILE Application.cs in Application.dll dal progetto Application.Mock
public sealed class Application {   // mock implementation
    public bool AddPersonInvoked { get; set; }
    public void AddPerson(Person person) {
        this.AddPersonInvoked = true;
    }
}

Se la cartella che contiene l’applicazione contiene i seguenti file:

  • Console.dll
  • Application.Mock.Dll

Allora il tipo Application risolto sarà quello con implementazione Mock,

La seconda soluzione tramite direttive di compilazione condizionata diventerebbe invece:

// FILE Bootstrap_Prod.cs (compilato solo in compilation mode RELEASE)
#DEFINE REAL
#DEFINE REPOSITORY_IN_DATABASE
#DEFINE SECURITY_IN_LDAP

// FILE Bootstrap_Test.cs (compilato solo in compilation mode TEST)
#DEFINE MOCK
#DEFINE REPOSITORY_IN_MEMORY
#DEFINE SECURITY_IN_MEMORY

// FILE Main.CS
public class Main {
    public static void Main() {
        Application app = new Application();
        app.AddPerson(person);
    }
}

// FILE Real\Application.cs
#IF REAL
public sealed class Application {   // real implementation
    public void AddPerson(Person person) {
        PersonService personService = new PersonService();
        personService.Add(person);
    }
}
#ENDIF

// FILE Mock\Application.cs
#IF MOCK
public sealed class Application {   // mock implementation
    public bool AddPersonInvoked { get; set; }
    public void AddPerson(Person person) {
        this.AddPersonInvoked = true;
    }
}
#ENDIF

Notato qualcosa? Non ci sono più interfacce!! Se il progetto viene compilato in modalità RELEASE allora il file Bootstrap_Prod.cs viene incluso e il file compilato sarà Real\Application.cs. La classe Main quando istanzia Application otterrà la versione reale senza alcun bisogno di DI. Il giro funziona bene finquando le due classi REAL e MOCK hanno lo stesso fullname (devono quindi dichiarare lo stesso namespace).

Confrontando le due soluzioni la separazione fisica delle dll è la soluzione più semplice, ma meno flessibile rispetto a quella basata su compilazione condizionata, dove è possibile definire molti attributi che consentono di configurare a tempo di compilazione in modo molto puntuale l’implementazione da fornire.

Vantaggi dell’approccio a sostituzione statica

L’approccio abilita la stessa sostituibilità di implementazione del DI con i seguenti vantaggi:

  • il codice è facilmente navigabile (CTRL+Click)
  • la leggibilità del codice è diretta
  • la costruzione delle istanze è diretta
  • il ciclo di vita delle istanze è semplice da seguire
  • l’analisi statica del codice produce risultati veritieri, diventando uno strumento utile alla qualità del codice
  • i progetti di architettura possono validare il codice
  • errori grossolani come riferimenti circolari sono ora impediti
  • il codice è più performante poiché non ha l’indirezione del container IoC

Purtroppo l’approccio ha anche i suoi svantaggi

Problema 1: disallineamento (solo con la compilazione condizionata)

Il punto forte e il problema al tempo stesso è che viene compilato solo il codice interessato: questo potrebbe portare a non compilare per tanto tempo la versione MOCK con forti rischi di disallineamento. Inoltre strumenti di refactoring andrebbero a propagare i cambiamenti solo nelle parti attualmente compilate.

In questo caso è necessario avere un meccanismo che compili automaticamente nelle varie configurazioni. È sufficiente scrivere un semplice script di build tramite MSBuild o NAnt che genera i diversi binari nelle varie configurazioni e includerlo in un processo automatico di verifica.

Si noti che questo problema si presenta solo con la seconda soluzione (tramite direttive di compilazione condizionata). Nella prima soluzione semplicemente si andrà a creare un pacchetto che avrà o meno una certa dll, ma potranno essere sempre tutte compilate.

Problema 2: rimpiazzare con mock

L’approccio funziona bene con gli stub (implementazioni complete, come repository in memoria) ma funziona male con i mock (implementazioni specifiche del test per forzare un certo comportamento della dipendenza).

I framework di mocking, come Moq, funzionano generando dinamicamente implementazioni “al volo” di interfacce. Spesso questi framework chiedono di poter lavorare su un’interfaccia pura e solo i framework più evoluti possono lavorare con una classe concreta i cui metodi siano ridefinibili da una sottoclasse (virtual). Questo porcherebbe a sporcare tutte le classi con vari virtual in tutti i metodi.

Inoltre non basta riuscire a definire il mock, bisogna anche passarlo nel metodo che si sta testando. Senza IoC la dipendenza non è esternalizzata e non la possiamo impostare, poiché viene costruita all’interno del metodo stesso. In questo caso l’unico modo è fare, come nell’esempio precedente, una vera e propria implementazione mock. Per diminuire il lavoro ripetitivo si può generare il codice tramite T4 Text Templates o creando shim tramite framework molto particolari come Microsoft Fakes.

Problema 3: riuso delle istanze

A volte riusare la stessa istanza all’interno del codice è utile ed esiste il pattern Singleton per questo. Il problema è che il Singleton presenta forti problemi legati al testing e alla concorrenza e rappresenta una scelta architetturale molto vincolante che rende invasivo l’eventuale cambio di rotta.

Per questo si dovrebbe usare un container che abiliti il riuso della stessa istanza. Ragionando in questo modo rischiamo però di avvicinarci progressivamente a una versione “lite” del pattern IoC da cui cerchiamo di allontanarci.

LA SOLUZIONE: Dependency Injection senza interfacce

Bilanciando pro e contro il problema non è tanto la presenza di un framework DI, che ha numerosi vantaggi, quanto il fatto di puntare sempre, ovunque, verso interfacce e astrazioni invece di classi concrete.

La soluzione è scegliere un approccio misto: IoC+DI che non lega verso interfacce ma verso classi concrete costruite o (prima soluzione) in dll differenti o (seconda soluzione) tramite compilazione condizionata*.

Il codice diventa quindi qualcosa del genere:

// FILE Main.CS
public class Main {
    public static void Main() {
        IoC myContainer = GetConfiguredIoC();
        Application app = myContainer.Get<Application>();
        app.AddPerson(person);
    }
}

// FILE Real\Application.cs
#IF REAL
public class Application {  // real implementation
    private PersonService _personService;

    public Application(PersonService personService) {
        _personService = personService;
    }

    public virtual void AddPerson(Person person) {
        _personService.Add(person);
    }
}
#ENDIF

In questo modo si ottengono i vantaggi da entrambi i mondi, possono essere definiti mock con Moq ed essere facilmente testati. L’unico svantaggio che rimane è il virtual necessario a ogni metodo, ma questo è facilmente eliminabile in RELEASE aggiungendo uno step di build personalizzato.

Conclusioni

Le nuove tecniche emergenti TDD, DDD, IoC e DI devono essere valutate in modo critico solo dopo averle conosciute bene. Dopo averle conosciute e averci lavorato mi sento di consigliare l’approccio IoC e DI per i vantaggi sulla testabilità e sul controllo del ciclo di vita delle variabili. Ma mi sento di sconsigliare l’indirezione tramite interfacce che crea problemi sulla leggibilità e sull’analisi statica del codice.

Per questo motivo il compromesso DI+IoC+ClassiConcrete ottenuto tramite separazione dll o compilazione condizionata sembra bilanciare bene i vantaggi di ogni tecnica, facendo tornare “in auge” tecniche che risalgono a 40 anni fa.

Posted in design | No Comments »

A Strange ReportViewer Error

Posted by Ricibald on October 11th, 2013

When I visualize my report using SSIS I have the following error:

One or more data sources is missing credentials

After hours of investigation I’ve realized a very strange thing:

If you iterate the ReportViewer’s Controls property in the Init phase (OnInit, Page_Init) you get the error “One or more data sources is missing credentials

To fix it just skip the iteration of Controls property :-)

Posted in .net | 1 Comment »

Come adottare i test nel mondo reale

Posted by Ricibald on September 25th, 2013

Perché testare (è una domanda seria…)

Testare può significare semplicemente elencare una serie di test in un Word, eseguirli secondo input specifici e riportarne l’esito in un file Excel. Significa passare nottate davanti a un Word per essere sicuri di aver scritto tutto, eseguire i test nei vari ambienti remoti con attese interminabili, riportare meticolosamente gli esiti in un foglio excel. Questo in genere ha serve solo a produrre un grafico di avanzamento al cliente, che può avere una panoramica immediata dello stato dei test.

Il motivo per cui uno sviluppatore odia i test è il fatto che non mirano a verificare realmente le funzionalità (per questo bastano anche sessioni di debug) bensì producano elaborati che servono solo per la forma, senza puntare alla sostanza. Eseguire test predeterminati non è efficace nel trovare nuovi bug, bensì fa emergere solo che i test non sono mai stati fatti, probabilmente perché abbiamo perso tempo a produrre questi file Word ed Excel che producono “fuffa” inutile. Condiamo il tutto con la ripetitività delle operazioni, la lentezza degli ambienti, la fretta e le aspettative stressanti e avremmo ciò che nessuno vorrebbe mai fare. Fare cose noiose significa farle male, quindi probabilmente sbagliarle e sentirsi dequalificati. Devo continuare con i contro…?

In realtà scrivere test dovrebbe essere un vero e proprio stile lavorativo, che deve coinvolgere la stesura dei requisiti (i test sono istanze di requisiti) e lo sviluppo in tutto il ciclo di vita. Non si tratta di forma ma di molta, molta sostanza. Scrivere i test in modo che siano semplici da scrivere, veloci da eseguire, isolati e facilmente riadattabili è una vera e propria sfida che richiede molta competenza e che di conseguenza risulta più che appassionante.

Senza noia (scrivere test è stimolante), senza stress (i test migliorano la confidenza nel codice), senza interminabili sessioni remote di troubleshooting (i test evitano regressioni) il lavoro dello sviluppatore si trasforma nell’implementare le nuove funzionalità, che costituisce la parte stimolante (e divertente) del lavoro. Devo continuare con i pro…?

Come testare…

Rispetto a un requisito dovrebbero essere previste le seguenti tipologie di test:

  1. per impedire regressioni nei layer applicativi scrivere i vari unit test secondo approccio TDD (mantra red/green/refactor). Simulare le dipendenze (es. db). Scrivere unit test significa dettagliare tramite esempi concreti il requisito spendendo circa il 50% del tempo dello sviluppo:
    • in mancanza di un input o output ben definito utilizzare il baseline test: testa, salva output in un file e al prossimo test confronta l’output con quanto salvato precedentemente nel file
    • non scrivere test specifici per un certo valore cablato, bensì rendili concettualmente veri non legandoti a un input particolare
    • non accorpare in un singolo test più clausole ma crea più test separati
    • non cambiare o rimuovere un test unitario a meno che non cambi il corrispondente requisito
    • scegli i valori di input dei test seguendo il model-driven testing: testa i valori limite e immediatamente contigui
    • al termine del giro mantra red/green/refactor verifica il code coverage che sia almeno 80% per controllare quali execution path sono stati omessi dai test
    • testare i layer applicativi come se fossero API generiche, senza legarle a un client particolare
  2. per impedire regressioni nel presentation layer (UI) scrivere coded UI test che replicano la pressione dei pulsanti o l’edit delle textbox (usando TFS o Selenium o WatiN). Simulare le dipendenze (es. layer application).
    • attenzione: questi test servono solo a testare la UI in isolamento ma non sostituiscono i test unitari dei layer applicativi
    • per semplificare la manutenzione dei test mantenere, a fronte di modifiche grafiche, gli stessi ID degli elementi grafici per non introdurre una breaking change nel test
  3. per verificare che il requisito sia interamente soddisfatto trascrivere un’istanza del requisito in un test case con i relativi step manuali dettagliati. Può essere trascritto prima o dopo aver prodotto il codice. Deve essere eseguito a implementazione completata in un ambiente completamente integrato. Un sottoinsieme sarà successivamente candidato a essere automatizzato
  4. per verificare che il requisito soddisfi caratteristiche minime creare una serie di smoke test rapidi da eseguire manualmente in sequenza
  5. per ricercare nuovi bug nel requisito condurre exploratory test. Una volta rilevata una situazione anomala è possibile trascrivere in uno script gli step precisi per consentire a chiunque di replicare il bug. Alcuni script significativi saranno successivamente convertiti in test automatizzati per garantire sempre la non regressione
    • gli exploratory test possono essere condotti seguendo diversi tour (equivalenti dei design pattern). Il tour può essere positivo (si verificano storyboard, CRUD di entità e relazioni, cambiamento di comportamento in diversi stati) oppure negativo (si verifiano variazioni insolite, invarianti dentro l’operation envelope)
  6. per verificare che un bug segnalato non si ripresenti più creare sempre un regression test che verifichi il bug. In questo modo lo stesso bug non dovrebbe più regredire
  7. per impedire bug in fase di deploy condurre dei deploy test andando sempre a generare un installer. Può essere un Installer o un IIS Deployment Package o un deployment script o un ClickOnce Deployment, non importa. Il punto è che deve esistere in quanto solo questo lo rende parte integrante del test. L’installer deve poter essere testato, come qualunque altra cosa. Molti bug rilevati sono spesso in realtà problemi in fase di deploy e determinarli con anticipo semplifica molto la gestione

Come procedere…

La sequenza descritta è quello ideale: test automatici unitari all’inizio, poi test integrati manuali e infine test automatici integrati.

Per arrivare a questo risultato un progetto ha però bisogno di tempo e lavoro per mettere in piedi una tale organizzazione. L’errore più comune in questo caso è avere una forma mentale del tipo “o tutto o niente”.

In realtà l’adozione dovrebbe essere progressiva per sostenere il cambiamento.
La progressione tipo dovrebbe essere la seguente:

  1. sfruttare l’IDE delle proprie macchine implementando i test unitari (applicativi e UI)
  2. adottare un sistema di controllo sorgente (TFS, Git, Mercurial, …)
  3. adottare un file system centralizzato per condividere documenti (TFS Portal, Dropbox, cartelle condivise, …)
  4. adottare un sistema condiviso di task & bug management (TFS, Basecamp, Zoho, Teamlab, Planbox, VersionOne, Bugzilla, Bug Genie, …)
  5. adottare un sistema di build management per abilitare il continuous integration (TFS, Jenkins, TeamCity, CruiseControl, DamageControl, …). Impostare una continuous build (“rolling”) che esegue la maggioranza dei test unitari. Impostare una build notturna che esegue test più estesi, come test di performance, di carico e di sistema
  6. adottare un sistema di gestione ed esecuzione dei test (manuali e automatici) per strutturare e automatizzare i test (Microsoft Test Manager, Telerik Test Studio, Tosca Testsuite, TestDrive, Word o Excel condiviso, …)
  7. adottare un sistema per creare automaticamente ambienti virtuali per semplificare i test in ambienti distribuiti (TFS Lab Environments, TestComplete, VmWare, VirtualBox, …)
  8. adottare un sistema per il test e deploy automatico in ambienti distribuiti (virtuali o fisici)

Già arrivare al punto 6 sarebbe un ottimo risultato :-)
Arrivare al punto 8 significa riuscire a rilasciare in produzione senza intervento umano (!).

Per sapere come si classifica il vostro modo di lavorare potete divertirvi a fare il Joel Test. Se realizzate un punteggio di 12/12 vi mando il cv :-)

Posted in pattern, test | 1 Comment »

Where condition: IEnumerable vs IQueryable

Posted by Ricibald on August 8th, 2013

Check this LINQ To Entities query

    IEnumerable<Book> books = ObjectContext.Books.Where(x => x.Id == 23);
    books = books.Where(x => !x.IsActive);

The query is, as expected, defferred: only when iterating we’ll get the value.

But…this is the query it produces (!!!):

SELECT *
FROM [dbo].[Books]
WHERE [Id] = 23

But… wait!! And the IsActive condition? This is the trap…!!

Solving the main trap

The extension method where exists in two forms:

If at compile time whe are using the first extension method we’ll execute query using LINQ To Objects. It’s deferred, but the filter is applied in memory on the entire result set and doesn’t filter in the data source…!!!

To fix it, “just” make sure to always use IQueryable.Where:

    IQueryable<Book> books = ObjectContext.Books.Where(x => x.Id == 23);
    books = books.Where(x => !x.IsActive);

Or… better (another reason to always use var!!):

    var books = ObjectContext.Books.Where(x => x.Id == 23);
    books = books.Where(x => !x.IsActive);

This produces the following correct query:

SELECT *
FROM [dbo].[Books]
WHERE ([Id] = 23) AND ([IsActive] <> cast(1 as bit))

Solving the dependent trap

Now that we know the rule… take attention to write a similar code or you’ll have the same error:

void Test()
{
    IQueryable<Book> books = ObjectContext.Books.Where(x => x.Id == 23);
    books = FilterActive(books);
    books.Dump();   // show data
}

IQueryable<Book> FilterActive(IEnumerable<Book> books)
{
    return books.Where(x => !x.IsActive);
}

In the example you are filtering using IEnumerable.Where and this leads to the same error. You need to take in input IQueryable collection.

However, if you need to use IEnumerable because you’ll want to be indipendent of IQueryable you can write the following and it will work:

void Test()
{
    var books = ObjectContext.Books.Where(x => x.Id == 23);
    books = FilterActive(books).AsQueryable();
}

IEnumerable<Book> FilterActive(IEnumerable<Book> books)
{
    return books.AsQueryable().Where(x => !x.IsActive);
}

This is a trap, but not a bug. This strange behavior enable this scenario (thanks to @Enzo): the DAL works internally passing IQueryable objects and returns to the caller only IEnumerable. The Business Layer uses the detached IEnumerable to refine the query in memory. The Presentation Layer execute only if needed the mixed query (because deferred).

Posted in .net | No Comments »

Crash Reporting in .NET

Posted by Ricibald on August 6th, 2013

In your .NET windows application you can’t catch all exceptions. There are critical exceptions that leaves your application inconsistent: in this case let your app crash.

But wait… and error reports? You have two alternatives:

  • use the native Microsoft solution: Windows Error Reporting (WER). It’s not easy to customize but it’s fully integrated in Win OS (i.e. when your application freezes). Here how to use WER.
  • use an off-the-shelf crash reporting library:

Note: if your application is an ASP.NET application, just use the excellent ELMAH

Posted in .net | 5 Comments »

Scrum Start: come cominciare??

Posted by Ricibald on August 2nd, 2013

Dal sito Scrum Alliance:

Scrum è un framework Agile finalizzato a completare progetti complessi. Nato per i progetti di sviluppo software, si adatta bene anche per qualunque progetto complesso o innovativo. Le possibilità sono infinite. Il framework Scrum è solo apparentemente semplice.

Questi i punti principali:

  • Il product owner (PO) crea una lista del desiderato ordinato per priorità chiamato product backlog
  • Durante lo sprint planning il team sceglie uno spaccato del desiderato dalla cima della lista, lo sprint backlog, e decide come implementare i pezzi scelti
  • Il team deve completare il lavoro entro un lasso di tempo definito: lo sprint (tra 2 e 4 settimane) ma si riunisce ogni giorno per valutare i progressi (daily Scrum)
  • Nel frattempo, lo ScrumMaster (SM) mantiene il team focalizzato sugli obbiettivi
  • Al termine dello sprint il lavoro dovrebbe essere potenzialmente consegnabile: pronto per l’uso da parte del cliente, per una demo verso uno stakeholder, per la messa in commercio
  • Lo sprint termina con una sprint review e una retrospettiva
  • Con l’inizio dello sprint successivo, il team sceglie un nuovo set dalla cima del product backlog e il ciclo ricomincia

Lo Scrum è semplice, l’adozione prevede una serie di pratiche complesse da padroneggiare. Esistono moltissimi libri e presentazioni a riguardo.

Ma come si comincia??

Qualsiasi guida Scrum spiega il processo a regime, ma non dettaglia gli step iniziali necessari per portare a regime questo processo. L’obbiettivo di questo articolo è dettagliare dal punto di vista pratico “cosa fare” prendendo spunto da questo libro:

  1. Il PO seleziona il team che lavorerà nel progetto
  2. il PO apre il portale TFS e crea un nuovo Team Project scegliendo come template “Scrum” e aggiungendo i relativi utenti del team
  3. il PO convoca il team e gli stakeholder principali per un requirement workshop iniziale.
    • Lo SM (o il PO se non presente) cerca di sensibilizzare i partecipanti sull’esigenza di non pretendere di definire da subito tutti i requisiti: si dovrebbe discutere solo di requisiti di alto livello, senza scendere in dettagli né in questioni tecniche. Lo SM (o il PO) deve moderare questo aspetto.
    • Per chiarire ulteriormente, lo SM/PO spiega il concetto di user story come un requisito espresso dal punto di vista dell’utente “Come XXX voglio fare YYY per ottenere ZZZ” senza andare oltre questa semplice frase ed entrare in dettagli
    • La durata della riunione è stabilita in 3 ore, organizzata in una stanza con una grande lavagna bianca e pennarelli colorati. Ogni postazione avrà postit e penne.
    • Dopo un brainstorming si arriverà a chiarire i vari user story
  4. il PO produce nel proprio ufficio un foglio excel alimentando il backlog con le user story individuate
  5. il PO ordina rapidamente il backlog nell’excel basandosi inizialmente sull’importanza ignorando l’effort richiesto
  6. il PO trascrive nel portale i vari backlog dell’excel creando così nuovi Product Backlog Item in TFS. Lascia molti campi vuoti come Effort, Acceptance Criteria, Test Cases.
  7. due giorni dopo il PO convoca una riunione con il team ed eventuali esperti per stabilire il Definition of Done (DoD) in cui si concordano le qualità minime che il codice deve sempre avere per considerare concluso un certo task (testato, installato, copertura codice 80%, …)
  8. dopo aver definito il DoD, il PO ha le informazioni necessarie per stimare il lavoro. Convoca quindi una riunione di poker planning utilizzando carte fisiche con valori ?, 0, 1/2, 1, 2, 3, 5, 8, 13, 20, 40, 100, infinito. Per ogni user story viene quindi stabilito il peso in story point in termini di confronto tra user story fra loro
  9. terminata la riunione il PO aggiorna l’Effort in story point dei vari Product Backlog Item in TFS
  10. prima di convocare lo sprint planning il PO esegue un risk assessment per riordinare i product backlog secondo quello con più alto rischio (non è legato con l’incertezza assoluta dei requisiti). Il risk assessment può essere fatto in diversi modi: un modo semplice è calcolare il rischio min-max come prodotto tra gravità e probabilità min-max (dipende da eventuali fattori di mitigazione). In TFS semplicemente si possono trascinare le varie user story per riordinare
  11. per mantenere in stato coerente il backlog (operazione di grooming) il PO ha bisogno anche del contributo del team. Il PO stima un 10% di tempo necessario per mantenere il backlog
  12. il PO sceglie la durata per uno sprint tra 2–4 settimane. Una durata bassa (2 settimane) consente di avere feedback più brevi sullo stato di avanzamento del rilascio
  13. il PO per stimare le tempistiche ha bisogno di conoscere la velocità del team (quanti story point in uno sprint). Per farlo ha bisogno prima della capacità in ore effettivamente lavorabili per poi stimare la relativa velocità sulle user story da implementare:
    • per calcolare le ore effettivamente lavorabili il PO considera i giorni lavorativi, le ferie o feste programmate, il tempo necessario per incontri e varie riunioni di Sprint Planning, Sprint Review, Retrospective. Dal risultato sul lavorabile il PO deve inoltre dedurre il tempo di grooming e di drag: tempo perso per attività non previste. In genere in un team nuovo e non affiatato avrà un drag del 25%. Le ore effettive lavorabili a persona devono essere riportate nel tab Capacity di TFS.
    • per ottenere la velocità iniziale del team il PO convoca una riunione di Sprint Planning preliminare. Durante la riunione il team decompone la user story in cima al backlog in vari task stimando per ogni task le ore necessarie. Alle ore ottenute sottrae la capacità del team calcolata precedentemente: se avanza tempo allora il team procede ad analizzare la prossima user story e così via. Se la user story in esame è troppo generica (epic user story) questa viene eliminata (nelle ultime versioni si può ulteriormente aggregare) a favore di user story più di dettaglio che a loro volta sono decomposte in task. Se avanza poco tempo conviene non tirare troppo la corda cercando di aggiungere un altro user story, specialmente se il team è nuovo. TFS è in grado anche di calcolare la previsione (forecast) su quanti sprint sono necessari per completare il backlog basandosi su una velocità del team dichiarata.
  14. Il PO aggiunge in TFS user story e relativi task individuati con corrispondenti ore. Le user story che sono “epic” vengono eliminate
  15. Il PO inizia il release planning basandosi sul forecast di TFS e categorizzando le user story in temi per trovare un filone comune al rilascio e così dare funzionalità al cliente interamente testabili. Poiché nel primo sprint ci saranno diversi chores (messa a punto degli strumenti di lavoro) il primo sprint avrà meno funzionalità testabili. Alcuni temi sono rilasciabili in uno sprint, altri temi più corposi saranno rilasciabili in due o più sprint, perciò non tutti i rilasci saranno regolari.
  16. con le informazioni a disposizione il PO può stendere dei rapporti excel di massima con il time plan e il budget di progetto calcolando stipendi, hardware, software.
  17. il progetto può ufficialmente partire e andare a regime!

Posted in .net | No Comments »