Software Component Relationships

Stephen H. Edwards

Department of Computer Science
Virginia Polytechnic Institute and State University
660 McBryde Hall
Blacksburg, VA 24061-0106
Tel: (540)-231-7537
Email: edwards@cs.vt.edu


David S. Gibson, Bruce W. Weide, and Sergey Zhupanov

Department of Computer and Information Science
The Ohio State University
2015 Neil Avenue
Columbus, OH 43210
Tel: (614) 292-5813
Email: dgibson@cis.ohio-state.edu
weide@cis.ohio-state.edu
sergey@cis.ohio-state.edu

Abstract:

Large complex software systems are composed of many software components. Construction and maintenance of component-based systems require a clear understanding of the dependencies between these components. To support reuse, components should be designed to minimize such dependencies. When component coupling is necessary, however, dependencies need to be expressed clearly and precisely. Most software analysis and design methodologies rely on relationships such as passes-data-to, calls, is-a-part-of, and inherits-from for this purpose. Our position is that component relationships such as these are not an effective way to convey important dependency information to implementors and maintainers working with reusable software components. Precisely-defined conceptual relationships are better suited to this task.

Keywords: Software components, component relationships, software engineering, software reuse, behavioral substitutability

Workshop Goals: Learning, feedback, networking

Working Groups: (1) Rigorous Behavioral Specification as an Aid to Reuse, (2) Component Certification Tools, Frameworks and Processes, and (3) Object Technology, Architectures, and Domain Analysis: What's the Connection? Is There a Connection?

Background

As members of the Reusable Software Research Group (RSRG) at The Ohio State University, we have been exploring various aspects of software component engineering for over ten years. One recent focus of our research has been on the identification, formalization, and expression of dependency relationships between software components. Many of our ideas on software component relationships are based on the results of RSRG research which has been incorporated into the RESOLVE framework, language, and discipline for software component engineering [1]. Newer ideas and terminology for expressing these relationships are based on a formal model of software subsystems called ACTI, for ``Abstract and Concrete Templates and Instances[2].

To demonstrate the application of our ideas on software component relationships, we have developed the RESOLVE/C++ and RESOLVE/Ada95 disciplines for software component engineering. Steve Edwards, Bruce Weide, and Sergey Zhupanov developed the RESOLVE/C++ discipline. David Gibson developed the RESOLVE/Ada95 discipline. These disciplines use the language mechanisms of C++ and Ada (as revised in 1995) to encode language-independent software component relationships. Bruce Weide is currently using the RESOLVE/C++ discipline in the introductory Computer Science course sequence at Ohio State.

Position

Building software systems from reusable software components has long been a goal of software engineers. While other engineering disciplines successfully apply the reusable component approach to build physical systems, it has proven more difficult to apply in software engineering. A primary reason for this difficulty is that distinct software components tend to be more tightly coupled with each other than most physical components. Furthermore, components are often designed with extremely subtle dependencies on other components are which are not explicitly described. These dependencies may significantly complicate reasoning about program behavior[3].

Clearly some dependencies between software components are necessary and desirable. These dependencies need to be clearly expressed by component designers and well-understood by implementors and maintainers. The role of software component relationships is to express dependencies between components and, in doing so, to provide information about how components may and should be used in conjunction with other components. Our position is that the software component relationships used by most analysis and design methodologies are not well-suited for building and maintaining large complex systems and that there are more suitable alternatives.

Commonly used component relationships suffer from one or more of the following problems:

Traditional techniques based on functional decomposition of systems have software ``part'' relationships depicted in notations such as data flow diagrams and structure charts. Relationships such as passes-data-to, calls, and is-a-part-of are common to these notations. These relationships may be useful for understanding how components of a particular system are related. However, they do not directly address how one might reuse individual components to build a new system or modify an existing system. That is, these notations do not describe the dependencies of a component independent of a particular use of that component.

Object-oriented analysis, design, and programming methodologies usually rely heavily on the inherits-from component (class) relationship. Unlike those described above, this relationship can describe component dependencies independent of a specific component (class instance) usage. However, inherits-from typically fails to convey precise useful information about component dependencies. Even if the vague and varied meanings of inherits-from play a useful role during analysis and design, this relationship is much less useful when working with specific components during implementation and maintenance. Inheritance is a programming language mechanism that can be used to encode conceptual relationships between software components. Inheritance is not itself a conceptual relationship.

