Command driven desing is quite a new buzzword in php world which the community is adopting quickly. Lets dive into some theoritical details of whats and whys of this desing patterns. Code examples will be based on
Coming out from the CRUD mentality
We developer like to think in terms of CRUD(CREATE, READ, UPDATE, DELETE) like kind of one-to-one mapping with business needs and out models but all business needs doesn’t go well with CRUD.
Like there’s a task named Charge client for some kind of service. This action is not easily mappable to CRUD with any model. And there can be tasks which affects more than one model in complex ways. Bending the tasks or the client to think in terms of CRUD is not the solution, rather this bending should be the opposite. We developers should look for patterns to bend to our thinking process to align more with the complex business needs. Command driven design is a solution to this problem where you can have commands like
SubscribeUserToSilverPlanCommand and any others use cases you have in your application.
There are several benefits of this using this pattern:
You can have really skinny controllers. HTTP itself is very simple and controllers are just gateways to your application, it’s better not do all kinds of business things in your controllers. That breaks the
Single Responsibilityprinciple of
SOLID. Using commands you can easily achieve this.
You can have better seperation of concerns in your application. With all your busiess entities seperated from others parts of the application, command from all kinds of business tasks and unified command pipeline for handling command.
Let me give you an example, With everything properly set up, lets see how a
user register action method of registration controller will look like,
1 2 3 4 5 6 7
Just see how clean it looks. Dont think it doesnt perform validation or other tasks required for user registration.
Lets list the tasks the above action is doing under the hood.
- Firstly the execute command might be coming from a
Traitwhich does all the heavy lifting. It creates a DTO(Data Transfer Object) with required constructor parameters required for user registration like username, email etc from the POST data.
- Then it call the proper vaidator for that command, you can determine yourself how the command bus will determine the FQN(Fully Qualified Name) of the vaidator class. After determining that the command bus will pass the command object to the Validator for input validation and checking business constraints. If the input from user doesnt pass the validation then it might throw a
FormValidationExceptionfor which we can set up a global exception handler and just send a response to client from that handler without returning the control to the controller action at all.
- And if the validation passes, the command bus then determine the
handlerclass for the command call maybe the
handle()method on that class and that method create the
usersave it to database of any kind which is also decoupled from the
- After creating user the handler dispatch
UserHasRegisteredevent, for which we can listen for using another listener class. Once that listener class has been invoked it can do all sorts of background tasks like, sending welcome email, adding users to a mailing list, sending confirmation email and anything else your business require. And all of that can go into the queue without keeping user waiting for this tasks.
From the face of all sorts of tasks it’s doing, it may seem intimidating at first glance. But once you have basic command bus and event dispatching system set up then just by following some convetions you can work pretty fast.
The real benefit of it maintanence. If you have application with a lifecycle of several years, if you don’t follow best practices it can soon become your headace. Even as the sole developer you will fear to touch it after sometime when its already a mess with controller actions doing all sort of things which necessarily controllers concern.
Another benefit of this approach is you can expose API for your project pretty easily as you have everything conatained already, exposting is just setting up new
routes for it and You are done. Because you are doing all your heavy lifting in their self contained objects.
Lets clarify some terms:
Data Transfer Objects are instances of simple classes with public properties to pass between different componets of your application. A simple
RegisterUserCommand DTO can look like (Taken from one of my personal project)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
as you see it has everything I need for user registration. And the cool thing is that the parameter on the the constructor of this class is auto-magically resolved form
laravel's Input::all() store where all get and post variables are stored.
Likewise, A sample
RegisterUserHandler can look like,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
And with these two and some other classes( like
RegisterUserValidator etc) placed in proper directories my
RegistrationController@store method is as simple as following
1 2 3 4 5 6 7 8 9 10
I dont have any input validation or anything in this action as they are all done in the command pipeline.
This kinda patterns takes some time to sink your head in them, but once you have the core set up then its really feels much better working on the project and you feel confident and better about it’s long term maintenance. I have learned most of it from this Laracasts series and from many other sources. I will be writting more about it. Stay tuned!
Hope you enjoyed it!