Sunday, January 13, 2013

Self-contained commands with dependencies

Also read: separating command data from logic and sending it on a bus

In October I looked at an architecture that limits abstractions to solely commands and queries. In that post, I had some infrastructure that looked like this.
public abstract class Command
{
    public abstract void Execute();
}

public abstract class Query<T>
{
    public abstract T Execute();
}

public interface ICommandHandler
{
    void Execute(Command command);
}

public class CommandHandler : ICommandHandler
{
    public void Execute(Command command)
    {
        command.Execute();
    }
}

public interface IQueryHandler 
{
    T Execute<T>(Query<T> query);
}

public class QueryHandler : IQueryHandler
{
    public T Execute<T>(Query<T> query)
    {
        return query.Execute();
    }
}
Commands and queries are both accompanied by their specific handler. In this example, the handler does nothing but invoking the command or query. In reality, you want your handlers to do a little more. For example: provide the commands and queries with a context to work with, add logging, handle your unit of work and all of that good stuff.

Let's look at the infrastructure, and particularly the handlers of a project that uses RavenDB to store its data.
public abstract class Command
{
    public IDocumentSession Session { get; set; }

    public abstract void Execute();           
}

public abstract class Query<T>
{
    public IDocumentSession Session { get; set; }

    public abstract T Execute();
}

public class CommandHandler : ICommandHandler
{
    public void Execute(Command command)
    {            
        var store = DocumentStore.Get();
        using (var session = store.OpenSession())
        {
            command.Session = session;
            command.Execute();

            session.SaveChanges();
        }
    }
}
    
public class QueryHandler : IQueryHandler
{    
    public T Execute<T>(Query<T> query)
    {
        var store = DocumentStore.Get();
        using (var session = store.OpenSession())
        {
            query.Session = session;

            return query.Execute();
        }
    }
}
The handlers take care of creating and managing the session, but also provide the commands and queries with a reference to the session.

An actual command could look like this.
public class ConfirmOrderCommand : Command
{
    private Guid _token;

    public ConfirmOrderCommand(Guid token)
    {
        _token = token;
    }

    public override void Execute()
    {
        var order = Session.Query<Documents.Order>().Where(x => x.Token == _token).First();

        order.ChangeStatus(Documents.Status.Confirmed);
    }
}
I really like this style of command and queries; very little ceremony. The downside though, is that you can't use constructor dependency injection. Like discussed in this post, you could split your classes in two parts: the handler and the data, and you would solve that problem.

I wasn't that keen on that approach. Also, now that I'm so accustomed to having fast in-memory integration tests with RavenDB, it's exceptional that I have the need to inject dependencies. I worked out an alternative which allows me to inject dependencies without having to put my data somewhere else.

Instead of injecting the dependencies through the constructor, we're going to use an Inject method. This is a convention; there is no interface that enforces this. Returning to our ConfirmOrderCommand, we'll add support for creating a new folder on the file system.
public class ConfirmOrderCommand : Command
{
    private IFileSystem _fileSystem;

    private Guid _token;

    public ConfirmOrderCommand(Guid token)
    {
        _token = token;
    }

