Patterns of Events

Alexander S. Ran

Nokia Research Center, Software Technology Laboratory,

P.O. Box 45, 00211 Helsinki, Finland

e-mail: ran@research.nokia.com

"... we must begin by understanding that every place is given its character by certain patterns of events that keep on happening there." Christopher Alexander

1. Event-centred architecture.

Context

In many domains products are organised into families, in which each member-product is a slightly different version of the same prototype. These product families are the result either of the evolution of one product or of the parallel development of related products designed to satisfy different requirements of the same problem.

Product families are extremely important, because they help to minimise the costs of concurrent evolution of similar products. This is only possible, of course, if the products are related not only by their function but also by their internal structure. As a product family evolves, developers should preserve the distinction between what the family members share and what is specific to each member. This goal is hard to attain in the context of evolving families of software products.

Objectives

In most circumstances software designers should strive to optimise the development and maintenance of the entire software family rather than just individual programs. Usually we wish all the members of the family to be constructed from the same set of reusable components. Ideally, members of a family are identical architecturally and differ only in subsets of their components.

The architecture of a family should represent the essential core shared by all members that is unlikely to change, but may be incrementally extended or specialised for a particular application. In such an architecture the components should not be bound to each other directly, but only through their interaction with the core. Furthermore, the core should not depend on the presence or functionality of particular components.

Approach

Architecture of a program family is often understood as a common structure maid by the major parts of the member-programs. In this approach the structure depends on the components. Changes in the components affect the structure.

In The Timeless Way of Building, Christopher Alexander [1979] wrote "we must begin by understanding that every place is given its character by certain patterns of events that keep on happening there. . . . And indeed, the world does have a structure, just because these patterns of events which repeat themselves are always anchored in the space."

A family of programs defines a specific application domain. Each application domain is given its character by certain patterns of events that keep on happening there. And indeed, the structure on an application is just a consequence of some components of the application causing and some responding to these events. Thus we may achieve a greater stability of program family architecture if it is based on the major events that occur in the domain. The advantage to event-centred architecture is that, by starting from important events and then decomposing a system into components bound not to each other but to events, it helps to create a stable architecture for an evolving program family.

Notes

The term event is often used to mean a special communication mechanism (interrupt, signal, operating system message) that is different from the function call mechanism. These should not be confused with the events discussed here, that are conceptual entities unrelated to implementation details.

Events represent and communicate important changes in the state of a system. However event-centred architecture does not assume that this state is explicitly represented anywhere.

2. Classes of event objects.

Context

In event-centred architecture events become rather complex entities - significant modelling power is required to properly capture their different aspects.

Objectives

Some information may be associated with each event. Different event generating components may use different kinds of information to generate the same type of events. Events must eventually transfer control to reactive components. Reactive components may require different views of the same event.

Complex relationships may exist between events: events may cause or imply other events, they may shadow or disable other events, etc.

Generation of an event must be independent of the response to the event. This is required in order to avoid binding between components and to allow more freedom in scheduling of the response.

Approach

When an object-oriented programming languages is used for software construction, it is appropriate to use classes to model events as system-level concepts. Event classes allow the programmer to treat events as a group. Event generating components instantiate event objects. Different components may use different instantiation methods to generate events, based on different types of information.

Event objects allow the programmer to separate event generation from event handling. Notification of reactive components about event occurrence is the responsibility of the event objects. Event objects encapsulate information associated with the event and may provide different views of this information to different reactive components.

Registration of the reactive components may be handled by subscription services provided by the event classes. Event classes may establish requirements to subscribers. A minimal requirement may be the capability to handle events of this class. Subscription protocol may also ensure that additional conditions are fulfilled by a prospective subscriber.

Notes

The behaviour of components that dynamically subscribe and unsubscribe event classes - possibly as a result of receiving events - is difficult to understand. A program that relies on such capability resists static analysis and is often impossible to understand by reading. It is usually better to regard the relationship between a component and the event classes as static. The lost flexibility of dynamic changes in the coordination behaviour may be regained by other means. Component invocation procedures associated with different event classes may depend on some system-level condition. State-dependent event response of reactive components is addressed by the object-oriented state machine pattern.

3. Fine-Grained Classification of Events

Context

A reactive component is usually interested in only a small subset of all possible events. Invocation of components for irrelevant events may significantly increase the computational cost of invocation. This approach also requires components to be ready to receive events of different types, making component behaviour more complicated and even sacrificing type safety.

When it is invoked by an arbitrary event, a component must decide if the event is a member of its set of interest. Different components may be interested in the same or different sets of events; furthermore, these sets may be disjoint or intersecting or one set of events may be a subset of another. If several components are interested in the same set of events, it is wasteful when invoking the components to repeatedly perform the computation of the membership for the same event in the same set.

An event's membership in different sets of interest may be determined more efficiently if the relationships between the sets are known in advance. When sets of interest are static, it is possible to compute and efficiently encode membership information for every possible event prior to the deployment of the system.

Objectives

Event classes provide the context in which reactive components operate. This context must be specific enough to make the definition and operation of reactive components more effective. How specific this context is depends on how specific is the classification of the events in the program. Merging event classification into the functionality of reactive components complicates their behaviour as it hides and replicates important information. This increases the cognitive effort required for understanding the program, and also results in computationally inefficient systems. Fine-grained classification of events explicitly represents important information that is otherwise hidden in the computations performed by the reactive components.

Approach

