neos / Neos.EventSourcing

A library for Event Sourcing and CQRS for Flow projects.
MIT License
45 stars 30 forks source link

Check if CommandBus can be avoided #3

Closed albe closed 8 years ago

albe commented 8 years ago

The "CommandBus" is actually rather a kind of router/dispatcher, as it will only dispatch a command to a single handler. Also, the CommandBus is commonly used in client applications, since there is nothing like a http request involved and all communication happens in-process. However, for our web-based environment, there is no real need for a CommandBus, since the Flow Router+Dispatcher can already act as the "CommandBus".

Either the request URI describes the command type directly and the controller actions act as CommandHandler, or a single dispatch controller action is involved, which will invoke the specific handlers.

dfeyer commented 8 years ago

I agree for many case 1 HTTP Request === 1 Command

But definitively not in all cases, dispatching multiple command in a single request can make sense. And if we are bound the 1 HTTP Request === 1 Command we are locked down.

albe commented 8 years ago

That's an interresting idea - do you have any concrete use-case for sending multiple Commands in a single request?

I mean, a command is generally supposed to trigger a single transaction (talk to a single Aggregate) and triggering multiple transactions within a single request is not that straightforward - what if one transaction in between fails? Will the whole request fail or still return 200 OK?

dfeyer commented 8 years ago

Don't have practical example, but try to be the devil's advocate a bit ;)

robertlemke commented 8 years ago

See also our discussion here: https://discuss.neos.io/t/cqrs-es-meeting-notes-06-09-2016/1392 Right now also think that we don't need a command bus, but we should have some central manager which accepts commands. And if you agree on that, we can just use a Command Bus class for that and give it a dispatch() method.

I would not feel comfortable using the existing Router or Dispatcher in Flow for commands or events. Both serve a different purpose.

bwaidelich commented 8 years ago

I can't think of a scenario where you want to have two commands within one request, IMO that's rather dangerous and should probably replaced by a ProcessManager.. Anyways, it's got nothing to do with this issue IMO because you can dispatch as many commands as you wish, whether you have a CommandBus or not – or am I missing something?

bwaidelich commented 8 years ago

We just discussed the CommandBus in our initial CQRS Meeting and decided:

TL;DR:

Unless someone comes up with a valid counter-argument we'll remove the CommandBus for now and see how far we get without it. Before releasing the package we'll re-evaluate that decision.

Background

To recap on some of the potential use-cases for a CommandBus and (my personal) counter-arguments in relation to Flow:

Dispatch to multiple handlers

This is considered bad practice and most libraries will fault if there's none or more than one matching handler for a given command

"Remote" commands

According to Greg Young: "asynchronous commands don't exist you want an event"

Being able to decorate a handler for validation/logging

This can be useful in order to add validation or logging in regular implementations. In Flow we can already syntactically validate the command when it's sent to the Controller (using @Flow\Validate annotations and/or constructor assertions). Logging all commands would also be easily achievable using AOP (within(CommandControllerInterface) && method(.*->handle.*())) – IMO one of the very rare valid use cases for it.

Being able to replace a handler from 3rd party code

I can't really imagine that this would be a useful extension point tbh, because the handler usually just

  1. Reconstitutes the aggregate (using a repository)
  2. Calling a method on the aggregate
  3. Persist the agggregate

Anyways, if an extension point is needed, one could still refer to some *HandlerInterface and replace that via Objects.yaml if needed.

albe commented 8 years ago

I like :) Thx for the write-up!

robertlemke commented 8 years ago

I assigned this to you, @dfeyer, because you volunteered to remove the CommandBus code, right?

dfeyer commented 8 years ago

I assigned this to you, @dfeyer, because you volunteered to remove the CommandBus code, right?

@robertlemke I volunteer to remove anything ;)

bwaidelich commented 8 years ago

In Slack @dfeyer argued:

I need a command line utility to launch some simple commands ... and now I see the need of a commandbus

I can see that it could be useful to be able to execute all available commands from a very generic CLI command controller. At least in slightly more complex scenarios I don't think that will work out and a dedicated command controller makes sense IMO. In any case it should be possible to implement that generic command controller nevertheless as we can determine all commands and their handlers.