Chapter 8


This chapter summarizes the results of this work and distills a set of design guidelines for developing notations, mechanisms, and tools that facilitate software reuse. It concludes by discussing some ideas for future research.

8.1 Summary of Results

This thesis began with the question: Why is it difficult to integrate existing components into new applications?

Chapter 2 attempted to provide one answer. Our answer was: Because components built using current technologies contain fragments of interconnection protocols that connected them to other components in their original applications. This is due to a failure of current programming languages to provide separate abstractions for representing interconnection protocols among components. Programmers are thus forced to disperse fragments of such protocols among the interdependent components. When attempting to reuse such components in applications with different interconnection needs, these built-in, and often undocumented, assumptions get in the way. They have to be manually identified and resolved, either by modifying the code of the component, or by manually writing additional coordination code that bridges assumption mismatches.

This observation suggested one solution for alleviating the problem: Separate the "core" function of components from their application-specific interconnection protocols and develop language abstractions for specifying and implementing each separately. The main body of this thesis was devoted to proposing and exploring one practical way of achieving this separation.

In order to be able to separate the main functional pieces of an application from their interconnection needs and protocols, we need notations for describing application architectures that provide separate abstractions for each. Chapter 3 introduced SYNOPSIS, one such notation developed for this thesis. SYNOPSIS is an architectural language that supports two orthogonal abstractions: activities, for describing the main functional pieces of an application, and dependencies, for specifying their interconnection needs in the context of an application. Dependencies are managed by coordination processes, an attribute of dependencies which represents implementations of interconnection protocols. Using SYNOPSIS, designers specify new applications as patterns of activities, interconnected by dependencies. Applications can then be implemented by successively specializing activities and dependencies, until all activities are directly associated with code-level software components, and all dependencies are managed by executable coordination processes.

To assist the design task of representing application interconnection needs, as well as the design of appropriate coordination processes, Chapter 4 proposed a standardized, but extensible, vocabulary of dependency types and an associated design space of coordination processes. The vocabulary is based on the observation that the most frequently occurring patterns of component interdependencies are independent of any application domain, and can be specified using a relatively narrow set of concepts, such as resource flows, resource sharing, and timing dependencies. Likewise, the design of coordination processes involves a relatively narrow set of concepts orthogonal to the problem domain of most applications, such as machine architectures, language conventions, and communication mechanisms. For those reasons, the development of an application-independent framework that captures the most useful patterns of interdependencies and the ways of managing them, looks like a feasible and useful endeavor. Such a framework can form the basis for a developing a design handbook of software component interconnection.

To test the feasibility and usefulness of both our language and our design space, we built a prototype component-based application development tool called SYNTHESIS. SYNTHESIS provides graphical editors for entering and editing SYNOPSIS architectures. It provides support for building repositories of SYNOPSIS entities, including activities, dependencies, and coordination processes. Finally, it provides a design assistant that exploits a repository of dependencies and coordination processes based on the framework of Chapter 4, in order to semi-automate the design process specializing generic design elements, and automate the process of integrating a set of excutable design elements into sets of code modules. Chapter 5 was devoted to a detailed description of the algorithms and transformations used by the design assistant.

In Chapter 6, we have used SYNTHESIS to perform four experiments that tested different aspects of our approach. The most important areas where we have put our technology to the test include:

SYNOPSIS and our current vocabulary of dependencies were able to concisely and elegantly describe all four test applications. SYNTHESIS successfully exploited its repository of coordination processes in order to generate all four systems with minimal need for additional user-written code. Additional user-written code was only required in three cases to implement unsupported data format conversions, and consisted of simple subroutines which, once written, became a permanent part of the coordination processes library and were re-used in later experiments.

The system was able to resolve both low-level interoperability mismatches (differences in provided and expected procedure names, parameter data types, languages, etc.) between heterogeneous components, as well as more fundamental architectural mismatches between components with incompatible built-in interaction assumptions (e.g. a filter, writing sequential byte streams, and a server, processing individual lines of text). The stronger the built-in assumptions, however, the less the flexibility of efficiently reusing a component in alternative organizations.

