Sunteți pe pagina 1din 22

1

Written by Steven van Deursen


on December 11, 2011
12-minute read

Meanwhile... on the command side of my


architecture
Proofread by Peter Parker

This article describes how a single interface can transform the design of
your application to be much cleaner, and more flexible than you ever
thought possible.

Chapter 10 of my book contains a much more elaborate version of this article.

Since I began writing applications in .NET I’ve been separating operations that mutate state (of
the database mostly) from operations that return data. This is basically what the Command-query
separation principle is about. Over time the designs I have used have evolved. Initially triggered
by a former colleague of mine I started to use the Command Pattern about four years ago. Back
then we called them business commands and a single command would represent an atomic
business operation, or use case.

Over the years, the projects I have participated on have increased in complexity and I have adopted
newer techniques such as Test Driven Development and Dependency Injection (DI). The flaws in
this approach to the Command Pattern have become obvious to me. DI has a tendency of exposing
violations of the SOLID principles and this implementation hindered the maintainability of these
applications.

In the early days my implementation of the Command Pattern design consisted of classes that
contained both properties to hold the data and an Execute() method that would start the operation.
The design had an abstract Command base class that contained all of logic for handling transactions,
re-executing commands after a deadlock occurred, measuring performance, security checks, etc.
This base class was a big code smell and was a form of God Object with many responsibilities.
Furthermore, having data and behavior interleaved made it very difficult to mock/abstract that
logic during unit testing. For example a consumer of a command would typically new up a
command instance and call Execute() directly on it, as shown in the following example:

var command = new MoveCustomerCommand


{
CustomerId = customerId,
NewAddress = address
};
2

command.Execute();

I tried to solve this problem by injecting the command into the constructor of a consumer
(constructor injection), but this was awkward to say the least. It remained the responsibility of the
consumer to set all the properties of the object that was passed in and didn’t really solve the
problem of abstracting away the command elegantly. To prevent the command’s logic from being
executed, I had to define a fake version of each command for testing and it did nothing to reduce
the large and complicated base class.

All of these experiences led me to try a design that I had seen others use, but that I had never seen
the benefits of. In this new design, data and behavior are separated. Each business operation has a
simple data container called the command object; my standard naming convention for these classes
is to suffix them with Command:

public class MoveCustomerCommand


{
public int CustomerId { get; set; }
public Address NewAddress { get; set; }
}

The logic gets its own separate class; my standard naming convention for these classes is to suffix
them with ‘CommandHandler’:

public class MoveCustomerCommandHandler


{
private readonly UnitOfWork db;

public MoveCustomerCommandHandler(
UnitOfWork db,
[Other dependencies here])
{
this.db = db;
}

public virtual void Handle(MoveCustomerCommand command)


{
// TODO: Logic here
}
}

This design gives us a lot; a command handler can be injected into a consumer, while the consumer
can simply new up the related command object. Because the command only contains data, there
no longer a reason to fake the command during testing. Here’s an example of how a consumer can
use that command and command handler:

public class CustomerController : Controller


{
private readonly MoveCustomerCommandHandler handler;
3

public CustomerController(MoveCustomerCommandHandler handler)


{
this.handler = handler;
}

public void MoveCustomer(int customerId, Address newAddress)


{
var command = new MoveCustomerCommand
{
CustomerId = customerId,
NewAddress = newAddress
};

this.handler.Handle(command);
}
}

There is still a problem with this design. Although every handler class has a single (public) method
(and therefore adheres the Interface Segregation Principle), all handlers define their own interface
(there is no common interface). This makes it hard to extend the command handlers with new
features and cross-cutting concerns. For example, we would like to measure the time it takes to
execute every command and log this information to the database. How can we do this? In the past
we would either change each and every command handler, or move the logic into a base class.
Moving this feature into the base class is not ideal as the base class will soon contain lots of these
common features, and would soon grow out of control (which I have seen happening). Besides,
this would make it hard to test derived types and enable/disable such behavior for certain types (or
instances) of command handlers because it would involve adding conditional logic into the base
class, making it even more complicated!

All these problems can be solved elegantly by having all command handlers implement a single
generic interface:

public interface ICommandHandler<TCommand>


{
void Handle(TCommand command);
}

Using this interface, the MoveCustomerCommandHandler would now look like this:

// Exactly the same as before, but now with the interface.


