I've been busy developing a large application on Laravel. In the middle of this, I've been trying to also be a good PHP developer (oxymoron?) and look into using the Command Bus pattern, specifically using Laravel's implementation. I think I get the idea in theory: Fire a Command
, the Handler
deals with it, the Command
is immutable, and all that. I've looked up tons of tutorials on the subject, and even watched Ross Tuck's talk Models and Service Layers; Hemoglobin and Hobgoblins which mentions the subject.
The one thing these tutorials do not mention is how one might use the data generated in the Handler
. For example, say I have a controller method that fires off a command:
// Register the User
public function register(RegisterRequest $request)
{
$this->dispatch(new CreateRegistrationCommand($request));
}
Now, let's assume this method needs to charge a credit card with Stripe, created the Order
in our database, generate some tickets, email the user, notify the admins, and log the whole thing. After the Command
is successful, I want to redirect the user to a confirmation page (using a reference number or ID from the Order
we created). So our usage of the Command Bus gets a little more hard to figure out.
// Register the User
public function register(RegisterRequest $request)
{
$this->dispatch(new CreateRegistrationCommand($request));
$this->dispatch(new CreateOrderCommand($charge));
// Redirect the user here
}
If I want to use the data from the newly-created charge, and use it to create the Order
in our system, how would I do that? Using the Command Pattern means a Handler
is not allowed to return anything. It just goes off to do its thing and we can handle any Exception
that's thrown, but that's it. Redirecting from there becomes tricky. Here are some of the suggestions I've seen.
Handler
classes aren't supposed to return anything and you're not supposed to rely on any of the data they generate. In theory, this is because a Command
could take several minutes, hours, or even days to complete. Some people say, "Screw this!" and do it anyways. I see this as creating a lot of extra unneeded Command
and Handler
classes when I could create a simple RegistrationService
class that handles all of this and is not bound to the rules of a Handler
.
Using my example, one could reason that my reference_number
could be used as a makeshift UUID
and be generated by the Controller
for use in the creation of the Order. A Controller
, in my mind should not need to worry about doing such things. At that point the Controller
will know too much about the application and be veering away from its primary duty of handling HTTP requests. But, assuming I'm okay with making that concession, this could be a viable way to handle it, but you lose the purity of the pattern, and by that point it's no better than using a Service class for the same goal.
This one is the most complex and makes me go, "Dafuq?". This approach suggests something like this:
// Register the User
public function register(RegisterRequest $request)
{
// Create UUID
$uuid = uniqid();
// Dispatch the Commands to the Queue
$this->dispatch(new CreateRegistrationCommand($request, $uuid));
$this->dispatch(new CreateOrderCommand($charge, $uuid));
// Redirect the user to the verify method
return redirect()->route('register.verify', $uuid);
}
// Show the verification page
public function verify($uuid)
{
// Have your view listen via AJAX call and redirect when the order is ready
return view('register.verify');
}
// The AJAX verification route
public function verifyOrder($uuid)
{
// Verify the Charge and Order
// Return the Order when all is well
return $order;
}
Look at all this set up so we can use the "pure" approach of the Command Bus! This is total madness. Essentially, we fire the Command
s off to the queue, redirect the user to a holding page that checks via an AJAX route whether the order with a UUID
you generate is ready. This is no more simple than using a Service class that shoots these actions off to the queue and does the same actions.
I'm don't profess to be the best developer in the world. I'm very pragmatic and don't buy into a lot of the overly complex patterns and I don't tend to prematurely optimize. But I'm just not seeing the benefit in the Command Bus pattern for use cases like these. What am I missing?
In general, no need for complexity if you don't need the behaviors they enable!. Use commands or don't, it's all good! Here's just an example I find useful that you may not may not need or want:
Re-use
I re-use the same commands for CLI, API and regular web calls. Same code, difference context, so the only difference becomes (essentially) how you gather your user input and how you respond to validation issues/errors.
Logging / Extra functionality centralized:
My favorite use has been logging actions so users have a history of what they've done. I wrap the Dispatcher with another class (Decorator Pattern) which logs the action. Then users have a nice audit log for themselves (and I do for myself) - stuff like this:
Only commands with also implement "Loggable" in my application are logged, so I can selectively decide which commands are logged.
To generalize that: Everything going through a central bus makes it a useful place to add extra functionality around some or all commands.
Exceptions
I use exceptions to catch validation errors and any other errors while the command is running, which is how i get information back to respond to a web request client.
Otherwise I have handlers return data, which are then returned through teh dispatcher, so the code calling the command can then use it:
Note sure if any of this helps clarify, just my 2 cents on how I use it and why I like it.