Specification pattern versus Query object pattern

Both specification and query pattern are trying to answer simple question: what entities are satisfying the specified rules. Both functionality gives us the possibility, for example, to filter a collection of customers for those older than 18 years old.

What is the difference between specification and query pattern and when should I use former or latter one? The answer is as usual "it depends" and we will try to walk through the most common scenarios.

Design patterns (OOD) versus Domain patterns (DDD)
A pattern is a reusable solution for a problem in software design. The difference between the two groups is small and it is important to remember that the implementations of the patterns from the design patterns group are normally general. Name of the methods are generic, usually unrelated to the domain of the problem (although it is normal that the implementation is influensed by the domain and model to improve readability and maintainability). On the other side, the implementation of patterns from domain patterns group and domain oriented, implementation contains strong domain specific names and is tightly coupled to the specific domain. This ensures better readability, less need of comments and improves also communication between the devs, testers and business (it is very common that to get the decision from the business we need to clarify with them open questions that are often technical and sometimes involves also names of the methods or objects).

Specifications are usually builded over query objects in case of usage of a data mapper. This means specifications are the layer over the data mapper and it's queries.

The above is nice abstract but what it does mean in real world? Lets examinate both patterns and provide examples.

Query object pattern
Is an object that represents a database query. For example we don't have to go far away, every data mapper (e.g. NHibernate) contains an implementation of the pattern (e.g. NHibernate Criteria). With LINQ functionality in C# 3.0+ we can consider integrated query language as a sort of query object pattern.

The query object is then in the lower level translated to the language of data storage (e.g. SQL). The pattern belongs to the group of design patterns and you can query an object in whatever domain you like. You write generic queries to get your data, using generic AND, OR, LIKE, WHERE statements. Basically it is object oriented implementation of the data storage query language (e.g. SQL). Eventually you can wrap then into a class or other functionality, but this is the place where specification pattern comes to play.

Example (NHibernate Criteria):
var posts =
  .Add(Restrictions.Eq("Title","Specification pattern versus Query object pattern"))  

Specification pattern
Also represents a database query but as the pattern belongs to the domain patterns group, you specify what entities you want to get from a data storage in domain oriented way. You write your specifications using strong domain oriented names that are selfexplanatory. Usually the implemenation also supports fluent interface to ensure better reusability.

var posts = repository.Specify<IPostSpecification>()
  .WithTitle("Specification pattern versus Query object pattern")

From the examples above it is clear that the functionality is more or less the same. And it is really true. Specification can be wrapper over a query object that gives you domain specific functionality over generic queries. Another benefit is better support for unit testing and creating stubs or mocks of used specifications.

If we take into account a data mapper that supports LINQ (NHibernate, Entity framework, Linq2Sql, etc), we can build our specifications over the linq functionality. A specification can contain more methods to improve reusability of common functionality:

ICustomerRepository customerRepository =  
    , specificationLocator

IList = customerRepository.Specify<ICustomerSpecification>()

Complex queries can be wrapped to a single and dedicated specification (single responsibility principle - SRP) that is easy to test.

IList = customerRepository.Specify<IVeryComplexSpecification>().ToList();

Both patterns solve the problem of hiding specific data storage query. Query object pattern implementation usually contains general methods like AND, OR, Equal, etc to specify the query. Specification pattern implementation has domain focused method names. The implementation can be wrapper over query object implementation.

The specification pattern usually adds another layer of indirection to your model, when it is builded as wrapper over query object. This brings you another complexity.

On the other hand, the benefit is that the clients of the code (devs) benefit from better flexibility, reusability, readability and communication with business. And the testability is improved, because your code deals with specification in form of interface that is easy to mock.

Check out the open source project generic repository http://code.google.com/p/genericrepository/ for examples of specifications and their usage in generic way.

Žiadne komentáre:

Zverejnenie komentára