public class MoveCustomerCommandHandler
: ICommandHandler<MoveCustomerCommand>
{
private readonly UnitOfWork db;

public MoveCustomerCommandHandler(
UnitOfWork db,
[Other dependencies here])
4

{
this.db = db;
}

public void Handle(MoveCustomerCommand command)


{
// TODO: Logic here
}
}

One important benefit of this interface is that it allows the consumers to depend on the new
abstraction, rather than a concrete implementation of the command handler:

// Again, same implementation as before, but now we depend


// upon the ICommandHandler abstraction.
public class CustomerController : Controller
{
private ICommandHandler<MoveCustomerCommand> handler;

public CustomerController(ICommandHandler<MoveCustomerCommand>
handler)
{
this.handler = handler;
}

public void MoveCustomer(int customerId, Address newAddress)


{
var command = new MoveCustomerCommand
{
CustomerId = customerId,
NewAddress = newAddress
};

this.handler.Handle(command);
}
}

What does adding an interface give us? Well frankly, a lot! As nothing depends directly on any
implementation but instead depends on an interface, we can now replace the original command
handlers with any class that implements the new interface. Ignoring, for now the usual argument
of testability, look at this generic class:

public class TransactionCommandHandlerDecorator<TCommand>


: ICommandHandler<TCommand>
{
private readonly ICommandHandler<TCommand> decorated;

public TransactionCommandHandlerDecorator(
ICommandHandler<TCommand> decorated)
{
5

this.decorated = decorated;
}

public void Handle(TCommand command)


{
using (var scope = new TransactionScope())
{
this.decorated.Handle(command);

scope.Complete();
}
}
}

This class wraps an ICommandHandler<TCommand> instance (by accepting an instance of the same
interface in its constructor), but at the same time it also implements the
same ICommandHandler<TCommand> interface. It is an implementation of the Decorator pattern.
This very simple class allows us to add transaction support to all of the command handlers.

Instead of injecting a MoveCustomerCommandHandler directly into the CustomerController, we


can now inject the following:

var handler =
new TransactionCommandHandlerDecorator<MoveCustomerCommand>(
new MoveCustomerCommandHandler(
new EntityFrameworkUnitOfWork(connectionString),
// Inject other dependencies for the handler here
)
);

// Inject the handler into the controller’s constructor.


var controller = new CustomerController(handler);

This single decorator class (containing just 5 lines of code) can be reused for all of the command
handlers in the system.

In case you’re still not convinced, let’s define another decorator:

public class DeadlockRetryCommandHandlerDecorator<TCommand>


: ICommandHandler<TCommand>
{
private readonly ICommandHandler<TCommand> decoratee;

public DeadlockRetryCommandHandlerDecorator(
ICommandHandler<TCommand> decoratee)
{
this.decoratee = decoratee;
}

public void Handle(TCommand command)


6

{
this.HandleWithRetry(command, retries: 5);
}

private void HandleWithRetry(TCommand command, int retries)


{
try
{
this.decoratee.Handle(command);
}
catch (Exception ex)
{
if (retries <= 0 || !IsDeadlockException(ex))
throw;

Thread.Sleep(300);

this.HandleWithRetry(command, retries - 1);


}
}

private static bool IsDeadlockException(Exception ex)


{
return ex is DbException
&& ex.Message.Contains("deadlock")
? true
: ex.InnerException == null
? false
: IsDeadlockException(ex.InnerException);
}
}

This class should speak for itself—although it contains more code than the previous example, it is
still only 14 lines of code. In the event of a database deadlock, it will retry the command 5 times
before it leaves the exception bubble up through the call stack. As before we can use this class by
wrapping the previous decorator, as follows:

var handler =
new DeadlockRetryCommandHandlerDecorator<MoveCustomerCommand>(
new TransactionCommandHandlerDecorator<MoveCustomerCommand>(
new MoveCustomerCommandHandler(
new EntityFrameworkUnitOfWork(connectionString),
// Inject other dependencies for the handler here
)
)
);

var controller = new CustomerController(handler);


7

By the way, did you notice how both decorators are completely focused? They each have just a
single responsibility. This makes them easy to understand, easy to change—this is what the Single
Responsibility Principle is about.

The downside of these changes is that it can require a lot of boilerplate code to wire up all the
classes that depend on a command handler; but at least the rest of the application is oblivious to
this change. When dealing with any more than a few dozen of command handlers you should
consider using a Dependency Injection library. Such a library can automate this wiring for you and
will assist in making this area of your application maintainable.

