Build Reusable, Testable Queries Part 1

February 13, 2012 — 3 Comments

Queries are complicated to test and nearly impossible to reuse. In systems of all sizes they get duplicated,  modified and augmented to the point where we are afraid to modify them. They are essentially questions about data that generate information upon which we can act. They should be reusable. They should be predictable and above all, they should be testable.

In this series of posts I will show you how this small yet powerful interface can help you build reusable queries which can be tested.

public interface IModelQuery<out TResult, in TModel>
{
    IEnumerable<TResult> Execute(TModel model);
}

Lets start by looking at how we can implement IModelQuery to create a reusable Query that can search for partial matches from lists of strings. The PartialMatchQuery class adheres to a predefined contract, a contact that should not change very often. This contract will allow us to reuse the same query instance over various lists of strings.

To achieve the reusability we’re after, the query parameters are provided through the constructor and stored as instance variables. When we execute the query, we provide the query with a model to query. The model and result types are enforced by the interface. Allowing us to reuse the query with any model that satisfies the IEnumerable<string> constraint.

public class PartialMatchQuery : IModelQuery<string, IEnumerable<string>>
{
    private readonly string partial;

    public PartialMatchQuery(string partialString)
    {
        partial = partialString;
    }

    public IEnumerable<string> Execute(IEnumerable<string> model)
    {
        return model.Where(s => s.ToLower().Contains(partial));
    }
}

Using the query becomes as easy as creating an instance and calling the Execute method with a list of strings.

var listOfNames = new List<string>
            {
                "Emma",
                "Hugo",
                "Janne",
                "Maude",
                "Louis",
                "Felix" };

var query = new PartialMatchQuery("ma");

var result = query.Execute(listOfNames);

Doesn’t this remind you of Regex? Where the pattern is passed into the constructor as a parameter, the string we are matching against is passed into the method. This enables us to reuse the same regex expression over many string instances.

var regex = new Regex(@"\b(\w*ma\w*)\b");

string names = "Emma, Hugo, Janne, Maude, Louis, Felix";
var matches = regex.Matches(names.ToLower());

Benefits of Encapsulating Queries

Queries can have many shapes, sizes and levels of complexity. By encapsulating its logic in an object like PartialMatchQuery, we are effectively protecting ourselves against future changes. We are also actively applying the Open/Closed Principle which states that the implementation of a class could only be modified to correct errors; new or changed features require that a different class be created.

Creating a new class for each query will essentially generate many classes and for some, it may raise an alarm. Fear not, using Visual Studio and tools like ReSharper greatly facilitates working with large amounts of classes. It also allows us to have an organized library of reusable queries that can be classified by type, responsibility or domain. Such libraries can be quite useful when new members join the team.

New members, can quickly browse through the library of queries and grasp the essence of the module. This has the positive effect of lowering the barrier of entry and enables to quickly focus on the business logic instead of trying to understand the thin boundaries between queries and the surrounding code. Separating different types of LINQs can greatly clarify boundaries and eliminate questions like “where  and when does this get executed?”.

At this point it’s important to remind ourselves that queries do not alter the state of a system. Their only goal is to answer questions about the system’s state. Further more, there should only be one answer per question. When designing queries it’s quite important to adhere to the Single Responsibility Principle, which states that a class or module should have one, and only one, reason to change. By focusing a query on a single concern it makes queries more robust and less likely to change.

In upcoming posts we will look at how this interface can simplify testing. We will also go over the possible uses of reusable queries.

Build Reusable, Testable Queries Part 2

 

Content of Interest

References

3 responses to Build Reusable, Testable Queries Part 1

  1. 

    I like the idea. It reminded me of a similar article by Ayende about query encapsulation: http://ayende.com/blog/3955/repository-is-the-new-singleton

    However, I don’t really like ‘Execute’ for the name of the method. It makes me think of a command and it is not clear that the data passed to the query is not going to be altered in some way. It should be clear that you are interrogating a model and not modifying it.

    Like

Trackbacks and Pingbacks:

  1. Test Driving A Web Application Domain Model » Coding My Way - February 6, 2014

    […] where they don’t we can make them so by splitting them into actions and redirects. Like many others, I’ve been through the process of first using the common approach of repositories for each […]

    Like

  2. Links of interest #Week2 | Louis Turmel Blogs - April 30, 2014

    […] Build Reusable Testable Queries Part 1 […]

    Like

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.