Some people in the object-oriented community argue that inheritance should only be used to express the is-a relationship between two components. Unlike inherits-from, is-a is a conceptual relationship between components. However, the is-a relationship does not have a single precisely-defined meaning. Furthermore, even when formally defined in terms of behavioral substitutability, the is-a relationship generally does not convey specific design intent. For example, stating that component X is-a Y does not suggest any information about why X was designed to be substitutable for Y and thus how X might be used.

To address the problems described above, component relationships should:

We have defined a small set of language-independent component relationships which satisfy these three criteria. Our relationships describe the dependencies between components at a conceptual level. The relationships provide implementers and maintainers precise information about how components may and should be used. Furthermore, they may be used to express specific design intent. In the remainder of this section, we briefly introduce the component relationships: implements, uses, and extends. While we have defined several other useful component relationships, these are the most general and easiest to understand.

The software component relationships we have defined relate components which may either be abstract (specifications) or concrete (implementations)gif. An abstract component describes functional behavior--what services a subsystem provides. A concrete component describes an implementation--how a subsystem's services are provided. Having separate abstract and concrete components supports data abstraction, information hiding, multiple implementations, and self-contained descriptions of component behavior.

The most fundamental component relationship upon which all others rely for meaning and utility is implements. Implements describes the key relationship between an implementation, a concrete component, and a specification, an abstract component. The implements relationship may be defined informally as follows:

Concrete component X implements abstract component Y if and only if X exhibits the behavior specified by Y.

This is a fairly intuitive relationship between a specification and an implementation. However, a fully formal and general definition of the implements relationship is very intricate and has been the subject of much research. Implements expresses a dependency between two components in the following sense. If component X implements component Y, then X depends on Y to provide an abstract, client-level description of its behavior - a ``cover story'' hiding all implementation details.

While justifying a claim that X implements Y may require significant effort, especially if done formally, considerable leverage is gained from doing so. If two different concrete components both implement the same abstract component, then either of them may be used in a context requiring the functional behavior described by the abstract component. In this case, the two implementations are behaviorally substitutable with respect to the specification they both implement. The two implementations may differ in non-functional characteristics such as execution time, space requirements, cost, warranty, legal use restrictions, level of trust in correctness, and so forth.

The implements relationship describes a dependency between an implementation and a specification. The uses relationship may describe a dependency that exists between two different abstractions. The relation name uses actually applies to three different yet closely related component relationships. Uses may describe a dependency between two implementations, between two specifications, or between an implementation and an specification. The last of these three relationships is defined as follows:

Concrete component X uses abstract component Y if and only if X depends on the behavior specified by Y.

This form of the uses relationship expresses a polymorphic relationship between implementations. Any component that implements abstract component Y may serve as the actual concrete component used by instances of component X. Thus, this form of uses reduces unnecessary dependencies between components. Note that none of the three uses relationships is equivalent to the is-a-part-of relationship. If implementation X uses implementation Y, Y may or may not be a part of the data representation of X. The client wishing to use component X does not need to know Y's specific role in X, just that component Y is required in order to use component X.

A third component relationship is extends. The name extends applies to two different, yet closely related, component relationships. One extends expresses a dependency between two abstract components. The other expresses a dependency between two concrete components. Both extends relationships may be defined informally as follows:

Component X extends component Y if and only if all of the interface and behavior described by Y is included in the interface and behavior described by X.

This definition conveys the intuitive meaning of extends, that is, component X extends the interface and behavior of component Y. It implies the essential property of behavioral substitutability. If abstract component X extends abstract component Y, concrete component X1 implements X, and concrete component Y1 implements Y, then X1 is behaviorally substitutable for Y1 with respect to Y. Note that Y1 is not behaviorally substitutable for X1 with respect to X in this case. Thus behavioral substitutability is a ternary relationship, not a binary equivalence relation.

To some readers, the extends relationship may sound very much like an inheritance relationship. It is important to understand that extends is not an inheritance relationship. Extends describes a behavioral relationship between two components. Inherits-from does not. Furthermore, while inheritance may be a convenient programming language mechanism for expressing structural aspects of the extends relationship, extends may be encoded in programming languages without any use of inheritance.

Comparison

Perhaps the most widely known work which includes definitions of software component relationships is that by Grady Booch, Ivar Jacobson, and James Rumbaugh on the Unified Modeling Language (UML). The UML includes software component relationships in the form of class relationships defined in Booch's method for object-oriented analysis and design [4]. Booch identifies three basic kinds of class relationships: those expressing is-a relationships, those expressing is-a-part-of relationships, and association relationships which denote some semantic dependency between otherwise unrelated classes. The specific class relationships used by Booch include association, inheritance, aggregation, and using. The meanings of these relationships are largely influenced by available programming language mechanisms (in particular, those of C++).