The system obviously depends on the correct wiring of these dependencies. Wrapping the deadlock
retry behavior with the transaction behavior, for instance, would lead to unexpected behavior (a
database deadlock typically has the effect of the database rolling back the transaction, while
leaving the connection open), but this is isolated to the part of the application that wires everything
together. Again, the rest of the application is oblivious.

Both the transaction logic and deadlock retry logic are examples of cross-cutting concerns. The
use of decorators to add cross-cutting concerns is the cleanest and most effective way to apply
these common features I ever came across. It is a form of aspect-oriented programming. Besides
these two examples, there are many other cross-cutting concerns I can think of that can be added
fairly easy using decorators:

• checking the authorization of the current user before commands get executed,
• validating commands before commands get executed,
• profiling the duration of executing commands,
• building an audit trail of commands,
• logging execution failures
• executing commands in the background, or
• queuing commands to be processed in a different process.

Background story: This last point is a very interesting one. Years ago I worked on an application
that used a database table as queue for commands that would be executed in the future. We wrote
business processes (commands by themselves) that sometimes queued dozens of other (sub)
commands, which could be processed in parallel by different processes (multiple Windows
services on different machines). These commands did things like sending mail or heavy stuff such
as payroll calculations, generating PDF documents that would be merged by another command,
and sending those merged documents to a printer by yet another command. The queue was
transactional, which allowed us to—in a sense—send mails and upload files to FTP in a
transactional manner. However, We didn’t use Dependency Injection back then, which made
everything so much harder (if only we knew).

Because commands are simple data containers without behavior, it is very easy to serialize them
(as JSON or XML for instance) or send them over the wire (using WCF for instance), which makes
it not only easy to queue them for later processing, but also makes it very easy to log them in an
audit trail—yet another reason to separate data and behavior. All these features can be added,
8

without changing a single line of code in the application (except perhaps a line at the application’s
entry point).

This design makes maintaining web services much easier too. Your (WCF) web service can consist
of only one ‘handle’ method that takes in any command (that you explicitly expose) and can
execute these commands (after doing the usual authentication, authorization, and validation of
course). Because you will be defining commands and their handlers anyway, your web service
project won’t have to be changed. If you’re interested in that approach, take a look at my
article Writing Highly Maintainable WCF Services.

One simple ICommandHandler<TCommand> interface has made all this possible. While it may seem
complex at first, once you get the hang of it (together with Dependency Injection), well… the
possibilities are endless. You may think that you don’t need all of this up front when you first
design your applications but this design allows you to make many unforeseen changes to the
system later without much difficulty. One can hardly argue a system with this design is over-
engineered—every business operation has its own class and we have put a single generic interface
over them all. It’s hard to over-engineer that—even really small systems can benefit
from separating concerns.

This doesn’t mean things can’t get complicated. Correct wiring all of these dependencies, and
writing and adding the decorators in the right order can be challenging. But at least this complexity
is focused in a single part of the application (the startup path a.k.a. Composition Root), and it
leaves the rest of the application unaware and unaffected. You will rarely need to make sweeping
changes across your application, which is what the Open/Closed Principle is all about.

By the way, you might think the way I created all those decorators around a single command
handler is rather awkward, and imagined the big ball of mud that it would become after we have
created a few dozen command handlers. Yes—this might not scale well. But as I already
mentioned, this problem is best resolved with a DI library. For instance, when using Simple
Injector, registering all command handlers in the system can be done with a single line of code.
Registering a decorator is another single line. Here is an example configuration when when using
Simple Injector:

var container = new Container();

// Go look in all assemblies and register all implementations


// of ICommandHandler<T> by their closed interface:
container.Register(
typeof(ICommandHandler<>),
AppDomain.CurrentDomain.GetAssemblies());

// Decorate each returned ICommandHandler<T> object with


// a TransactionCommandHandlerDecorator<T>.
container.RegisterDecorator(
typeof(ICommandHandler<>),
typeof(TransactionCommandHandlerDecorator<>));

// Decorate each returned ICommandHandler<T> object with


9

// a DeadlockRetryCommandHandlerDecorator<T>.
container.RegisterDecorator(
typeof(ICommandHandler<>),
typeof(DeadlockRetryCommandHandlerDecorator<>));

// Decorate handlers conditionally with validation. In