Finally, our experiments proved that describing applications at the level of activities and dependencies allows a single SYNOPSIS description and a single set of components to be reused for generating applications for different target environments simply by selecting different coordination processes suitable for each environment.

8.2 Design Lessons

The main body of the thesis is devoted to describing one concrete approach for developing software applications from existing components. Underlying this approach, however, is a set of more abstract principles that can serve as a framework for developing notations, mechanisms, and tools for facilitating software reuse. This section distills these abstract principles and gives a brief explanation.

8.3 Future Work

In this section I will briefly describe some ideas for further research suggested by the various components of this thesis.

8.3.1 SYNOPSIS Architectural Language

No programming language design is ever complete. As more experience is gained with a programming language, additional features are added and existing features are modified to enrich its expressive power. We expect the same to happen with SYNOPSIS.

Two immediate areas of future enhancements have been identified in the thesis:

8.3.2 Coordination Process Design Space

Extend vocabulary of dependencies

Although the vocabulary of dependencies presented in Chapter 4 is capable of describing a large number of commonly occurring relationships, it by no means claims completeness in any rigorous sense. Further experience with using the approach to describe and implement non-trivial software applications might uncover additional relationships that could usefully be encoded as special cases of existing dependency types, or as new dependency types. Likewise, the design space of coordination processes can be enriched by new generic processes, or by new special cases of existing generic processes.

A particularly promising path seems to be the discovery and classification of commonly occurring composite patterns of dependencies, for which efficient joint coordination processes have been developed. One example is the joint management of a set of unidirectional flows through the network by combining the respective data items into a single packet. The existence of a library of such composite entities will enable automated design assistants to scan SYNOPSIS application diagrams, discover patterns of simpler dependencies that correspond to composite dependencies, and efficiently manage them using joint coordination processes. Section 4.8 presents some examples of composite dependencies and coordination processes for jointly managing them.

Develop coordination process design rules

In the current implementation of the system, designers are responsible for selecting among multiple compatible coordination processes for a given dependency. It would be interesting to develop design rules that help automate that selection step by ranking candidate processes according to various evaluation criteria such as their response time, their reliability, and their overall fit with the rest of the application. For example, when managing a data flow dependency, one possible design heuristic would be to use direct transfer of control (e.g. remote procedure calls) when the size of the data that flows is small, and to use a separate carrier resource, such as a file, when the size of the data is large.

Explore relationship to architectural style

Several researchers are using the term architectural style to describe and classify recurring organizational patterns and idioms, such as client-server, pipe-filter, and event-based architectures. Section 6.3 has provided some evidence for the important role of coordination processes in determining the overall architectural style of a software system: By selecting different coordination processes, the same set of components can be organized into different styles.

Our multi-dimensional design space of coordination processes can thus provide a useful vehicle, both for defining styles as points in our space (combinations of design choices), and for providing more specific guidelines as to which design choices are consistent with a desired architectural style. For example, in Section 6.3 we hinted that event-based architectures exclude the management of dependencies using push or pull organizations. Furthermore, our design space could help invent and characterize new styles, for which widely-accepted names do not yet exist.

8.3.3 SYNTHESIS Design Assistant

Like every prototype implementation, SYNTHESIS could benefit from a substantial rewrite that will focus on improving its performance and scalability. From a research perspective, the following are some interesting topics of future work:

Develop search/selection heuristics

Before managing a dependency, the SYNTHESIS design assistant performs an exhaustive search of candidate coordination processes, applying the compatibility checking algorithm of Figure 3-15 to each candidate. For large repositories of coordination processes, this approach will be prohibitively slow. Appropriate heuristics must be developed that will eliminate some of the potential candidates without the need to apply the compatibility checking algorithm. Such heuristics might rely on specifications of performance requirements, or on constraints on the desired architectural style of the overall system.

Build handbook of domain-specific architectures

In this thesis, we have emphasized the use of SYNTHESIS for building repositories of application-independent coordination processes and assisting designers in the management of dependencies. In most of the thesis we have assumed that the responsibility for decomposing the architecture of a system into a pattern of activities and dependencies fell to the designer.