    public override void Execute()
    {    
        var order = Session.Query<Documents.Order>().Where(x => x.Token == _token).First();
        
        _fileSystem.CreateDirectory(Path.Combine("D:\", order.Customer.Id));

        order.ChangeStatus(Documents.Status.Confirmed);
    }
    
    public void Inject(IFileSystem fileSystem) 
    {
        _fileSystem = fileSystem;
    }
}
We can now amplify the commandhandler to automatically resolve and inject the dependencies into our commands. The handler uses reflection to look for a method named Inject on the type. If this method exists, it will inspect the method for its expected arguments and try to resolve those, to finally invoke the Inject method with its resolved arguments. 
public class CommandHandler : ICommandHandler
{
    private IKernel _kernel;

    public CommandHandler() { }

    public CommandHandler(IKernel kernel)
    {
        _kernel = kernel;
    }

    public void Execute(Command command)
    {
        if (_kernel != null)
            ResolveDependenciesIfNeeded(command);
            
        var store = DocumentStore.Get();
        using (var session = store.OpenSession())
        {
            command.Session = session;
            command.Execute();

            session.SaveChanges();
        }
    }

    private void ResolveDependenciesIfNeeded(Command command)
    {
        var method = command.GetType().GetMethod("Inject");
        if (method != null)
        {
            var parameters = method.GetParameters();
            var parameterInstances = new List<object>();

            foreach (var parameter in parameters)
            {
                var type = parameter.ParameterType;
                var instance = _kernel.Get(type);

                parameterInstances.Add(instance);
            }

            method.Invoke(command, parameterInstances.ToArray());
        }
    }
}
Consumers now don't have to care about the dependencies; they just have to be registered in the container. In the tests however, we can now explicitly inject mocks or stubs, and take advantage of having discoverable dependencies though the Inject convention.
[TestClass]
public class When_confirming_an_order
{
    private Mock<IFileSystem> _fileSystem;

    [TestInitialize]
    public void When()
    {
        DocumentStore.InitializeEmbedded();

        var cmd = new ConfirmOrderCommand("_token_");
        
        // Inject mock
        _fileSystem = new Mock<IFileSystem>();    
        cmd.Inject(_fileSystem.Object);

        new CommandHandler().Execute(cmd);
    }

    [TestMethod]
    public void the_status_is_changed_to_confirmed()
    {
        ...
    }
    
    [TestMethod]
    public void a_new_folder_is_created()
    {
        _fileSystem.Verify(...);
    }
}
Although I haven't really gone the distance with this implementation - I only have one command that has extra dependencies, I find this technique showing lots of promise. You get the leanness of self-contained commands and queries, while you still allow discoverable dependency injection by convention, supported by a tiny bit of infrastructure in the handlers.

I'd like to hear your opinion.

13 comments:

  1. No offense, but you seem to have reinvented "property injection". You use a method called "Inject" to capture all properties. And it's not even "property injection" because that commonly means "optional dependencies". By the looks of it, it's "your way" to get around the fact you can't have "constructor injection". It's a smell and a strong argument for decoupling data and execution. That doesn't mean it won't work, but you're already adding "some" cognitive load because I have to be aware of the difference in setting up dependencies for test and production purposes.

    Your CommandHandler is a cry for composition: "Please, decorate this Command!". This is me bikeshedding ... your intention with ICommandHandler is to capture the execution context of Command, while Command captures the data and logic associated with the intent regardless of execution context, right?!

    I'll stick with a split commandhandler and command because it doesn't force me into the quandaries you're in, it plays nicer with messaging, allows for distribution between data and logic, makes composition more explicit by using conventional dependency idioms, and stimulates putting logic into its proper place (and the command is not it). Again, this is not generally applicable and doesn't diminish what you are building in any way. Trade-offs, personal experience and "it depends" TM.

    You do get points for challenging the status quo and trying to come up with an innovative, minimalistic approach.

    Typo: ConfirmQueryCommand is not a ctor for ConfirmOrderCommand

    ReplyDelete
    Replies
    1. > Thanks for the comment; I appreciate the counterbalance! I added some of my thoughts.

      No offense, but you seem to have reinvented "property injection". You use a method called "Inject" to capture all properties. And it's not even "property injection" because that commonly means "optional dependencies". By the looks of it, it's "your way" to get around the fact you can't have "constructor injection". It's a smell and a strong argument for decoupling data and execution. That doesn't mean it won't work, but you're already adding "some" cognitive load because I have to be aware of the difference in setting up dependencies for test and production purposes.

      > Agreed, not claiming to be reinventing anything here; this is just a form of property injection working around not being able to inject dependencies through the ctor. I don't see the issue you perceive in the difference for test and production though; with CDI you would also delegate composition to your infrastructure (DI framework) in production, and do it manually for testing.

      Your CommandHandler is a cry for composition: "Please, decorate this Command!". This is me bikeshedding ... your intention with ICommandHandler is to capture the execution context of Command, while Command captures the data and logic associated with the intent regardless of execution context, right?!

      > You assume there are several command contexts? Why does this have to be a separate concept, and not just a different handler?

      I'll stick with a split commandhandler and command because it doesn't force me into the quandaries you're in, it plays nicer with messaging, allows for distribution between data and logic, makes composition more explicit by using conventional dependency idioms, and stimulates putting logic into its proper place (and the command is not it). Again, this is not generally applicable and doesn't diminish what you are building in any way. Trade-offs, personal experience and "it depends" TM.

      > I probably also wouldn't use this variation in a messaging context; there it's obvious data and logic are two different things. I think there are arguments to make for separating things more, but I also think they often don't hold up versus YAGNI, levels of indirection, developer convenience, etc.. An approach doesn't always _need_ to be conventional to be good, right?

      You do get points for challenging the status quo and trying to come up with an innovative, minimalistic approach.

      > Worth it! ;)

      Typo: ConfirmQueryCommand is not a ctor for ConfirmOrderCommand

      > Thanks, fixed.