// this case based on their metadata.
container.RegisterDecorator(
typeof(ICommandHandler<>),
typeof(ValidationCommandHandlerDecorator<>),
c => ContainsValidationAttributes(c.ServiceType));

// Decorates all handlers with an authorization decorator.


container.RegisterDecorator(
typeof(ICommandHandler<>),
typeof(AuthorizationCommandHandlerDecorator<>));

No matter how many command handlers you add to the system, these few lines of code won’t
change, which also helps to underline the true power of a DI library. Once your application is built
applying the SOLID principles, a good DI library will ensure that the startup path of your
application remains maintainable.

This is how I roll on the command side of my architecture.

Further reading
• If you found this article interesting, you should also read my follow up: Meanwhile… on
the query side of my architecture.
• In Writing Highly Maintainable WCF Services I talk about sending commands over the
wire
• If you want to learn how to migrate your existing application to use this model, please
read this thread.
• Chapter 10 of my book contains a much more elaborate version of this article.
10

Written by Steven van Deursen


on December 18, 2011
17-minute read

Meanwhile... on the query side of my


architecture
Proofread by Peter Parker

Command-query separation is a common concept in the software


industry. Many architectures separate commands from the rest of the
system and send command messages that are processed by command
handlers. This same concept of messages and handlers can just as easily
be applied to the query side of an architecture. There are not many
systems using this technique and this article is an attempt to change that.
Two simple interfaces will change the look of your architecture… forever.

In my previous post I described how I design the command side of my systems. The greatest thing
about this design is that it provides a lot of flexibility and lowers the overall complexity of the
system through the addition of one simple interface to the system. The design is founded on
the SOLID principles and is brought to life with Dependency Injection (although DI is optional).
Please read that post if you haven’t already, as this post will regularly refer to its content.

It’s funny that I encountered the command/handler design so many years ago but failed to
understand why anyone would use two classes for one operation (one for the data and one for the
behavior). It didn’t seem very object oriented to me and it was only after I experienced problems
with the old design (message and behavior in the same class) that the potential of the
command/handler design became clear to me.

With my business layer modeled uniformly and giving me great flexibility it then became clear
that the same wasn’t true for the part of the business layer that was responsible for querying. It
was this dissatisfaction that triggered me to think about the design of this part of my application
architecture.

Originally I would model queries as methods with clear names and group them together in a class.
This led to interfaces like the following:

public interface IUserQueries


{
User[] FindUsersBySearchText(string searchText, bool
includeInactiveUsers);
11

User[] GetUsersByRoles(string[] roles);


UserInfo[] GetHighUsageUsers(int reqsPerDayThreshold);

// More methods here


}

There is a variation of this pattern that a lot of developers use today in their applications. They mix
this query class with the repository pattern. The repository pattern is used for CRUDoperations.
The following code may look familiar:

// Generic repository class (okay)


public interface IRepository<T>
{
T GetByKey(int key);
void Save(T instance);
void Delete(T instance);
}

// Custom entity-specific repository with query methods (awkward)


public interface IUserRepository : IRepository<User>
{
User[] FindUsersBySearchText(
string searchText, bool includeInactiveUsers);
User[] GetUsersByRoles(string[] roles);
UserInfo[] GetHighUsageUsers(int reqsPerDayThreshold);

// More methods here


}

Alongside the IUserQueries interface, my application contained interfaces such


asIPatientInfoQueries, ISurgeryQueries, and countless others, each with its own set of
methods and its own set of parameters and return types. Every interface was different, which made
adding cross-cutting concerns, such as logging, caching, profiling, security, etc very difficult. I
was missing the uniformity in the design that I had with my command handlers. The query classes
were just a bunch of random methods, often grouped around one concept or one entity. No matter
how hard I tried, it would end up looking messy and each time a query method was added both the
interface and the implementation would need to be changed.

In my automated test suite things were even worse! A class under test that depended on a query
interface was often only expected to call one or two of its methods, while other classes were
expected to call other methods. This meant I had to do hundreds of asserts in my test suite to ensure
a class didn’t call unexpected methods. This resulted in the creation of abstract base classes in my
test project that implemented one of these query interfaces. Each abstract class looked something
like this:

public abstract class FakeFailingUserQueries : IUserQueries


