Workshop on the Methodologies and Object-Oriented Programming OOPSLA '88, San Diego, CA Monday, 26 September 1988 Norman L. Kerth, organizer Department of Computer Science University of Illinois at Urbana-Champaign 1304 West Springfield Ave. Urbana IL 61801 (217) 328-3523 firstname.lastname@example.org
The three characteristics that distinguish object-oriented approaches from conventional ones are polymorphism, inheritance, and encapsulation (PIE). While polymorphism and inheritance are useful during a system's initial design, their real value becomes evident as the system evolves. Polymorphism makes it more likely that a goven component will operate correctly in a variety of different contexts. Inheritance allows common behaviors to be shared among a family of objects, that permits programming-by-difference.
Object-oriented tools and techniques promote the emergence of application specific frameworks. A framework is a collection of cooperating classes that together define a generic or template solution to a family of domain specific requirments. The best known frameworks, such as MVC and MacApp, define generic user interfaces. However, frameworks are by no means limited to user interface construction. For instance, the Battery Simulation [Foote 1988] defines a framework for constructing realtime data acquisition and experimental control applications. As object-oriented techniques are applied in other application domains, frameworks for these domains can be expected to appear as well.
Frameworks are often characterized by an inversion of control in which the framework plays the role of a main program in coordinating and sequencing application activity. The user of a framework will supply methods that override specific framework behaviors to tailor it for a specific application. Frameworks can hence serve as dynamically extensible skeletons.
Frameworks are unlike skeletons, though, in that their cores are dynamically shared among all applications derived from them. This allows a framework to serve as the nucleus of a family of related applications as evolving requirements cause its members to diverge.
A framework's application specific behavior is usually defined by adding methods to subclasses of one or more of its classes. Each method must abide by the internal conventions of its superclasses. We call these white-box frameworks because the internal implementation details of the framework are visible to the application specific methods, and must be understood if the framework is to be sucessfully used [Foote & Johnson 1988].
The relationships among the elements of a white-box framework tend to be rather informal. As a framework evolves, the relationships among its elements tend to become better defined. Portions of the framework emerge as distinct components. Communication among components is then performed in conformity with the component's external protocol. The white-box elements become black-box components. We call such frameworks black-box frameworks. A black-box framework is easier to reuse than a white-box framework, since only the external protocol of the framework components need be understood, and since any component conforming to that protocol may be substituted for any other.
White-box frameworks can play an important role during the early, exploratory phases of a system's evolution. They encapsulate an informally organized part of a system while its structure is still the subject of experimentation. As the system and problem domain become better understood, distinct black-box components begin to emerge.
Designing and implementing a system that meets its specifications is a challenging task in itself. Adding to this the requirement that the components of such a system anticipate and accomodate future requirements is a much more daunting task. Designing a system from a fixed specification is a deductive process, whereas designing reusable classes and frameworks is an inductive one. Most often, a designer will know how to produce a general solution to a problem only after having seen several related specific solutions to it. A prototyping pass may on occasion provide such experience, but it will more typically acrue during the perfective maintenance phase of a product's lifecycle, or during the implementation of successive members of a family of related products.
As a result, design can be seen as a process that pervades an object-oriented product's lifecycle. Indeed, some of the most valuable design effort, that involving the identification, generalization, and refinement of framework components, will take place during the maintenance phase of the project. An interesting implication of this observation is that existing programmer deployment practices that place the most skilled designers on new projects and delegate maintenance to fledgling programmers may be less than optimal.
Designing reusable classes and frameworks is a difficult task that requires experience, judgement, and skill. Even the best designers will seldom be able to divine optimal abstractions on a first attempt. Only experience within a given application domain can lead to the insights needed to produce general components for it. An organization willing to invest the long-term resources and effort in designing reusable classes and frameworks will reap considerable rewards.
[Foote 1998] Brian Foote Designing to Facilitate Change with Object-Oriented Frameworks Masters Thesis, 1988 University of Illinois at Urbana-Champaign [Johnson & Foote 1988] Ralph E. Johnson and Brian Foote Designing Reusable Classes Journal of Object-Oriented Programming Volume 1, Number 2, June/July 1988 pages 22-35