What Are Command Functions?
Command and Queries Functions comprise the two complementary behaviours of Command Query Responsibility Separation or CQRS. While Query functions measure and report on the state of a system, Command functions, or Commands for short, change a system’s state.
Command Functions
How do Command Functions alter the state of a system? Simple, they receive a Command Message containing information that will update the system state.
In a broader sense, Command Messages could be an HTTP POST payload, an event in an event store, or one or more parameters in a function call.
Command functions intend to change the state of the system. They create a Side Effect. Unlike queries, commands do not enquire as to the state of the system, and therefore no return value should be required — Commands return void
. Well, usually—we’ll come to that.
Example Commands:
// C# property setter called via assignment. Eg. IsActive = true;
bool IsActive { set; } void Update(CustomerRevision revision); void SetOrderStatus(OrderStatus newStatus)
In a minority of cases, it does make sense for Commands to return a value:
Customer Register(CustomerRegistation registration);
In this example, if the call to register a new customer succeeds, it will presumably have saved a new customer record, including an identifier to a persistent data store for later retrieval. It is only appropriate that this command function informs the caller of the newly created customer record, including the internally generated customer identifier, so we can reference this customer in other operations — for example, when the customer makes a purchase.
Errors
However, we do not require a return value from a Command Function to communicate a problem or error in program operation.
To illustrate, let’s consider what a high-level method to register a new customer might look like using a hybrid return structure which combines the customer, in case of successful registration, and an error message describing a failure:
public class RegisterCustomerResult
{
public bool IsSuccess { get; set; }
public string ErrorMessage { get; set; }
public Customer Customer { get; set; }
}
And
public RegisterCustomerResult RegisterCustomer(CustomerRegistration registration)
{
var validationResult = Validate(registration);
if (validationResult != ValidationStatus.OK)
return new RegisterCustomerResult
{
IsSuccess = false,
ErrorMessage = validationResult.Error
}; var customer = registration.ToCustomer();
var dbResult = Repository.Save(customer);
if (dbResult != DbReturnCode.SuccessOK)
return new RegisterCustomerResult
{
IsSuccess = false,
ErrorMessage = dbResult.ErrorMessage
}; return new RegisterCustomerResult
{
IsSuccess = true,
Customer = customer
};
}
The RegisterCustomer()
command method is noticeably busy, and it isn’t easy to understand what’s happening. The result code checks are to blame.
Error return codes are out. I recommend you avoid them.
Maybe we can do better.
How should a Command function communicate errors back to its caller?
The answer is with Exceptions.
Exceptions
Commands throw exceptions to signal errors to the calling function. This approach simplifies our code by removing the need for result code checks.
Here is an alternative version of the RegisterCustomer()
method, but this time Validate()
and Repository.Save()
communicating errors via exceptions:
public Customer RegisterCustomer(CustomerRegistration registration)
{
Validate(registration);
var customer = registration.ToCustomer();
Repository.Save(customer);
return customer;
}
How much simpler is that? A lot, I think. The return code checking in the previous example masked the real action that is so clear in the second: Validation, Conversion, Persistence, Return Customer, Done!
Command Functions should communicate errors via Exceptions.
If you enjoyed this article, please leave some claps — and a bunch of claps if you loved it! :) Thank you kindly.
Join my email list to fast-track your software engineering career.
When signing up, you’ll get my guide, ‘The Road to Master Progammer’, containing 3 powerful ideas to help you shorten your journey to expert programmer.