{
public virtual User[] FindUsersBySearchText(
string searchText, bool includeInactive)
12

{
Assert.Fail("Call to this method was not expected.");
return null;
}

public virtual User[] GetUsersByRoles(string[] roles)


{
Assert.Fail("Call to this method was not expected.");
return null;
}

public virtual UserInfo[] GetHighUsageUsers(


int requestsPerDayThreshold)
{
Assert.Fail("Call to this method was not expected.");
return null;
}

// More methods here


}

For each test I would inherit from this base class and override the relevant the method:

public class FakeUserServicesUserQueries : FakeFailingUserQueries


{
public User[] UsersToReturn { get; set; }
public string[] CalledRoles { get; private set; }

public override User[] GetUsersByRoles(string[] roles)


{
this.CalledRoles = roles;
return this.UsersToReturn;
}
}

All this meant I could leave all the other methods fail (as they were not expected to be called)
which saved me from having to write too much code and reduced the chance of errors in my tests.
But it still led to an explosion of test classes in my test projects.

Of course all these problems can be solved with the ‘proper’ tooling. For instance, cross-cutting
concerns can be added by using compile-time code weaving (using PostSharp for instance), or by
configuring your DI container using convention based registration, mixed with interception
(interception uses dynamic proxy generation and lightweight code generation). The testing
problems can be resolved by using Mocking frameworks (which also generate proxy classes that
act like the original class).

These solutions work, but they usually only make things more complicated and in reality they are
patches to hide problems with the initial design. When we validate the design against the five
13

SOLID principles, we can see where the problem lies. The design violates three of the five SOLID
principles:

• The Single Responsibility Principle is violated, because the methods in each class are not
highly cohesive. The only thing that relates those methods is the fact that they belong to
the same concept or entity.
• The design violates the Open/Closed Principle, because almost every time a query is
added to the system, an existing interface and its implementations need to be changed.
Every interface has at least two implementations: one real implementation and one test
implementation.
• The Interface Segregation Principle is violated, because the interfaces are wide (have
many methods) and consumers of those interfaces are forced to depend on methods that
they don’t use.

So let us not treat the symptoms; let’s address the cause.

A better design
Instead of having a separate interface per group of queries, we can define a single interface for all
the queries in the system, just as we saw with the ICommandHandler interface in my previous
article. We define the following two interfaces:

public interface IQuery<TResult> { }

public interface IQueryHandler<TQuery, TResult>


where TQuery : IQuery<TResult>
{
TResult Handle(TQuery query);
}

The use of such IQuery<TResult> interface is something that Udi Dahan mentioned back in
2007. So in fact this concept isn’t new at all. Unfortunately, Udi doesn’t go into much details in
his article.

The IQuery<TResult> specifies a query message with TResult as the query’s return type.
Although this interface doesn’t look very useful, I will explain later on why having such an
interface is crucial.

Whereas a command is normally “fire and forget” and will update something in the system and
not return a value, a query is the opposite, in that it will not change any state and does return a
value.

Using the previously defined interface we can define a query message:

public class FindUsersBySearchTextQuery : IQuery<User[]>


{
14

public string SearchText { get; set; }


public bool IncludeInactiveUsers { get; set; }
}

This class defines a query operation with two parameters that returns an array of User objects. Just
like a command, this query message class is a Parameter Object.

The class that handles this message can be defined as follows:

public class FindUsersBySearchTextQueryHandler


: IQueryHandler<FindUsersBySearchTextQuery, User[]>
{
private readonly NorthwindUnitOfWork db;

public FindUsersBySearchTextQueryHandler(NorthwindUnitOfWork db)


{
this.db = db;
}

public User[] Handle(FindUsersBySearchTextQuery query)


{
return (
from user in this.db.Users
where user.Name.Contains(query.SearchText)
select user)
.ToArray();
}
}

As we’ve seen with the command handlers, we can now let consumers depend on the
generic IQueryHandler interface:

public class UserController : Controller


{
IQueryHandler<FindUsersBySearchTextQuery, User[]> handler;
15

public UserController(
IQueryHandler<FindUsersBySearchTextQuery, User[]> hndler)
{
this.handler = handler;
}

public View SearchUsers(string searchString)


{
var query = new FindUsersBySearchTextQuery
{
SearchText = searchString,
IncludeInactiveUsers = false
};

User[] users = this.handler.Handle(query);

return this.View(users);
}
}

