- Heterogeneity of Communication Mechanisms
- Communication Middleware
- Synchrony
- Interface Versus Payload Semantics
- Tight Versus Loose Coupling
- Conclusion
3.4 Interface Versus Payload Semantics
Typically, an interaction between a client and a server (or a sender and a receiver) results in the execution of a transaction (or some other activity) on the receiving end. In order to determine the type of transaction or activity that was requested by the caller (or sender), it is necessary to specify the operation. This is normally performed in one of two ways: The requested transaction/activity can be encoded in the operation signature of the server component's interface, or it can be embedded in the message itself.
In the first case, the requested transaction (or other kind of activity) is defined by using self-descriptive function names such as saveCustomer(), retrieveCustomer(), or transferMoney(). RPC-style interfaces provide this type of semantically rich interface, which we refer to as interface semantics (see Figure 3-13).
Figure 3-13 RPC-style interaction is typically based on interface semantics. Every procedure call has a meaningful name that indicates its purpose.
In the second case, the requested transaction is embedded directly into the message (see Figure 3-14). This can be done as part of the message header (if the MOM provides such a field as part of the message header data structure), or as part of the application specific payload. We refer to this as payload semantics.
Figure 3-14 The name of a remote call with payload semantics has no functional meaning in its own right. The remote functionality required is encoded in the message that is sent. The receiver typically has to determine the function name and the dispatch message to the associated business function.
Payload semantics is widely used in the context of MOMs that provide APIs with functions such as MQGET()/MQPUT() or sendMessage()/onMessage()/receiveMessage() for the clients and servers to communicate with each other. The semantics of these functions is purely technical (see Figure 3-15).
Figure 3-15 MOM is generally based on payload semantics. Functions such as sendMessage() and processMessage() are purely technical, without any business semantics.
Interface semantics provide users with well-defined interfaces that are intuitive and easy to understand. Changes to these interfaces require modifications to all applications that depend on the particular interface, even if they do not depend on the operation or argument that was added or changed. Payload semantics, on the other hand, result in systems where changes to message formats can have a potentially lesser impact on the different components of the system. New functionality can easily be added to a system by creating new messages types. Consumers that are not dependent on the new messages types remain unaltered. Thus, payload semantics results in a weaker coupling at the type level.
The choice of interface semantics versus payload semantics is not an obvious one, as each approach has its pros and cons. Strongly typed languages, such as Java, limit the flexibility of the programmer by applying strict type checking at compile time. Almost all dependencies caused by the change of a type in the system can be discovered at compile time, thus significantly reducing the number of runtime errors. Weakly typed languages, such as TCL, offer much more flexible data manipulation, often based on string manipulation. These types of languages are generally used for scripting, especially in Web environments, where fast results are required.
However, the application of interface semantics and payload semantics cannot be viewed in black-and-white terms. While RPCs are not restricted to pure functional call semantics, neither are MOMs limited to payload semantics. This can be illustrated with one insightful example. Consider an RPC call such as transferMoney(). The transmitted data can significantly contribute to the determination of the code that is executed:
String transferMoney (amount: decimal; cur, accFrom, accTo: String); { switch (cur) case 'EUR': handleEurTransfer (amount, accFrom, accTo); case 'GBP': handleGbpTransfer (amount, accFrom, accTo); case 'USD': handleUsdTransfer (amount, accFrom, accTo); . . . }
Going one step further, it is possible to remove all interface semantics from an RPC-style interface. In the following example, a service supports exactly one function, executeService(). This function has only one parameter, a plain string. This string encodes all functional parameters and the requested functionality:
String executeService (message: String); { int i = determineFunctionNumber (message); switch (i) case 1: handleCase1 (message); case 2: handleCase2 (message); case 3: handleCase3 (message); . . . }
3.4.1 Document-Centric Messages
With the emergence of self-descriptive data structures such as XML, an approach to handling message types referred to as document-centric has become popular. Document-centric messages are semantically rich messages where the operation name, its parameters, and the return type are self-descriptive. However, the passed parameters and returned object can be extremely flexible and can include any number of optional parameters. SOAP (Simple Object Access Protocol) is a technology that is particularly suitable for this type of solution. As long as the underlying XML Schemas impose only loose constraints on the document structure, the parameters can be extended in any manner required without breaking compatibility with previous software versions. Consider the following example that describes the booking of a flight. It is straightforward to enhance the protocol with additional parameters, such as the time of day of the flight, the date and time of arrival, or the verbose names of the airports. As long as these fields are not required, the previous version of the protocol, in addition to all software that relies on that version, remains totally valid. Because this type of communication includes a structured document in both reply and response, it is called document-driven communication:
<SOAP-ENV:Envelope xmlns:SOAP-ENC="http://schemas.xmlsoap.org/ soap/encoding/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <SOAP-ENV:Body> <ns1:bookFlight xmlns:ns1="http://www.openuri.org/"> <ns1:inbound> <ns1:flightNumber>LH400</ns1:flightNumber> <ns1:flightDate>2003-11-08</ns1:flightDate> <ns1:isConfirmed>false</ns1:isConfirmed> </ns1:inbound> <ns1:outbound> <ns1:flightNumber>LH401</ns1:flightNumber> <ns1:flightDate>2003-11-17</ns1:flightDate> <ns1:isConfirmed>false</ns1:isConfirmed> </ns1:outbound> <ns1:passenger> <ns1:Passenger> <ns1:firstName>Karl</ns1:firstName> <ns1:lastName>Banke</ns1:lastName> <ns1:birthday>1970-08-05</ns1:birthday> </ns1:Passenger> </ns1:passenger> </ns1:bookFlight> </SOAP-ENV:Body> </SOAP-ENV:Envelope>