Background on Software Frameworks

Software frameworks are a promising application of object-oriented technology that promote the reuse, extensibility and maintainability of software. They are well-established in the area of system software (graphical user interfaces, editors, operating systems) but have rarely been applied to real-time, mission critical systems like the AOCS. Frameworks differ from other re-use technologies because they make architectural (as opposed to code) re-use possible.

Classes versus Modules

Languages such as Modula-2 and Ada were among the first serious solutions to the problem of software re-use which they addressed with the introduction of the concept of a software module. A module offers an interface to its clients. Clients interact with a module only through its interface. The internal implementation of this interface in the module's body is hidden from them. Modules proved an unsatisfactory solution to the re-use problem because the exist only once, corresponding to an abstract data structure (ADS). In practice, what is needed is an abstract data type (ADT). An ADT is analogous to an ADS but represents a type. Thus any number of variables of a particular type can be declared. Object-oriented languages implement ADT's through the class construct. A class is an instantiable module. It hides design decisions (algorithms and data structures) and offers an interface like a module. In addition it serves as an object factory which allows the instantiation of any number of objects with the structure of the corresponding class.

Besides their failure to support ADT's, modular languages suffered from another serious flaw. In most cases, a module cannot be reused in another project exactly in the same way as it was originally designed: the source code or even its interface have to be changed. This leads to the creation of multiple versions which undermines the very idea of reuse.

In order to overcome this second problem, object-oriented languages introduce language constructs to achieve such delta changes (programming by difference) without having to touch the source code of original modules/classes. Subclasses can be derived (through inheritance) from a parent class. Subclasses can add instance variables, and add, augment or override functions/procedures. This makes flexible reuse possible: inheritance allows module adaptations without having to edit source code or give up compatibility.

Ideally, inheritance suffices to accomplish the few necessary changes for reusing a particular class. As a consequence, many adopters of object technology expect that the usage of an object-oriented language alone yields significant improvements in software reusability. This however leads to a naive application of object technology as discussed below.

Back to Top


Costs of Single Component Reuse

The next  figures (taken from Boehm B. (1994) Megaprogramming. Video tape by University Video Communications , Stanford, California)  summarizes the results of a study regarding the reuse costs of single components in NASA projects. The graph relates the percentage of necessary changes to a single component in order to render it   reusable (x-axis) to the costs of these changes relative to the development of a component from scratch (y-axis).


There are several reasons for the trends shown in the figure. First, reusing single components without any changes does not come for free. One has to locate the appropriate component, understand its interface and determine how to fit it into the system under construction. Furthermore, a(n electronic) catalogue of reusable components and the components themselves have to be maintained. The components have to be built for reuse which is more expensive than for a special purpose.

More worrying is the fact that only a few changes (12%) to a component raise the reuse costs to 55% compared to a from-scratch development of the particular component: not the changes but the required component understanding costs a lot and, without this understanding, changes would obviously be disastrous.

The study corroborates programmers' gut feeling that single-component reuse is almost as expensive as development from scratch. The bottom line is that it does not matter whether languages support adaptations in an elegant way or not. Simply using an object-oriented language instead of a conventional one cannot ensure reusability improvements.

Projects that apply object technology with this naive view are likely to fail. Nevertheless, many software projects still use object-oriented languages in a manner similar to module-oriented languages, with classes as slightly improved modules, resulting in a design that is object-based rather than object-oriented (see an example from from the AOCS Framework Project for an illustration of the difference between the two approaches).

Back to Top


Framework Reuse

Many successful object-oriented projects take a different approach to reuse based on software frameworks. In the most general sense, a framework is a collection of components with predefined cooperation between them. Frameworks are adapted to a particular application domain and capture an architectural design which is optimized for that domain.

Frameworks predefine most of the overall architecture (ie the composition and interaction of its components) of a system but at the same time allow for customization by providing hooks where some of the default behaviours can be overridden. It is this possibility of flexibly reusing architecture - as opposed to simple source code fragments - that makes frameworks so successful as reuse vehicles.

Experienced software engineers who develop several related applications reuse architectures as a matter of course. Software frameworks are intended to formalize and make explicit this form of architectural reuse. They allow the investment that is made into designing the architecture of an application to be made available across projects and across design teams. The framework approach is well suited to situations where several functionally similar applications must be developed.