This model gives us a lot of flexibility because we can now decide what to inject into
the UserController. As we’ve seen in the previous article, we can inject a completely different
implementation, or one that wraps the real implementation, without having to make any changes
to the UserController (and all other consumers of that interface).

Note this is where the IQuery<TResult> interface comes into play. It prevents us from having to
cast the return type (to User[] in this example); it therefore gives us compile-time support when
working with the query handler; it provides compile-time support when specifying or
injecting IQueryHandlers into our code. If we were to change
the FindUsersBySearchTextQuery to return UserInfo[] instead of User[] (by updating it to
implement IQuery<UserInfo[]>), the UserController would fail to compile because the
generic type constraint on IQueryHandler<TQuery, TResult> won’t be able to
map FindUsersBySearchTextQuery to User[].

Injecting the IQueryHandler interface into a consumer however, has some less obvious problems
that still need to be addressed.

The number of dependencies if our consumers might get too big and can lead to constructor over-
injection—when a constructor takes too many arguments (a common rule of thumb is that a
constructor should take no more than 4 or 5 arguments). Constructor over-injection is an anti-
pattern and is often a sign that the Single Responsibility Principle (SRP) has been violated.
Although it is important to adhere to SRP, it is also highly likely that consumers will want to
execute multiple different queries without really violating SRP (in contrast to injecting
many ICommandHandler<TCommand> implementations which would certainly be a violation of
SRP). In my experience the number of queries a class executes can change frequently, which would
require constant changes into the number of constructor arguments.
16

Another shortcoming of this approach is that the generic structure of the IQueryHandler<TQuery,
TResult> leads to lots of infrastructural code which in turn makes the code harder to read. For
example:

public class Consumer


{
IQueryHandler<FindUsersBySearchTextQuery, IQueryable<UserInfo>>
findUsers;
IQueryHandler<GetUsersByRolesQuery, IEnumerable<User>> getUsers;
IQueryHandler<GetHighUsageUsersQuery, IEnumerable<UserInfo>>
getHighUsage;

public Consumer(
IQueryHandler<FindUsersBySearchTextQuery,
IQueryable<UserInfo>> findUsers,
IQueryHandler<GetUsersByRolesQuery, IEnumerable<User>>
getUsers,
IQueryHandler<GetHighUsageUsersQuery, IEnumerable<UserInfo>>
getHighUsage)
{
this.findUsers = findUsers;
this.getUsers = getUsers;
this.getHighUsage = getHighUsage;
}
}

Wow!! That’s a lot of code for a class that only has three different queries that it needs to execute.
This is in part due to the verbosity of the C# language. A workaround (besides switching to another
language) would be to use a T4 template that generates the constructor in a new partial class. This
would leave us with just the three lines defining the private fields. The generic typing would still
be a bit verbose, but with C# there’s nothing much we can do about that.

So how do we fix the problem of having to inject too many IQueryHandlers? As always, with an
extra layer of indirection :-). We create a Mediator that sits between the consumers and the query
handlers:

public interface IQueryProcessor


{
TResult Process<TResult>(IQuery<TResult> query);
}

The IQueryProcessor is a non-generic interface with one generic method. As you can see in the
interface definition, the IQueryProcessor depends on the IQuery<TResult> interface. This
allows us to have compile time support in our consumers that depend on the IQueryProcessor.
Let’s rewrite the UserController to use the new IQueryProcessor:

public class UserController : Controller


{
private IQueryProcessor queries;
17

public UserController(IQueryProcessor queries)


{
this.queries = queries;
}

public ActionResult SearchUsers(string searchString)


{
var query = new FindUsersBySearchTextQuery
{
SearchText = searchString
};

// Note how we omit the generic type argument,


// but still have type safety.
User[] users = this.queries.Process(query);

return this.View(users);
}
}

The UserController now depends on a IQueryProcessor that can handle all of our queries.
The UserController’s SearchUsers method calls the IQueryProcessor.Process method
passing in an initialized query object. Because the FindUsersBySearchTextQuery implements
the IQuery<User[]>interface, we can pass it to the
generic Execute<TResult>(IQuery<TResult> query) method. Thanks to C# type inference,
the compiler is able to determine the generic type and this saves us having to explicitly state the
type. The return type of the Process method is also known. So if we were to change
the FindUsersBySearchTextQuery to implement a different interface
(say IQuery<IQueryable<User>>) the UserController will no longer compile instead of
miserably failing at runtime.

It is now the responsibility of the implementation of the IQueryProcessor to find the


