Previous Section  < Free Open Study >  Next Section

5.20 Reusing Components Versus Reusing Frameworks

Heuristic 5.19

When building an inheritance hierarchy, try to construct reusable frameworks rather than reusable components.

This heuristic illustrates the difference between system and domain analysis. System analysis attempts to find key abstractions from the particular application you are developing. The result is system-specific classes, which we call components. It is a designer's hope that they will become reusable in other applications. Domain analysis is the process of taking a step back and asking ourselves, "Can we create one design that satisfies the needs of a whole family of applications, of which our system is one member?" If the answer is yes, then the result is often reusable frameworks. In this context, a framework is defined as a class that contains a base class(es) by reference. Consider the design that wishes to place an object-oriented wrapper around the operating system in order to make the transition between hardware platforms easier. Someone performed system analysis and decided which operations an operating system needed in order to satisfy the given application. These became pure polymorphic functions on a base class called OperatingSystem (see Figure 5.54). The derived classes DOS, Unix, and VMS must define each of these methods in order to be useful in the application.

Figure 5.54. An operating system wrapper.


Given this hierarchy, it is possible to port our application to OS/2 by creating a new derived class, OS/2, and implementing the necessary methods in this new operating system. While this is useful, domain analysis would have asked the question, "Can we take the reusable components DOS, VMS, Unix, and now OS/2, and find a reusable framework that models them more fully?" We can generalize these derived classes by realizing that all operating systems consist of a file system, a process system, and a device driver system (see Figure 5.55). Of course, there are different types of file systems, process systems, and device driver systems, each of which requires its own methods. However, we have now captured part of the design of an operating system. With luck we can continue to break down each piece into its generic pieces. Even though we never get any reusable code, we can get a reusable design. Reusable designs are often considered much more useful than reusable code. Do you want to be in a situation where you are told to create an OS/2 class with its 50,000 lines of code? Or would you prefer to be in a situation where you are told to create an OS/2 class with its 50,000 lines of code but it requires the following three pieces, each of which has the following pieces and interfaces, etc.? After creating several object-oriented systems, most developers agree that the production of a good design requires a great amount of effort for each system. Any reduction of that effort is very valuable and can save much more time than a simple reduction in code.

Figure 5.55. A framework for operating systems.


It is important to note that the OperatingSystem class shown in Figure 5.55 allows for an OperatingSystem object to be created from a UnixFS, a DOS_process, and a VMS_devicedriver. This is obviously an unworkable OperatingSystem object. This implies that there exists a semantic constraint between the objects contained in the OperatingSystem class. These semantic constraints are best captured in the class definition when possible. For this reason, many designers will bring back the derived classes DOS, Unix, and VMS for the sole purpose of maintaining the semantic constraints of operating systems. These derived classes usually capture the semantic constraint in their constructors, which build and pass the appropriate pieces of the framework to constructors higher in the hierarchy (see Figure 5.56).

Figure 5.56. A framework for operating systems.


Many case studies demonstrate the benefits of reusable frameworks. In a process control project on which I worked at Draper Laboratories in the mid 1980s, our requirements were to development a system to fold men's suit sleeves with a robot. Instead, our development team took a step back and asked, "What do all process control systems (of which we are aware) require for design and implementation?" We designed a framework for process control architectures based on our answers to that central question. It was on this framework that we built our first representative application, namely, the robotic sleeve-folding system. As it turned out, the textile industry did not prove to be a steady source of funding for automation research and development. However, companies involved with composites manufacturing were in great need of automation. Our framework was used to create a new application, which wrapped kevlar around steel frames to simulate the manufacturing of airplane wings. The new system took less than two days to develop on top of the existing framework. It would have taken considerably longer to build a new system from the beginning, even if some of the existing code was reusable.

In another case study, I taught an object-oriented analysis and design course to a group of employees from The Travelers' Insurance Company. In this course, one-third of the attendees were working on a workmen's compensation insurance claim system, another third on a health insurance claim system, and the last third on an automobile insurance claim system. I argued that this was the perfect class to discuss domain analysis and framework design since clearly they were building three related systems. Several members of the class argued that these related segments of the insurance industry were completely different upon closer inspection. However, after several hours, we were able to produce a considerable collection of abstractions that were common to all three domains. A dissenting member of the class agreed that there were many abstractions in common but stated that upon implementation they differed significantly. She argued that it was not worth the time to create the abstractions if their eventual implementations were going to differ. While there may not be any code in common among the three designs, the fact that the designs overlap is very valuable information. Would you like to build a new system of 500,000 lines of code with nothing but its requirements to guide you? Or would you like to write 500,000 lines of code but know exactly how it is decomposed at the design level? After building systems, any developer will argue that the latter task is much easier than the former.

A third and last case study comes from Salomon Brothers. This company needed to build a collection of applications that dealt with reporting systems for securities trading. Instead of spending two team years building each of a number of systems, an enterprising executive allowed his group the extra time to construct a framework to support all of the applications. The result was that the first application took longer than the expected time, due to the need for framework design and construction. The remaining applications took a small fraction of the expected time, due to a high level of reuse achieved from the framework designed by the first group. This resulted in a substantial net savings in development time and effort as well as increased maintainability of the system. The latter is a result of the large amount of design and code sharing between the applications.

It is important to note that the development and use of a framework requires a front-end investment in time and money. The reward comes in reduced maintenance costs for the systems already developed and in reduced development costs for future systems. This type of cost structure must be supported by the top levels of management for the organization attempting the development of the framework. Unfortunately, there are surprisingly few companies willing to spend the extra time/money today to save significant amounts of both in the future.

    Previous Section  < Free Open Study >  Next Section