It is doubtful that many software developers will ever build distributed applications without middleware, but it is almost equally doubtful that there will ever be a consensus on what architecture and middleware is best. In this tip, I examine why component coupling in particular has been challenging and how cloud computing is introducing its own set of changes through things like microservices.
An application or architect driving distributed applications needs to get control of component coupling and middleware at the same time. And that means identifying the primary coupling models, taking a cloud-side view of the component coupling models and trends, cataloging the implications of coupling models on development, and relating component coupling to middleware architecture.
Passing work among application components is the central requirement for distributed development, and it's the basis for strategies on software component reuse. The cloud has linked componentization and coupling efficiency to resource efficiency and agility, which has profound implications on the best way to couple components and develop distributed software. It's important to understand basic middleware-coupling approaches.
The most fundamental question about middleware coupling is whether the called and calling processes are synchronized in real time. That means a message requiring service can be dispatched only if it can be received, and this places multithread constraints on the coupling unless the entire application can be made single-thread. Today, message-passing interfaces support real-time coupling, and message-oriented middleware provides queue-based decoupling to allow requests for component handling of messages to accumulate if multiple requests are made and the destination component can't keep up.
The second question to be answered on middleware coupling is whether service requests are blocking or nonblocking. When a message is sent, the sender can, in theory, either wait for a response (blocking) or proceed to do other things (nonblocking) -- and the same is true on the receiving-component side. Blocking calls to another component stops the calling process until service is complete and the result returned, and these are easy to develop. Where nonblocking coupling is used, the applications have to recognize the return of responses to messages sent elsewhere for processing, and this requires a more sophisticated application implementation. This model is often called an event handler because it requires components to handle work that is presented asynchronously.
Let's move now to cloud development. The cloud has popularized the so-called RESTful model, where messages are passed to stateless components for processing. In a stateless model, each message is processed as a complete entity, and it's the responsibility of the caller of a RESTful component to maintain context or state in a chained series of work requests -- such as what would occur in transaction processing.
The RESTful approach to workflow management among components contrasts with the more traditional remote procedure call (RPC) model that is commonly used with CORBA and SOA. With the RPC approach, an application component passes work to a remote component by calling it as though it were local. The context or state of the calling component is thus tightly coupled to that of the called component.
RPC models can support both time-synchronized and asynchronous approaches, and both blocking and nonblocking message handling, with proper component design. RESTful interfaces, designed largely for Web server applications that support a large number of concurrent events, are more intrinsically asynchronous. And good cloud-component design tends to encourage an event-handler, nonblocking application design pattern.
The final point in middleware coupling is that of directionality. In traditional middleware architecture, developers can build duplex (request/response) flows, or they can build simplex (unidirectional) flows, where request and response are separate events related by message content and not by process state. Message-handling interfaces are most often used for duplex flows, and message-oriented middleware (MOM) concepts are often used with simplex flows.
The middleware implications of coupling issues -- particularly as they evolve toward the cloud -- are best controlled by thinking about applications not as a series of components as much as a series of process threads. A Web application's threads are diverse at the client side and converge in the server. And in most cases, clients that represent human users are inherently single-thread and blocking. If this model can be used for your application, then what you're designing is essentially a Web application and RESTful principles will prevail. In that case, you should use minimalist middleware support for coupling and focus middleware selection on Web compatibility.
A transaction thread in true distributed processing is a chain of workflow events. It has been a common practice to employ a service or message bus and process-language steering to mediate this sort of coupling. Translating this to the cloud would create more rigid coupling than many application planners and architects want, but avoiding it would require a thread for each transaction, which is practical in a processing sense in many cases, but requires special design attention. State management within the messages, combined with message-oriented middleware and RESTful interfaces, can create a cloud-ready framework.
The three primary attributes of middleware coupling can be harmonized with cloud practices such as microservices, but there seems little doubt that a MOM model is easier to harmonize. However, components can be collected into aggregations that within themselves employ a different mechanism for coupling. This approach is common with Web applications that use RESTful coupling of converging client threads in the front end, and then rationalize to a MOM-based transaction processing back end.
The important point here is that component coupling should be optimized to the nature of the application first, and middleware and interfaces then selected to support that optimized model. When doing this, use the least complex middleware architecture with the most open implementation. That will keep your options as open as possible.
What is IoT middleware?
Learn how middleware speeds app delivery
Learn when loose coupling and SOA style layering doesn't make sense