Specification Pattern – Essentials

Specification pattern is DDD specific way for building
blocks of business logic on top of domain entities.
They are defined as predicates/filters for entities.
They can be combined in more complex logic.
You can benefit from implementation specifics
as some technologies provide many enhancements.

 

To correctly define specification pattern and find an applicable area for it, we should describe 4 categories every software falls into:

  1. Large amount of data (big data)
  2. Performance critical (e.g. stock market apps)
  3. Complex business logic (ERP like SAP)
  4. Complex technologically (working with math, hardware etc.)

Domain Driven Design (DDD), which defines specification pattern itself, is applicable only for group 3.
It buries business logic directly into code, without too much abstraction – and it’s proven it works well.
DDD creates maintainable, readable code, it has it’s own world, terminology etc.,
but it’s applicable ONLY to software with complicated business logic.

Now, what is specification pattern? Let’s start from the C# implementation:


public class SpecificationBase<T> 
{ 
    public Expression<Func<T, bool>> Expression { get; } 

    public GenericSpecification(Expression<Func<T, bool>> expression) 
    { 
        Expression = expression; 
    } 

    public bool IsSatisfiedBy(T entity) 
    { 
        return Expression.Compile().Invoke(entity); 
    } 
} 

Implementation sample:


public sealed class IsReportYoungerThanSpecification : Specification<Report> 
{ 
    private readonly int _days; 

    public IsReportYoungerThanSpecification(int days) 
    { 
        _days = days; 
    } 

    public override Expression<Func<Report, bool>> ToExpression() 
    { 
        return report => report.IssueDate > DateTime.UtcNow.AddDays(-1 * _days); 
    } 
}

Usage samples (in-memory validation):


private void PrintInvoicesReport(int invoiceId) 
{ 
    var report = _repository.GetAll(); 	
    if (!report.HasValue) 
    {
	return; 
    }

    var report = report.Value; 
    var spec = new IsInvoiceReportSpecification(); 
    if (!spec.IsSatisfiedBy(report)) 
    { 
	MessageBox.Show("It is not an invoice report!"); 
	return; 
    } 

    PrintReport(report);
} 

Usage samples (ORM integration):


public class ReportRepository 
{ 
    public IEnumerable<ReportDto> Get(Specification spec, int page, int pageSize) 
    { 
        using (ISession session = SessionFactory.OpenSession()) 
        { 
            return session.Query<Report>().Where(specification.ToExpression())
				.Skip(page * pageSize)
				.Take(pageSize); 
        } 
    } 
} 

Usage samples (building complex queries):


internal sealed class AndSpecification<T> : Specification<T> 
{ 
    private readonly Specification<T> _left; 
    private readonly Specification<T> _right; 

    public AndSpecification(Specification<T> left, Specification<T> right) 
    { 
        _right = right; 
        _left = left; 
    } 

    public override Expression<Func<T, bool>> ToExpression() 
    { 
        Expression<Func<T, bool>> leftExp = _left.ToExpression(); 
        Expression<Func<T, bool>> rightExp = _right.ToExpression(); 
        var andExp = Expression.AndAlso(leftExp.Body, rightExp.Body); 
        return Expression.Lambda<Func<T, bool>>(andExp, leftExp.Parameters.Single()); 
    } 
} 

private void Search() 
{ 
    var spec = Specification.All;	
    if (IsInvoiceReport) 
    { 
        spec = spec.And(new IsInvoiceReportSpecification()); 
    }
    if (expirationDays > 0) 
    { 
        spec = spec.And(new IsOlderThanSpecification(expirationDays)); 
    }	
    return _repository.Get(spec); 
} 

I hope those code snippets are self explanatory. Basing on them, we cans say these are use cases common for specification pattern:

– In-memory validation
– ORM integration
– Building complex queries

A specification should be:

– of concrete type
– parameter-less (or with min. of parameters)
– simple and specific, in order to increase its re-usability
– without interface implemented
– immutable
– satisfy fluent API (And, Or, Not, Identity)

It should be used in projects with high business complexity ONLY, and it should be used ONLY if you have at least 2 out of 3 enumerated purposes for it. The biggest advantage of specification pattern (regardless of technology) is that it wraps potentially complex predicates/filters with class name that highly reflects its business usage. C# based implementation leverages C# lambda-s duality – they can be treated both as expressions or delegates (in LINQ to SQL and LINQ to objects). Nobody guarantees so elegant solution for same idea in other technologies.

Specification pattern is DDD specific way for building
blocks of business logic on top of domain entities.
They are defined as predicates/filters for entities.
They can be combined in more complex logic.
You can benefit from implementation specifics
as some technologies provide many enhancements.

Leave a Reply

Your email address will not be published. Required fields are marked *