Asynchronous Message Exchange Pattern Terminology
In software development, it can be quite difficult to give a good name to a component or coding artefact (such as a variable, method or class).
If you do not intentionally put effort into searching for a good name, then you are probably increasing technical debt and ongoing maintenance pain with terminology that causes confusion for other developers - or for yourself the following day when your memory has faded!
A good name for a coding artefact typically fulfils the following criteria:
- is as simple as possible;
- is descriptive and intention revealing - it conveys the purpose or [single] responsibility of the artefact;
- clearly differentiates its purpose from other artefacts;
- is intuitive for other team members to understand; and
- uses the accepted, ubiquitous terminology of the domain.
The last thing anyone wants is to be confused by a name that is ambiguous and overlaps with or overloads the name of other artefacts.
Deficiencies in the expressiveness of the English language itself can be a common cause of the difficulties we have. For instance, the Greek language distinguishes between at least four different ways of describing the one English word for “love”. Take that you imprecise and insufficient English language!
And so now we come to the word “asynchronous” when describing service call and message exchange patterns. Within the world of software, and especially in the integration, messaging or service-oriented architecture space, the word “asynchronous” is too overloaded.
Below is a list of the different types or usages of the word “asynchronous” that I am commonly communicating about and distinguishing between:
- A client can perform an asynchronous, non-blocking call to a service operation - e.g. from a background thread.
- A service operation may be called synchronously from a client, but the operation may return a response early to the caller and continue operating asynchronously in the background. For instance, this is possible with an Enterprise Service Bus / BizTalk orchestration.
- A service operation may be called synchronously from a client, but the client may perform the call using a synchronous-over-asynchronous messaging pattern. For instance, the client sends an asynchronous request message to a queue or service bus. The client then subscribes and waits for a correlated response message. To the end user, the entire interaction appears synchronous, none the wiser that asynchronous messages were used instead of typical web service calls.
- There might be a requirement for a service operation to be invokable both synchronously via a web service endpoint and also asynchronously via a message placed on a queue or service bus.
The word “asynchronous” is insufficient to clearly describe and distinguish between each of the points above.
So, borrowing concepts from both BizTalk ports and Command and Query Separation (CQRS), I am currently satisfied with using the following terminology:
- I only use the word “asynchronous” when a unit of work is performed in the background - where there is no caller waiting for a response message on the same channel it used to make the call in the first place. Please note that there is a difference between a response message and the ACK/NACK that is returned to the caller to acknowledge successful receipt (or not) of the message.
- A “Publish Message Command” pattern - where a caller sends/publishes a message to a queue or message bus and there may be multiple subscribers listening for that message.
- A “One-Way [Asynchronous] Command” pattern - where a caller sends a message to a queue or message bus, and a unit of work is performed in the background.
- A “One-Way [Asynchronous] Command with an Asynchronous Response” pattern (also known as a “Synchronous-over-Asynchronous Command / Query”) - where a caller sends a message to a queue or message bus and also subscribes to a corresponding/correlated response message that it waits for. Meanwhile, a unit of work is performed in the background and that unit of work publishes the corresponding/correlated response message to be received by the waiting original caller.
The terminology “One-Way” explicitly refers to the endpoint receiving a request and never sending a response message back to the caller (once again, the ACK/NACK is not considered a response message).
“Two-Way” however explicitly refers to the service endpoint receiving a request message and the service returning a response message back to the caller.
If we were to extend a similar style of terminology into the world of synchronous patterns, we would have:
- A “Two-Way Command” pattern for a synchronous service operation - where the caller waits for a response; and
- A “Two-Way Query” pattern for a synchronous service operation that is typically read only with no side effects (except perhaps for writing security audits).
To make things more interesting, different technologies may enable or prevent certain patterns from being implemented. For instance, in .NET, a “One-Way [Synchronous] Command” pattern can be implemented in WCF. In this case, the .NET method signature would have a “void” return type, operate synchronously and then at the end of the operation would return the typical ACK/NACK. This communication pattern however is not applicable in the world of BizTalk.
This WCF version of a “One-Way [Synchronous] Command” pattern is the only reason why I included the text “[Asynchronous]” in the name of the One-Way asynchronous patterns above - in order to clearly differentiate between them.
With this terminology, I have found that I can more quickly and clearly discuss message exchange patterns with my team. I hope it does the same for you!