Design a hierarchy of event classes that models the generalisation / specialisation relationship between events generated and expected by different components in the system. It is possible using multiple inheritance to express an arbitrary partition of the set of all possible events so that each set of interest is represented by a class of events.

A component may register its interest in one or several classes of events. A component that is registered for a class of events is considered to be registered for all the subclasses of this class as well. Thus queues of registered components are inherited in the event hierarchy. An event object invokes only the components registered in the event class of which it is an instance. This approach essentially substitutes run-time computation of event membership in the sets of interest of different components with compile-time typing of the events. Since the inheritance relationship between event classes is known prior to the creation of events the invocation of reactive components may be optimised.

Notes

The hierarchy of event classes establishes a natural ordering for invocation of subscribed components. A reactive component with more specific interests or responsibilities with respect to an event should be notified of the event before a reactive component with more generic interests or responsibilities.

Each class of events may specify its own invocation procedure used to invoke the components registered for it. Invocation methods should be combined in order of descending specificity in relation to the class of the event object. Since method combination is essential in the process of object initialisation, even languages that do not support method combination in general will combine the initialisation methods. This may be used to construct the invocation plan that is executed by the event object after it is constructed.

4. Object-oriented state machine

Context

Reactive components integrated into systems with event-centred architecture are essentially independent and are often distributed and concurrent. Each reactive component is attached to some event classes. A reactive component should provide the necessary interface for invocation by event objects. The actual response of the reactive components may be rather complex and often depends on the state of the component at the time of invocation.

Objectives

The states of a reactive component are essential for understanding its functionality and must be explicitly represented. A state is a condition that implies more specific component behaviour than may be generally assumed. Event response of reactive components may be specified in correspondence with their state. This helps to specify the dynamic component behaviour that is otherwise too complex. The specification of behaviour is divided into several cases, each corresponds to a different state. Jointly, all states specify the component behaviour.

Much the same way that subclasses are used to refine the behaviour specified by their superclasses, states may be further partitioned by substates. When objects in a state exhibit complicated behaviour that depends on additional conditions, substates may be identified that guarantee simpler behaviour of the objects. This process of incremental specialisation of conditions and the corresponding behaviour may be continued until each state is characterised by sufficiently simple behaviour.

It is important that the selection of the event-response method is done in correspondence to the state of the reactive component and does not need to be explicitly programmed.

Approach

The representation and behaviour of a component is specified jointly by a cluster of classes. The root of the cluster specifies the public interface of the component and the state-independent part of its representation and behaviour. Each state is represented as a class that directly or indirectly inherits the root of the state cluster. State classes specify the state-dependent aspects of representation and behaviour of the component. State classes may include in their definition a predicate that specifies the condition of the state. States with complicated dynamic behaviour may be specified using substates, represented by further subclasses. A dispatcher class with standard behaviour that inherits from all the states of the cluster may be automatically generated. Objects that represent reactive components are instances of the corresponding dispatcher classes. Dispatchers use a standard state classification procedure to control event-response method selection for the reactive component in accordance with its state.

5. See Also

Event-based integration, also called implicit invocation, is discussed in detail and compared to other architectures in [SullivanNotkin], [GarlanShaw]. Design space for implementation of implicit invocation in different programming languages is explored in [NotGarGrisSul]. In the object-oriented systems implicit invocation is commonly associated with automatic change propagation. Active values [SteficBobrowKahn] of LOOPS allow to associate arbitrary actions with access to a variable. Model-View-Controller [KrasnerPope] of Smalltalk-80 is, probably, the best known framework for change notification specialised for user interfaces. A pattern for event objects was discussed in [Beck]. Several related design patterns like Subject - Observer, Chain of Responsibility, Mediator, State, etc. are presented in [GamHelJohnVlis]. Modelling states as classes is discussed in [Ran].

6. References

[Alexander] Christopher Alexander, The Timeless Way of Building, Oxford University Press, 1979.

[Beck] Kent Beck, Using patterns: Design, The Smalltalk Report, Vol. 3 No 9, July-August 1994.

[GamHelJohnVlis] Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides "Design Patterns: Elements of Object-Oriented Software Architecture", Addison-Wesley, 1994.

[GarlanShaw] David Garlan and Mary Shaw "An Introduction to Software Architecture", Advances in Software Engineering and Knowledge Engineering, Vol. 1, World Scientific Publishing Company, 1993.

[KrasnerPope] Glen E. Krasner and Stephen T. Pope, "A Cookbook for Using the Model-View-Controller User Interface Paradigm in Smalltalk-80", Journal of Object Oriented Programming, vol. 1 (3), pp. 26-49, 1988.

[NotGarGrisSul] David Notkin, David Garlan, William G. Griswold and Kevin Sullivan. "Adding Implicit Invocation to Languages: Three Approaches". JSSST-93, LNCS-742, Object Technology for Advanced Software. Ed. Shojiro Nishio and Akinori Yonezawa. New York: Springer-Verlag, 1993. 489-510.

[Ran] Ran A., Modelling States as Classes, in Proceeding of the TOOLS USA 94, Prentice Hall 1994.

[StefikBobrowKahn] Stefik M.J., Bobrow D.G., Kahn K.M., Integrating access-oriented programming into a multiparadigm environment. IEEE Software, January 1986.

[SullivanNotkin] Kevin J. Sullivan and David Notkin. "Reconciling Environment Integration and Software Evolution". ACM Transactions on Software Engineering and Methodology 1, 3 (July 1992): 229-268.