Notification Based Design

April 24th, 2007 | jchaager | programming

As discussed in a previous article, Interface-based design has limitations that I have had to address. In this post, I discuss a specific architecture that applies the theories discussed previously.

Introduction

Application design philosophy has evolved over the years from monolithic, tightly coupled systems, to loose coupling, to interface based coupling. This last is the philosophy embodied in the Spring Application framework. However, this can still lead to problems with tight coupling of application components.

Although Spring based applications are normally connected together using interfaces, it is very easy to slip into a system where every component needs a reference to several other components. This leads to a fragile system where replacing or modifying a single component can lead to cascading behavioral changes throughout the rest of the system. Additionally, it is possible for unintended relationships between components to be introduced, further complicating the architecture.

As an alternative to this, an application could be design around a Notification based philosophy. In such a system, the components are not wired directly to one another. Instead, each component is designed as an autonomous component that responds to specific notification events and to post specific notification events in response to well defined stimuli.

In such a system, none of the components need to be directly connected to each other. If a component is removed or replaced, no changes are needed to the surrounding components. If a new component is introduced to provide a new capability, it doesn’t need updates to any other components to work, and it doesn’t need to be connected to any existing components. It simply subscribes to the exiting notifications that are already in the system and responds to those.

Synchronous vs Asynchronous Dispatch

If you start discussing notification systems, the question invariably comes up of whether the system should be synchronous or asynchronous. In a synchronous system, posting a notification actually calls the handlers on all registered listeners and allows them to process the notification before the posting call returns. In an asynchronous system, the notification is placed into a queue and dispatched by a separate thread to all the registered listeners.

Synchronous dispatching has the advantage of allowing listeners to immediately react to the event without any intervening changes to shared data such as an application model. However, this can lead to very deep call stacks and situations where action is taken and shared resources modified before the original poster is able to finish what they were doing.

Asynchronous dispatching has the advantage of allowing the poster to immediately continue their processing without delay. However, if the notification dispatching happens on a separate thread, synchronization problems can occur between the listeners processing the notification and the original poster who might still be trying to do some processing.

So, we would like the benefits of synchronous dispatching without the deep callstacks and we want the no delay processing of asynchronous dispatching with the synchronization problems associated with it.

Global Event Dispatching

To achieve the goals stated above, we can design a system as follows. A single notification system is defined that all components use. A single Event Queue is created that all components use. When a notification is posted to the notification center, the Notification center places an event on the Event Queue that will cause the dispatching of the notification to the listeners. All notifications are then dispatched off of the single Event Queue thread insuring that the core of the application operates as a single threaded application resolving most potential race conditions.

It is possible, however, that external interfacing components might need their own threads to handle their interfaces, such as sockets. When events occur on these systems that require the updating of shared resources, such as the application model, these components should push events onto the event queue that will callback to the component for them to modify the model. This insures that al modification to the shared resource occur on a single thread and avoid race conditions that might otherwise occur.

Conclusion

This article has defined an asynchronous, notification-based, application architecture that allows applications to be constructed that are very loosely coupled, primarily single threaded, and event driven. By following a few simple rules, the application can be extended and enhanced without adversely affecting other components.

Rule #1: Components should subscribe to notifications about events they need to respond to. Rule #2: Components should publish notifications about events that other components might want to respond to. Rule #3: Components should only modify shared resources, such as an application model, when dispatching a notification, or executing a call back scheduled on the Event Queue.

Related Posts:


Leave a Comment