- Commands are pure Plain Old Objects
- Commands are used to execute and capture user actions
- Commands, when executed by a command handler, can run only in a single bounded context (a transaction boundary, with the exception of long running commands triggered via saga)
- Commands are classes that implements ICommand Interface or possibly inherits from the BusinessCommand abstract classes
- Command Handlers are registered by our Inversion of control in a central registry using the service locator pattern to load the needed command handler into the handling scope.
The above features are not everything that makes up a command, but enough to form my arguments around the subject matter. We concluded that we will leverage the dependency injection framework to serve as an invocation container for our commands and command handlers, therefore making for simple extensibility of the application by just registering a command (business requirements) and a command handler (business processor) using a declarative form rather than wiring everything up by hand whenever a new business requirements comes up, we can register and de-register our commands as the application evolve and due to clients need.
There is nothing new about maintaining a software architecture that favours plug-ability from ground up, I am a fan of software framework and architecture that makes writing code painless and developer friendly frameworks. Hence the reason for favouring service registration via declarative means over imperative paradigm.
I happen to chat with someone who disagree with using dependency injection as a way of service location strategy. We were chatting about how to create a console application like command line that takes in instructions like copy, move, ftp, message, delete etc ... At first the problem statement is something of high interests to me, and having been working on a distributed and message driven architecture for sometime now, I have come to appreciate the role of simulating the user actions, and my first go at the question is to use command pattern to capture all console instructions, and my suggestions was as follows:
- copy becomes CopyCommand
- move becomes MoveCommand
- ftp becomes FTPCommand
- message becomes MessageCommand
- delete becomes DeleteCommand
With experience that I have gained from using and building lots of commands and handler in a very complex business oriented project, it should not be far fetched that command is the right answer to this friends question. I gave the suggestion of command pattern, it allows passing command message into each command after the parsing instructions entered into the console from the prompt using a text parser or scanner to finish the business of tokenization (my favourite). It is not that there are no other ways, but I am still sticking to my choice of pattern, which does the job gracefully (what you dont know doesnt kill).
Now the business of identifying what will form the basis of my friends architecture is over, my friend wants to know how I am now going to wire the commands from the console to the concrete commands declared as classes in the code base. I said to my friend that it is a piece of cake, use dependency injection as a service locator, as the application grows, it will just be a matter of registering a command against a particular naming convention, in our case the command will be registered against the name of the console command as the following example:
The above registers console processing instruction against the command in code. A beautify way of locating commands that are mapped to the instructions, and of course I know that there are many ways that this can be done, but I preferred this approach .
Then my friend begin to see the clarity in my intentions, it was now occurring to him that I am building a software based on principles and pure object orientation and abstraction, but he continue to argue that my approach will break Single Responsibility Principle, but how? the command handles one thing, performs only one function. Also he criticised the use of the dependency injection for locating services, saying that the business requirements now relies on the IOC container to function appropriately, then I asked what can do this job than IOC container.
We ended the conversation by me suggesting other approaches to registering command against console instructions, and they are as follows:
- Use reflection to locate relevant commands, by annotating the command classes with attributes that carries the console instruction name.
- Create a registration repository class that does the wiring
- Re-invent the dependency injection approach and give it a more shiny name to pretend it wasn't IOC.
- Try and understand that we are both trying to decouple
While there might be little or no fault in the approach, but it is likely to succeed due to command pattern which would let you organise your business requirements in a nice and self describing code structure (some code do speak for themselves, you do not need a huge documentation to figure that out).