Booch's association relationship is primarily useful for design and analysis of a particular application or composition of components. It does not convey information about what compositions are possible for a reusable component. Booch's use of the inheritance relationship is limited to expressing is-a relationships. However, his definition of is-a is not strict enough to imply behavioral substitutability with respect to some specification (as does implements). Thus the component relationships expressed as class relationships in the UML appear to suffer from all of the problems described in the last section.

Some object-oriented programming advocates such as Bertrand Meyer do not insist that inheritance only be used to express the conceptual is-a relationship. Meyer has described twelve different component relationships that may be expressed using inheritance, only one of which expresses the is-a relationship [5]. As with the UML's use of inheritance, Meyer's is-a use of inheritance is not defined precisely enough to imply behavioral substitutability.

Some researchers have studied precisely defined class relationships which do imply behavioral substitutability of components [6, 7]. This research largely focuses on how the inheritance language mechanism can and should be used in a manner that supports reasoning about program behavior. Unlike our research, this work does not address conceptual component relationships from a language-independent perspective.

References

1
M. Sitaraman and B. W. Weide, editors, ``Special feature: Component-based software using RESOLVE,'' ACM SIGSOFT Software Engineering Notes, vol. 19, no. 4, pp. 21-67, 1994.

2
S. H. Edwards, A Formal Model of Software Subsystems. PhD thesis, The Department of Computer and Information Science, The Ohio State University, Columbus, Ohio, 1995.

3
B. W. Weide and J. E. Hollingsworth, ``Scalability of reuse technology to larege systems requires local certifiability,'' in Proceedings of the Fifth Annual Workshop on Software Reuse (L. Latour, ed.), Oct. 1992.

4
G. Booch, Object-Oriented Analysis and Design With Applications. Menlo Park, CA: Benjamin/Cummings, 2nd ed., 1994.

5
B. Meyer, ``The many faces of inheritance: A taxonomy of taxonomy,'' IEEE Computer, vol. 29, pp. 105-108, May 1996.

6
B. H. Liskov and J. M. Wing, ``A behavioral notion of subtyping,'' ACM Transactions on Programming Languages and Systems, vol. 16, pp. 1811-1841, Nov. 1994.

7
K. K. Dhara and G. T. Leavens, ``Forcing behavioral subtyping through specification inheritance,'' in Proceedings of the 18th International Conference on Software Engineering, pp. 258-267, IEEE Computer Society Press, Mar. 1996.

Biography

Stephen Edwards is a Visiting Assistant Professor in the Department of Computer Science at the Virginia Polytechnic Institute and State University. He received a B.S. in Electrical Engineering at the California Institute of Technology in 1988 and his M.S. and Ph.D in Computer and Information Science at The Ohio State University in 1992 and 1995, respectively.

David Gibson is a Major in the United States Air Force and a Ph.D. candidate in the Department of Computer and Information Science at The Ohio State University. He received a B.S. in Physics and Computer Science from Duke University in 1983 and his M.S. in Computer and Information Sciences from Trinity University in San Antonio in 1986.

Bruce Weide is a Professor of Computer and Information Science at The Ohio State University. He received a B.S. in Electrical Engineering from the University of Toledo in 1974 and a Ph.D. in Computer Science from Carnegie-Mellon University in 1978. He is a co-founder of the Reusable Software Research Group at The Ohio State University.

Sergey Zhupanov is a Research Associate in the Department of Computer and Information Science at The Ohio State University. He received his B.S. and M.S in Computer and Information Science at The Ohio State University in 1994 and 1996, respectively.

We gratefully acknowledge financial support from the National Science Foundation (grant number CCR-9311702, DUE-9555062, and CDA-9634425), the Advanced Research Projects Agency (contract number F30602-93-C-0243, monitored by the USAF Materiel Command, Rome Laboratories, ARPA order number A714), and the Fund for the Improvement of Post-Secondary Education under project number P116B60717. Any opinions, findings, and conclusions or recommendations expressed in this paper are those of the authors and do not necessarily reflect the views of the National Science Foundation, the Defense Advanced Research Projects Agency, or the U.S. Department of Education.

...(implementations)
In addition to the abstract versus concrete dimension, components are either templates or instances. These two orthogonal dimensions give rise to four kinds of components: abstract templates, abstract instances, concrete templates, and concrete instances. While the relationships introduced in this paper only deal with the abstract versus concrete dimension, we have identified template-specific relationships.