      Delete
    2. To be clear, it's not property injection either because that has the trait of being optional (I wasn't as opinionated about this point in my first remark). And it's not method injection either because the dependencies are not for the Inject method.

      > You assume there are several command contexts? Why does this have to be a separate concept, and not just a different handler?

      I'd argue that you already have two execution contexts, one for test and one for production (execution contexts and your command handlers are indeed synonyms). The fact that you have two constructors on that handler is already smelly, since one clearly exists for testing purposes (or when there aren't deps). The test initialization is (partially) taking on the role of what I would put in a TestCommandHandler. You would also get more reuse out of your CommandHandler if you "refactored to dependency" the DocumentStore (or is it really a session factory). Even the act of resolving dependencies is not really its concern (e.g. a dependency of the form object[] IMultiDependencyResolver.Resolve(params Type[] types)), so no need to depend on an IoC container. I would also ask myself the question: What is the system under test, the command handler or the command execution?

      > I probably also wouldn't use this variation in a messaging context; there it's obvious data and logic are two different things. I think there are arguments to make for separating things more, but I also think they often don't hold up versus YAGNI, levels of indirection, developer convenience, etc.. An approach doesn't always _need_ to be conventional to be good, right?

      I don't think the coupling of the execution logic with the data is buying you much. I honestly think the ceremony argument is overrated, and the split is a more natural direction for the code to follow when driven by tests.

      Delete
    3. Ah, now I see where you're coming from. I definitely wouldn't mind separating the test context; it just hasn't bitten me yet.

      I get your last point as well. Separating data from logic isn't buying me much neither (in my scenario) though; it's exceptional for me to have a dependency I need to be injected.

      Delete
    4. My concern is what is inside the command execution. That code is an application service in and by itself with a rather unconventional way of communicating dependencies. Before you know it we start writing domain logic in it. Oh, let's refactor it to a dependency (a domain service). So what have we gained? An unconventional way of communicating dependencies where several months down the road someone new starts asking why we didn't just use ctor injection. Because separating data and execution seemed like a better idea at the time (no overengineering)?

      So, which is better? Neither. If you have a domain model separate. If you have a data model combine.

      Delete
    5. We're getting somewhere I think :P

      Delete
    6. Also, I think putting 'domain' logic in these commands is OK for lots of scenarios. You basically move logic that would go in a domain service to a command.

      Delete
  2. Personally I don't like the approach you're taking. The "overhead" of separate handlers for your commands is already justified since you're compensating already. In this case seperate commands & handlers are not "accidential complexity" but "necessary complexity"

    If you want to stick with this approach: Why not use the ServiceLocator pattern in your command? The only advantage of your approach is that you know the type of the dependency. If you forget to call "Inject" in your test you'll get an ugly NullReferenceException. The drawback of your approach is obviously the boilerplate code & the field variable.

    (note: I'm not a fan of the ServiceLocator anti-pattern but it seems a valid choice here)

    ReplyDelete
    Replies
    1. Personally I don't like the approach you're taking. The "overhead" of separate handlers for your commands is already justified since you're compensating already. In this case seperate commands & handlers are not "accidential complexity" but "necessary complexity"

      > Remember that it's highly exceptional that my commands have extra dependencies, so I would introduce extra complexity and an extra level of indirection to support a few edge cases.

      If you want to stick with this approach: Why not use the ServiceLocator pattern in your command? The only advantage of your approach is that you know the type of the dependency. If you forget to call "Inject" in your test you'll get an ugly NullReferenceException. The drawback of your approach is obviously the boilerplate code & the field variable.

      (note: I'm not a fan of the ServiceLocator anti-pattern but it seems a valid choice here)

      > CDI would also introduce field variables for each dependency, so you can't avoid that. The advantage of the Inject method over a ServiceLocator is discoverability IMO.

      Delete
  3. Question, how are you going to use Command (ConfirmOrderCommand) in your code? using new ...?

    ReplyDelete
    Replies
    1. The command gets executed by the CommandHandler. Something like commandHandler.Execute(new ConfirmOrderCommand("token"));

      Delete
  4. See my comment on your October post. It seems you are going into the direction I described there.

    ReplyDelete
    Replies
    1. I wonder what the point is in injecting (either constructor or property) into your commands. A command or query should be a just a small DTO in my opinion. They shouldn't contain any methods or functionality.

      > What's the reason behind separating data from command and queries in my scenario? I'm not using it as a message.

      I mostly go with the following.

      You got a specific service within your application: Lets say AccountService. This service exposes in it's API the methods to "public GetTotalAmountResult GetTotalAmount(GetTotalAmountRequest request)" and "WithdrawAmount(WithdrawAmountCommand command)".

      This 'request' and 'command' then be processed by the AccountService implementation by calling to their appropriate handler (Command or Query).

      > Aren't you mixing request/response and commands/queries here?

      These handlers ( I rather call them 'Dispatchers' ) resolve 'QueryHandlers' or 'CommandHandlers' from your container. Those 'QueryHandlers' or 'CommandHandlers' then take in the command or request and process the provided data. On those 'QueryHandlers' or 'CommandHandlers' I would inject into the constructor whatever is necessary. Not on the command or query object itself.

      > Where is the added value? Why can't the command and query contain the actual logic? I'm having a hard time find a good argument here. Is it only to support CDI? Remember that I only exceptionally need extra dependencies.

      This setup will allow you to stub/mock anything in the process. We even extended this a bit more by pulling out the actually queries or commands from the handlers into separate objects, so they can to be tested. In case you won't some code to back this up, I'll be happy to create a small git for this.

      > I think this earlier post already describes how you're handling things? http://www.jefclaes.be/2012/10/commands-with-dependencies.html

      Delete