However, both SYNOPSIS and SYNTHESIS are particularly well-suited for building repositories of generic and specialized architectures in a wide variety of domains. Such repositories of domain-specific architectures or software architecture handbooks, could serve as useful starting points for designing any new system: When starting the design of a new application, designers first consult the handbook, in order to retrieve alternative generic architectures of similar systems. They can then specialize those generic architectures to fit their particular needs.

The use of the system as a software architecture handbook is an intriguing path of future work. Additional considerations that will have to be addressed in this case include building a robust and scalable SYNOPSIS entity repository, and providing adequate navigation mechanisms for retrieving related architectures.

8.3.4 New Component Programming Languages

This thesis argued for notations which separate the "core" function of software components from their application-specific interconnection protocols. It proposed SYNOPSIS, an architectural language for describing new applications with these properties. SYNOPSIS allows the main functional pieces of a new application to be specified independently from their patterns of dependencies in that application.

Since the practical objective of our system is to facilitate the reuse of existing components in new applications, SYNOPSIS executable activities are currently associated with code-level components built using current technologies. Such components, inevitably incorporate some built-in interaction assumptions from their original development environments (see Chapter 2). The existence of such assumptions is a violation of the intended separation of "core function" and "interconnection". In some cases difficulties associated with such assumptions can be resolved by augmenting components with appropriate caller and wrapper activities (see Section 5.2.3). In other cases, however, built-in assumptions might limit the flexibility of integrating a component in a given new application. For example, as we have seen in Section 6.4, it is difficult to efficiently reuse an executable program, which operates as a UNIX filter, in an interactive application.

Nevertheless, even with such "impure" components, the separation of activities and dependencies did provide valuable assistance in developing new applications from independently selected components. The overall experience from this separation has been very positive.

The positive experience from separating "core function" from "interconnection" in the "impure" world of today's components provides an indication that even more benefits are to be gained if we develop new programming languages with support for "pure" components. By "pure" components, we mean components with minimal assumptions about their interconnection patterns with the rest of the system. According to the results suggested by this thesis, such "pure" components would have maximum flexibility of reuse in new applications.

Although the form and nature of such components is left to future research, throughout this thesis we have informally defined minimality of interconnection assumptions to include at least the following four properties:

Components interact with their environment through input and output resource ports only.

Every input and output port of a component can be independently managed. That is, every input resource expected by a component can be independently produced and made accessible to the component. Likewise, every output resource can be independently made accessible to its consumers.

Every input port can be connected to an arbitrary number of producers and every output port to an arbitrary number of consumers.

Components make no assumptions about exclusive or shared ownership of resources. If necessary, coordination support for sharing resources should be defined completely outside the component.

The conventional programming language construct that more closely satisfies these properties is a sequential block of code which receives all its inputs and leaves all its outputs to independent local variables. In Chapter 5, we used activity augmentation by callers and wrappers to transform component types with stronger built-in interaction assumptions into approximations of this idealized construct. To facilitate the development of truly reusable software components, future programming languages should offer explicit support for abstractions with such properties.

8.4 Conclusion

Our ability to combine existing pieces of software to produce new applications holds the key to future increases in software productivity. However, after several years of extensive research efforts, systematic construction of large-scale software applications from existing parts remains an elusive goal.

This work has attempted to apply a coordination theory perspective to the representation and design of software systems, in order to explain why software reuse is such a hard problem, as well as to suggest ways for solving it. It has identified the inability of current programming languages to decouple ostensible function from interconnection details in software components. It has been able to come up with a novel way of decomposing software systems as sets of orthogonal subcomponents that separate the main functional pieces of an application from their patterns of interdependency. It has demonstrated that the patterns of interdependency, and the ways of managing them (coordination processes), can be systematized in a design framework of tractable complexity. Finally, it has shown that a practical methodology for developing component-based applications can be based on the representations and frameworks introduced by the thesis.

Much remains to be done, but it is hoped that the initial results of my thesis are a step in the right direction. A better understanding of how software components interconnect to form complex systems will not only allow us to understand how to design components for reusability, but might also enable us to discover new software organizations-organizations in which software and hardware work together in as yet unimagined ways.

Continue on to Appendix