Monday, October 6, 2008

Validating Domain Objects

Introducing Domain Engineering :
All OOP Languages allow users to create reusable components that cut across different domains in any business context. These components becomes an reusable asset to the practicing organization. It is called cross cutting concerns and also referred to the art of grouping objects/data's into families of system (Domain Engineering). The system families are distributed across application domains (With common variabilities and commonalities) within the same organization and/or entire world. The paradigm shift from application engineering to domain engineering gives us the gains of building reusable families of systems.

What are family of system's?
A system family is a library of components that are easily configured with other systems. In .NET a system family could be an .NET assemblies, and in JAVA it is the jar files which contains domain artifacts. When building domain objects we need to ensure that they represent what they are so as not to over engineer a system that will later on back-fire on our investments.

Let us assume the following scenario of a banking system : We have Customer, Account, Statements etc.

If we need to implement the above banking domain issues in C#, we will be modeling them each as C# POCO (Plain Old CLR Object) objects. The following diagrams forms what we would be implementing as our domain artifacts :

You can see the relationships that these object holds to themselves. An Customer object has many account. An customer object also have many statements to one account. This is a simple design of a banking domain system. If we are to create these classes, and add them in a single assembly (JAR file in Java), then, they become reusable across application domains and interfaces.


Mapping domain objects to relational database

The advent of the Object Oriented Relational Mapping has finally come, when the bigger guys in the OOP language community already have the framework interwoven with their runtime systmes. The two main OOP player of today are the .NET framework and the Java Runtime. The .NET framework has introduced the Entity Framework, while the Java people introduced java persistent framework (JPA). The mismatch between relational database and object orientation will soon be over.

When we map components or domain object to a relational database table, we are abstracting the relational semantics away from our code, which is a better thing to do. The following is the Customer code of the banking domain object in the above diagram.

Note the Customer class in the code below inherits from the BaseModel class, which is an abstract class that marks that our domain object can be validated. Note in your implementation, you can use an interface.

public abstract class BaseModel
{
public abstract bool CanValidate { get;}
}


public class Customer : BaseModel
{
private List <> statements = new List();

public List <> Statements
{
get { return statements; }
set { statements = value; }
}
private List <> accounts = new List();

public List <> Accounts
{
get { return accounts; }
set { accounts = value; }
}
}

The Domain Validation Rule Class
Since our domain objects are our relational table representation, we need to ensure that there is a valid object oriented validation before the state of our domain object hits the back end. What is a validation rule. In this example, domain rules are created as .NET attributes, and they will be used on properties of domain objects. For example of some domain rule, here are two types of rules :

Max Length Rule This rules checks the maximum length of a data in a property of a domain object. It inherits from the CustomValidationAttribute abstract class, which will be used to validate any domain object that inherits from the BaseModel

class MaxLengthRule : CustomValidationAttribute
{
private int min;

public int Min
{
get { return min; }
set { min = value; }
}
private int max;

public int Max
{
get { return max; }
set { max = value; }
}

internal override bool IsValid(T value)
{
if (null == value)
return false;

string text = value.ToString();

return (text.Length >= min && text.Length <= max); } }


NotNull rule : This rule checks if a property is null.

internal class NotNullRule : CustomValidationAttribute
{
private object value;

public object Value
{
get { return this.value; }
set { this.value = value; }
}

internal override bool IsValid(T value)
{
return (null != value);
}
}

Let us now decorate our POCO Customer class with our validation rules. The code below show how we will decorate our domain object with attributes of our validation rule :


public class Customer : BaseModel
{
private List <> statements = new List();

[NotNullRule]
public List <> Statements
{
get { return statements; }
set { statements = value; }
}
private List <> accounts = new List();

[NotNullRule]
public List <> Accounts
{
get { return accounts; }
set { accounts = value; }
}
}

Note that we have decorated our customer class with our NotNull Validation rule. This rule ensures that the value of the properties is not null.

Creating the The CustomValidationAttribute class

This class is the base class of all the validation rules that are used in this example, and it holds the entry points to the Validate method which takes the model as parameter. The following code snippet is the full code definition of the CustomValidationAttribute.


[AttributeUsage(AttributeTargets.Property)]
abstract class CustomValidationAttribute : Attribute
{
abstract internal bool IsValid(T value);

internal static bool Validate(T model) where T : BaseModel
{
Type modelType = GetModelType(model);
List validities = new List();

foreach (PropertyInfo propertyInfo in modelType.GetProperties())
{
object[] customAttributes = propertyInfo
.GetCustomAttributes(typeof(CustomValidationAttribute), true);

object value = FindValueByRule(propertyInfo, model);
foreach (CustomValidationAttribute attribute in customAttributes)
{
validities.Add(attribute.IsValid(value));
}
}

return validities.TrueForAll(el => el == true);
}

private static Type GetModelType(object instance)
{
return instance.GetType();
}

private static object FindValueByRule(PropertyInfo propertyInfo, object model)
{
return propertyInfo.GetValue(model, null);
}
}


The code above is the full defination of the base validator class. And to use the validation strategy which i have been explaining, we need to make the following simple call which returns a boolean flag that tells us if our Domain model is valid or not .


Customer customer = new Customer();

bool isValid = CustomValidationAttribute.Validate(customer);


The code above returns a boolean that indicates if the validation operation is valid or not. Happy domain validation.


No comments: