Validazione: dove, come, quando, perchè... IMHO.

La validazione è uno degli aspetti a cui ho iniziato a dare un volto nuovo da quando è comparso il VAB . In tutta sincerità, prima del VAB il mio concetto di validazione era un metodo IsValid() all'interno dell'entità di business con qualcosa tipo:

[...]

//DAL validation
if (this.FirstName.Lenght > 50)
{
    isValid = 
false;
}
if (this.LastName.Lenght > 50)
{
    isValid = 
false;
}

[...]

//Business validation
if (this.IsMarried && !this.Partner.IsMarried)
{
    isValid = 
false;
}

[...]

return isValid;

Poi è arrivato il VAB, un modo a mio parere elegante di poter eseguire una validazione "centralizzata" sfruttando gli attributi e reflection. Da quando è nata, questa soluzione da un lato mi è sempre piaciuta, ma dall'altro non mi ha mai convinto del tutto essenzialmente per il seguente motivo:

secondo me alcuni dei passaggi di validazione sono suscettibili al contesto esterno all'entità di business, che addirittura può essere variabile a seconda della situazione in quel momento.

Provo a spiegarmi meglio, aiutandomi con due passaggi relativi al codice di esempio precedente.

La proprietà "IsMarried" è validata in base ad una regola di business, ma cosa succederebbe se il software venisse utilizzato in un paese estero in cui è solo la moglie ad essere sposata (inteso come monogama) con il marito?
L'esempio è indubbiamente forzato, ma spero che faccia capire che quel test di validazione non dovrebbe essere contenuto nell'entità di business, ma piuttosto in una apposita classe di validazione del Business Layer (o Service Layer). Una cosa del tipo:

namespace BusinessLayer
{
    
public sealed class PersonValidator
    {
        
public static bool IsValid(Person person)
        {
            
bool isValid = true;
            
            
//ecc.
            
            
if (person.IsMarried && !person.Partner.IsMarried)
            {
                isValid = 
false;
            }
            
            
return isValid;
        }
    }
}

che a questo punto diventa un validatore specializzato, perdendo quindi la genericità introdotta nel VAB. Si potrebbe definire un nuovo attributo di validazione (un MarriedValidator...) ma comunque il discorso non cambia molto.

Ancora meglio sarebbe separare il validatore concreto, istanziandolo con una factory; un po' come succede per il DataAccessLayer nelle applicazioni multidb.

Tornando al primo codice di esempio, l'altro aspetto su cui mi sono soffermato è relativo alla validazione delle proprietà FirstName e LastName. Mi son chiesto quale fosse realmente il contesto di validazione di queste proprietà e la risposta mi ha portato a due contesti differenti:

1) le regole di business, che definiscono per esempio che il CAP è di 5 numeri (ma di 5 numeri in Italia, a differenza di altri paesi e quindi rientriamo nel discorso di prima). Nell'esempio specifico il CAP dovrebbe essere validato dal validatore del BusinessLayer come per IsMarried.

2) il "database" su cui persistiamo i dati, che ci impone una lunghezza massima a seconda delle caratteristiche dell'RDBMS.
In uno dei suoi esempi più belli, Andrea spiega che la nostra entità di business da persistere è simile, nel concetto, ad un'immagine aperta in un editor: possiamo creare un immagine a 32bit di colore, ma, per esempio, il formato GIF non supporta 32bit di colore ed allora al momento del salvataggio, a seconda del tipo di formato che scegliamo, l'editor effettuerà la validazione per il particolare formato scelto.
Percui magari se si sta utilizzando un DataAccessLayer per Access (teoricamente parlando, eh?) il validatore imporrà un massimo di 255 caratteri, nel caso di SQLServer di (boh...) 1000 caratteri e magari nel caso di... un file xml su uno SmartPhone (!) solo 50 caratteri!

Percui a questo punto la validazione di FirstName e LastName tocca al DataAccessLayer concreto ed al suo validatore specifico, che viene utilizzato a sua volta dal validatore del Business Layer:

namespace BusinessLayer
{
    
public sealed class PersonValidator
    {
        
public static bool IsValid(Person person)
        {
            
bool isValid = true;

            
//Validazione nel contesto database (creazione oggetto dal omessa)
            
isValid = dal.PersonValidator.IsValid(person);
            
            
//Validazione nel contesto di business
            
if (person.IsMarried && !person.Partner.IsMarried)
            {
                isValid = 
false;
            }

            
//ecc.
            
            
return isValid;
        }
    }
}

(NOTA: ovviamente al posto di IsValid é più opportuno un GetValidationErrors() che ritorni l'elenco dei problemi riscontrati, nel codice d'esempio IsValid era più "lineare"!)

Certo, poi a botte di idee e refactoring il tutto dovrà essere ripulito e riordinato, ma almeno adesso una mia personale idea chiara in merito ce l'ho.

...almeno per i prossimi 5 minuti!

Print | posted @ sabato 4 novembre 2006 12:35

Comments on this entry:

Gravatar # re: Validazione: dove, come, quando, perchè... IMHO.
by Michele Bersani at 05/11/2006 01:33

Prova a dare un'occhiata anche a NRuleValidator

workspaces.gotdotnet.com/NRuleValidator
Comments have been closed on this topic.