In principle, a framework constitutes a fully working   application that can be adapted by parameter tuning. In practice, more   flexibility is often required and a well-designed framework presents    replaceable elements and `hooks' (also called hot-spots) where new   elements can be inserted to customize it for a particular application. This   concept is illustrated in the figure where the inner boxes  represent modules and arrows represent method calls. The yellow area represents  the architectural backbone of the application. This remains fixed in one application domain and is provided by the framework. The red blocks are application-specific. They override or otherwise cooperate with framework objects to customize its behaviour. Note the difference with applications built on module/subroutine libraries: in the latter case, the mission specific code typically calls the reused code, in a framework the mission specific code is called by the reused code.

  Fw Plug-In View

The next figure shows a second view of framework  that makes more explicit their function as a basis for the generation of a whole family of applications. A single framework (yellow square in the figure) can generate any application in the framework domain (red squares in the figure). The figure also shows how frameworks and applications exist at two different levels of abstraction. The process whereby a concrete application is derived from the framework is called framework instantiation.

  Fw and Application Levels

Back to Top


Hot-Spots

A framework exists to be adapted. Adaptation takes place during the instantiation process when the framework is transformed from a generic artifact modelling a complete domain into a specific application within that domain. The points where adaptation takes place are called hot-spots (another commong terminology is point of adaptation). Hot-spots can take many forms, depending on the behaviour adaptation mechanism. If, for instance, behaviour adaptation is done by class inheritance, a hot-spot could be a method that is overridden or an abstract method that is defined. In component-based systems, hot-spots are often the points where plug-in components are loaded.

Back to Top


Framework Constructs

What is a framework made of in practice? Or, in other words, what does the framework offer to application developers to help them build an application within the framework domain? There is no consensus on the answer to these questions. In the AOCS Framework project, a framework was defined as consisting of the following constructs: The abstract interfaces are declarations of sets of related operations for which no implementation is provided. Abstract interfaces capture behavioural signatures that are common to all applications in the framework domain. In a language like C++, they are implemented by pure virtual classes.

The domain-specific design patterns are optimized solutions to recurring architectural problems in the framework domain. Since they encapsulate reusable architectural solutions, and since frameworks are intended as vehicles for architectural reuse, design patterns are normally the heart of a framework. Additionally, design patterns promote architectural uniformity by ensuring that similar problems in different parts of the same application receive similar solutions. This endows the application architecture with a single "look & feel" that makes using and expanding it considerably easier. Design uniformity is an important aspect of architectural reusability and a second important contribution of design patterns to frameworks.

The concrete components are binary units of reuse that implement one or more interfaces and that can be configured for use in a specific application at run-time. Framework components can be of two types:  core components and default components. Core components encapsulate behaviours that are common to all applications in the framework domain. They are therefore used by all applications instantiated from the framework. Default components represent default implementations for some of the abstract interfaces in the framework. They encapsulate behaviours that are found in many applications in the framework domain but that are not intrinsic to the framework domain.

Back to Top


Behaviour Adaptation in Frameworks

Frameworks are targeted to a specific application domain but within that domain they are generic. They must therefore offer behaviour adaptation mechanisms through which their behaviour can be tuned to fit the needs of specific applications within their target domain.

Two basic behaviour adaptation mechanisms are used in object-oriented frameworks: inheritance and object composition. The former mechanism is used for static behaviour adaptation, the latter for dynamic behaviour adaptation. An important property of these adaptation mechanisms is that they allow the behaviour of a target class to be adapted without touching its source code. This is an essential characteristic because it allows the behaviour of the target class to be adapted without invalidating its qualification status.

The figure below illustrates the mechanism of behaviour adaptation through inheritance. In the example in the figure, the derived class extends the interface of its parent class by adding one extra operation to it (operation_4) and it modifies one of its existing operations (operation_2) by overriding its original implementation and providing a new one. Adaptation by inheritance implements the so-called principle of programming by difference: if a given class needs to be modified in response to a change in its requirements, this can be done by subclassing it and building the difference between the original implementation and the new implementation into the derived class. Thus, in the example of the figure, the base class is adapted by adding a new method to it and by changing the implementation of one of its operations. The implementation of its other methods is left unchanged and is reused. Note how adaptation by inheritance does not require touching the code of the class to be adapted (the base class in the figure). Thus, a qualification process performed on the original class remains valid and the investment that was made into qualifying the base class is not lost. Only the (usually small) delta-implementation in the derived class needs to be qualified.

Adaptation through Inheritance

The next figure instead illustrates adaptation through object composition. The adaptable class delegates some of its behaviour to an external helper object (see pseudo-code of method T). Adaptation is achieved by loading a specific helper object into the adaptable class at run time. For this purpose, the adaptable class provides a loadHelper method. The behaviour of the adaptable class can be tuned by loading a new version of the helper object. As in the inheritance case, adaptation is achieved without touching the source code of the adaptable class and hence without invalidating its qualification. Adaptation through object composition is usually preferred to adaptation through inheritance because it creates a sharper demarcation between the adaptable class and the adapting class.

Object Composition

The object composition mechanism shown in the previous figure suffers from one serious drawback: it creates a coupling between two concrete classes (both AdaptableClass and Helper are concrete classes). In a framework perspective, and more generally in an adaptation perspective, this should be avoided because it makes independent use of the two classes very difficult. For this reason, object composition is usually implemented through dynamic coupling. The dynamic coupling mechanism is illustrated in the next figure. The adaptable class is still delegating part of its functionality to an external helper object. The helper object however is now represented by an abstract interface. Adaptation is achieved by switching between different concrete classes that implement this abstract interface. The abstract interface improves the decoupling between the adaptable class and the class that is responsible for the adaptation. It now becomes possible to have different implementations of the helper class that are embodied in different concrete classes and which are all compatible with the adaptable class. As in previous cases, adaptation is achieved without touching the source code of the adaptable class and hence without invalidating its qualification process.

Dynamic Coupling

Back to Top


Frameworks and Components

Object composition is a primary behaviour adaptation mechanism for frameworks. Normally, the plug-in objects need to be developed in the same language (in many cases, it is even necessary to use the same compiler version or development system) as the overall framework. Building the framework on a component infrastructure (eg. DCOM or CORBA) solves this wiring problem. Component technology additionally makes it possible to distribute the framework elements across process and processor boundaries.

The combination of framework and component technology has the potential of bringing the development of software applications in line with the development of hardware systems. In the long run, a commercial market for software components might emerge similar in character to the market for hardware components. Software applications will then come to be built as their hardware counterparts are built: by assembling commercially available components with standardized interfaces. For each application domain, one or more frameworks will provide the architectural backbone and individual applications will be realized by plugging behaviour-tuning components into a selected framework.

Back to Top


Autocoding

A framework represents an application in fieri. It offers constructs and a skeleton structure from which an application can be quickly derived. The process of building a concrete application from a framework is called instantiation. Much of the instantiation process consists of plugging together pre-defined components offered by the framework and tuning their parameters. Which components are plugged together and how their parameters are tuned depends on the particular configuration required for the application at hand. This process can in principle be automatized either through the use of wizards that take the user through the configuration process, or through the use of a tool that lets the user specify the configuration in a suitable manner (probably through a graphical user interface) and which then automatically generates the application code.

Back to Top


Empowering Application Specialists

One of the reasons for the poor reliability of so much software probably lies in the separation between the software engineering and the application engineering roles. The normal procedure on projects where an application is being designed that relies on software for its correct functioning is for the application experts to write the user requirements for their system but to delegate the software development to a separate team of software engineers who are usually not specialists in the application domain.

This results in a situation where the heart of the application - its software - is designed, developed and tested by persons who are not application specialists. This approach is regarded as flawed because the interface between the software engineers and their application colleagues lengthens development times and introduces a potential for errors through the misunderstanding or misspecification of the software requirements of the application under development.

A software framework is always targeted at a specific application domain. By providing a set of abstractions that are tailored to this domain, the framework makes it possible for application experts to directly construct their software with only minimal support from software specialists and without the need to write extensive source code. The framework approach thus simplifies the development of applications within a certain domain and in so doing it narrows the gap between the software and the application specialists and reduces the scope for errors at their interface.

Back to Top


Some Useful References

Useful references on software frameworks are:

An excellent overview of software components and related concepts can be found in:

Frameworks rely heavily on design patterns. The classic introduction to design patterns is:

Back to Top


Last updated on Feb. 5-th 2002 by Alessandro Pasetti