right IQueryHandler. This requires some dynamic typing, and optionally the use of a Dependency
Injection library, and can all be done with just a few lines of code:

sealed class QueryProcessor : IQueryProcessor


{
private readonly Container container;

public QueryProcessor(Container container)


{
this.container = container;
}

[DebuggerStepThrough]
public TResult Process<TResult>(IQuery<TResult> query)
{
var handlerType = typeof(IQueryHandler<,>)
18

.MakeGenericType(query.GetType(), typeof(TResult));

dynamic handler = container.GetInstance(handlerType);

return handler.Handle((dynamic)query);
}
}

he QueryProcessor class constructs a specific IQueryHandler<TQuery, TResult> type based


on the type of the supplied query instance. This type is used to ask the supplied container class to
get an instance of that type. Unfortunately we need to call the Handle method using reflection (by
using the C# 4.0 dymamic keyword in this case), because at this point it is impossible to cast the
handler instance, as the generic TQuery argument is not available at compile time. However, unless
the Handle method is renamed or gets other arguments, this call will never fail and if you want to,
it is very easy to write a unit test for this class. Using reflection will give a slight drop, but is
nothing to really worry about (especially when you’re using Simple Injector as your DI library,
because it is blazingly fast).

I did consider an alternative design of the IQueryProcessor interface, that looked like this:

public interface IQueryProcessor


{
TResult Process<TQuery, TResult>(TQuery query)
where TQuery : IQuery<TResult>;
}

This version of the interface solves the problem of having to do dynamic typing in
the QueryProcessor implementation completely, but sadly the C# compiler isn’t ‘smart’ enough
to find out which types are needed (damn you Anders!), which forces us to completely write out
the call to Process, including both generic arguments. This gets really ugly in the code and is
therefore not advisable. I was a bit amazed by this, because I was under the assumption that the
C# compiler could infer the types. (However, the more I think about it, the more it makes sense
that the C# compiler doesn’t try to do so.)

There’s one very important point to note when using the IQueryProcessor abstraction. By
injecting an IQueryProcessor, it is no longer clear which queries a consumer is using. This makes
unit testing more fragile, because the constructor no longer tells us what services the class depends
on. We also make it harder for our DI library to verify the object graph it is creating, because the
creation of an IQueryHandler implementation is postponed by the IQueryProcessor. Being able
to verify the container’s configuration is very important. Using the IQueryProcessormeans we
have to write a test that confirms there is a corresponding query handler for every query in the
system, because the DI library can not check this for you. I personally can live with that in the
applications I work on, but I wouldn’t use such an abstraction too often. I certainly wouldn’t
advocate an ICommandProcessor for executing commands—consumers are less likely to take a
dependency on many command handlers and if they do it would probably be a violation of SRP.
19

One word of advice: When you start using this design, start out without
the IQueryProcessor abstraction because of the reasons I described. It can always
be added later on without any problem.

A consequence of the design based on the IQueryHandler interface is that there will be a lot of
small classes in the system. And believe it or not, but having a lot of small / focused classes (with
clear names) is actually a good thing. Many developers are afraid of having too many classes in
the system, because they are used in working in big tangled code bases with lack of structure and
the proper abstractions. The cause of what they are experiencing however isn’t caused by the
amount of classes, but by the lack of structure. Stop writing less code; start writing more
maintainable code!

Although there are many ways to structure a project, I found it very useful to place
each query class, its DTOs, and the corresponding handler in the same folder,
which is named after the query. So the BusinessLayer/Queries/GetUsersByRoles
folder might contain the files GetUserByRolesQuery.cs, UserByRoleResult.cs and
GetUsersByRolesQueryHandler.cs.

Another fear of developers is long build times. Keeping the build times low is in my experience
crucial for good developer productivity. The number of classes in a project however, hardly
influences the build time. The number of projects on the other hand does. You’ll often see that the
build time increases exponentially with the number of projects in a solution. Reducing the number
of classes wont help you a bit.

When using a DI library, we can normally register all query handlers with a single call (depending
on the library), because all the handlers implement the same IQueryHandler<TQuery,
TResult>interface. Your mileage may vary, but with Simple Injector, the registration looks like
this:

container.Register(
typeof(IQueryHandler<,>),
typeof(IQueryHandler<,>).Assembly);

This code saves us from having to change the DI configuration any time we add a new query
handler to the system. They will all be picked up automatically.

With this design in place we can add cross-cutting concerns such as logging, audit trail, etc. Or
let’s say you want to decorate properties of the query objects with Data Annotations attributes, to
enable validation:

public class FindUsersBySearchTextQuery : IQuery<User[]>


{
// Required and StringLength are attributes from the
// System.ComponentModel.DataAnnotations assembly.
[Required]
[StringLength(1)]
20

public string SearchText { get; set; }

public bool IncludeInactiveUsers { get; set; }


}

Because we modeled our query handlers around a single IQueryHandler<TQuery,


TResult>interface, we can define a simple decorator that validates all query messages before they
are passed to their handlers:

public class ValidationQueryHandlerDecorator<TQuery, TResult>


: IQueryHandler<TQuery, TResult>
where TQuery : IQuery<TResult>
{
private readonly IQueryHandler<TQuery, TResult> decorated;

public ValidationQueryHandlerDecorator(
IQueryHandler<TQuery, TResult> decorated)
{
this.decorated = decorated;
}

public TResult Handle(TQuery query)


{
Validator.ValidateObject(
query,
new ValidationContext(query, null, null),
validateAllProperties: true);

return this.decorated.Handle(query);
}
}

All without changing any of the existing code in our system beyond adding the following new line
of code in the Composition Root:

container.RegisterDecorator(
typeof(IQueryHandler<,>),
typeof(ValidationQueryHandlerDecorator<,>));

If you’re concerned about performance and worry that this would add too much overhead by
wrapping query handlers that don’t need validation with a decorator, a DI container such as Simple
Injector allows you to easily configure a conditional decorator:

container.RegisterDecorator(
typeof(IQueryHandler<,>),
typeof(ValidationQueryHandlerDecorator<,>),
context => ShouldQueryHandlerBeValidated(context.ServiceType));
21

The applied predicate is evaluated just once per closed generic IQueryHandler<TQuery,
TResult>type, so there is no performance loss in registering such a conditional decorator (or at
least, with Simple Injector there isn’t). As I said, your mileage may vary when using other DI
libraries.

I’ve been using this model for some time now but there is one thing that struck me early on—
everything in the system is either a query or a command and if we want, we can model every single
operation in this way. But do we really want to? No, definitely not, mostly because it doesn’t
always result in the most readable code. Take a look at this example:

private IQueryHandler<GetCurrentUserIdQuery, int> userHandler;


private IQueryHandler<GetCurrentTimeQuery, DateTime> timeHandler;

public IQueryable<Order> Handle(GetRecentOrdersForLoggedInUserQuery


query)
{
int currentUserId =
this.userHandler.Handle(new GetCurrentUserIdQuery());

DateTime currentTime =
this.timeHandler.Handle(new GetCurrentTimeQuery());

return
from order in db.Orders
where order.User.Id == currentUserId
where order.CreateDate >= currentTime.AddDays(-30)
select order;
}

This query method is composed of other queries. Composing queries out of other queries is a great
way to improve modularity and manage the complexity of the system. But still there is something
smelly about this code. Personally, I find the following example easier to read:

private IUserContext userContext;


private ITimeProvider timeProvider;

public IQueryable<Order> Handle(GetRecentOrdersForLoggedInUserQuery


query)
{
return
from order in db.Orders
where order.User.Id == this.userContext.UserId
where order.CreateDate >= this.timeProvider.Now.AddDays(-30)
select order;
}

The previous sub queries are in this version replaced with


the IUserContext and ITimeProviderservices. Because of this, the method is now more concise
and compact.
22

So where do we draw the line between using an IQuery<TResult> and specifying an explicit
separate service interface? I can’t really define any specific rules on that; a little bit of intuition
and experience will have to guide you. But to give a little bit of guidance, when a query returns a
(cached) value without really hitting an external resource, such as the file system, web service, or
database, and it doesn’t contain any parameters, and you’re pretty sure you never want to wrap it
with a decorator (no performance measuring, no audit trailing, no authorization) it’s pretty safe to
define it as a specific service interface. Another way to view this is to use this design to define
business questions: things the business wants to know. In other words, use
the IQueryHandler<TQuery, TResult> and ICommandHandler<TCommand> abstractions as the
communication layer between the business layer and the layers above.This comes down to the idea
of holistic abstractions.

That’s how I roll on the query side of my architecture.

S-ar putea să vă placă și