problems, causes, solutions - Semantic Scholar

3 downloads 259475 Views 105KB Size Report
that application development is often based on mul- .... For example, while developing a new system based ..... ACM Press, New York, 1990, pp. 181–193. 2.
Michael Mattsson, Jan Bosch, and Mohamed E. Fayad

FRAMEWORK INTEGRATION P ,C , ROBLEMS AUSES SOLUTIONS

Though familiar with the most common problems and their causes, OO software developers struggle with solutions plagued by a lack of framework standards and development guidelines.

T

raditional framework-based application development assumes applications are based on single frameworks extended with application-specific code. More recently, it’s become clear that application development is often based on multiple frameworks that have to be integrated with one another, as well as with class libraries and with existing legacy components, to fulfill application requirements. But this integration process can lead to serious integration problems, since a framework is generally designed under the assumption that it is fully in control of the event loop. And a framework is always designed for extension (not for integration) and without the need for incorporating legacy components. Here, we focus on the integration of multiple frameworks at the code level, avoiding questions about integrating documentation. Our extensive experience with object-oriented application frameworks includes the following frameworks: measurement, process control, dialysis, fire-

alarm, intruder alarm, passage control, and adaptive OO filtering for event management. The development examples we cite involve the integration of these frameworks with one another and with other frameworks, such as graphical user interfaces (GUIs). In light of our experience [2–5], we have now identified six common problems that application and framework developers encounter when integrating two or more frameworks. Four of them—inversion of control, integration with legacy systems and existing tools, the framework gap, and architectural mismatches—are related to architectural design; the other two—overlapping framework components and integrating functionality from different frameworks—are related to detailed design and can result from any of the problems at the architectural design level. All these problems stem from a set of five common causes: cohesive behavior, domain coverage, design intention, lack of access to source code, and lack of standards for the framework. We also offer a number of approaches that can, at least partly, overcome these problems. COMMUNICATIONS OF THE ACM October 1999/Vol. 42, No. 10

81

Integration with legacy systems and existing tools. We call this problem the “capitalization principle,” or “don’t throw anything away, using and reusing as much as you can” [2]. Application Code Because the framework class contains only the functionality captured by the framework, not the domain-specific behavior required for the Controls current application being developed, applicaand Invokes tion and framework developers may want to Measurement use existing tools and legacy components as System classes in the application. However, for appliGUI Framework Framework cation and framework developers, it is neither trivial nor straightforward to integrate the existing tools and legacy components as classes Inversion of control. A distinguishing feature of in the application; frameworks often rely on the subframeworks is their ability to extensively use dynamic classing mechanism. Typing conflicts are a common binding. As a result, the framework code has a single problem, because the existing tools and legacy classes thread of control and calls the application code as cannot be subclasses of the framework class [3]. needed. This single-thread-of-control phenomenon For example, while developing a new system based is sometimes called the “Hollywood principle,” or on the measurement system framework, the develop“don’t call us, we’ll call you” and “flip-flop of control.” The inversion of control occurs Figure 2. Called framework extended to when two or more frameworks call the applifill the framework gap. cation code simultaneously, each assuming ownership of the application’s main event Framework loop. The complexity of this problem Interface increases along with the increasing number of frameworks that have to be integrated in the application. For example, consider the composition of a Additional measurement system framework [1, 5] and a Called Framework Functionality GUI framework. From the moment a trigger enters the system, the measurement system Extended Called Framework framework has a well-defined control loop that has to be performed in real time, in turn creating a measurement item, reading sensors, computing measurements, activating actuators, and storing ers’ intention was to reuse legacy sensor and actuator related historical data. The GUI framework has a simi- classes developed for an earlier version of the system. lar thread of control, though not in real time, that Although the legacy classes contained the required updates the screen whenever a system value changes, domain functionality, integration with the framework such as when a sensor value is read or the system per- proved very difficult for two reasons: The interface forms an action invoked by a user’s command. These required by the framework was different from the two control loops (see Figure 1) can collide with one interface provided by legacy classes; and the frameanother, potentially causing the measurement segment work required the legacy classes to exhibit certain to miss its real-time deadlines and the GUI to present domain-independent behavior for interacting with incorrect data due to out-of-sync conditions between other framework components. the activities. The control loop in the framework is genFramework gap. This problem occurs when inteerally not represented as a single entity but distributed grating two or more frameworks to fulfill an applicaover the framework code. Changes to the control loop tion’s requirements, where the resulting software require application and framework developers who structure does not cover the application’s needs. This want to change the control loop to have considerable problem is generally called the “framework gap” [3, understanding of the framework’s internal structures, 12]. If the framework is called, or told to perform a because these changes affect several parts of the frame- particular task, the problem may be solved with an work. added framework interface that includes both the Figure 1. Inversion of control problem.

82

October 1999/Vol. 42, No. 10 COMMUNICATIONS OF THE ACM

existing and the additional functionality—an approach called “wrapping” (see Figure 2). When a calling framework lacks functionality, mediating software is needed to manage the problem. Such mediating software is often difficult to develop, however, because framework A has to be informed by framework B about what happened in framework B in terms framework A can understand. The mediating software may also need to cut out parts of the functions offered by the framework and replace them with application-specific code that composes the functionality from framework A and framework B, along with the functionality needed to fill the framework gap. However, for the mediating software, such solutions also create dependence on the current framework versions, possibly leading to complex maintenance problems for the application, especially when new versions of the frameworks replace the old versions. Overlapping of framework components. This problem occurs when two or more integrated frameworks have the same real-world components but with different representations. We call it the “overlapping principle” [2]. When integrating two or more frameworks, these different representations have to be integrated, since they represent the same real-world component. Integration can be achieved through the use of multiple inheritance, given that the represented properties are mutually exclusive and do not affect one another. However, the two represented properties often involve shared or dependent properties, causing the composition of the representations to be more complex [3, 11]. For example, a fire-alarm framework and an intruder alarm framework may both use the same sensor type for detecting heat. But these frameworks use different representations of the sensor and require different behavior from the sensor. When integrating the frameworks in a monitoring system, the sensor representations need to be merged, so both frameworks can use the same physical entity, thereby reducing the system’s overall cost. Since the sensor behavior required by the frameworks is not orthogonal, multiple inheritance is often insufficient, possibly requiring manual integration of the sensor representations. Integrating functionality from different frameworks. Called the “composition principle,” this problem occurs when a real-world component has to be modeled by integrating parts of the functionality from different frameworks. A typical example is a layered software structure in which a user-interface layer is at the top, an application-domain-specific layer is in the middle, and a persistence layer is at the bottom, each layer represented by a framework. The real-world entity is typically represented in the applicationdomain-specific framework, but some of its perfor-

mance and architectural characteristics have to be displayed graphically in the user-interface layer, and the entity has to be made persistent for some transactions. Just integrating the respective classes from the three frameworks through aggregation or multiple inheritance does not yield the desired behavior. For example, changes of the state caused by messages to the application-domain-specific part of the resulting object do not automatically affect the object’s user interface or persistence functionality. Consequently, software engineers have to extend the applicationdomain class with behavior for notifying the userinterface and database classes, possibly by using the Observer design pattern [3, 6]. Application and framework developers could argue that the application domain class should have been extended with such behavior during the framework’s design. But, as mentioned earlier, most frameworks are not designed to be integrated with other frameworks, but to be extended with application-specific code written specifically for the application at hand. The authors experienced this problem in the firealarm framework [5] in which several entities had to be persistent and stored in nonvolatile memory, or an EEPROM. To deal with the lack of extensions, each entity was implemented with two objects—an application object and a persistence object—both tightly coupled and with frequent interactions, because they both represented parts of a single common entity. Architectural mismatches. This problem occurs when two or more integrated frameworks with different architectural styles fail to interoperate. This failure results when many framework components are in multiple forms to ensure their usability in various contexts. We call this problem the “impedance principle” [2]. Different models of integrated framework components and different interactions between framework components using different OO techniques may prohibit successful integration. The term “pragmatics” is sometimes used to refer to these and related issues. Consider the following example of the integration of a measurement system framework and a dialysis system framework. Assume that the measurement framework is organized according to OO principles, so the measured entities are represented as objects. The dialysis system, on the other hand, is modeled using the pipes-and-filters architectural style, that is, sensors pipe data to an analyzer that subsequently pipes commands to actuators. Even though the integration of these two systems makes sense from an application-domain perspective, the integration fails because of the architectural mismatch between the frameworks. COMMUNICATIONS OF THE ACM October 1999/Vol. 42, No. 10

83

the application is to benefit from the improvements in later framework versions. Design intention. Framework developers should explicitly define the design intentions of a framework to make it easier for application developers to determine how “integratable” the framework is for a particular application. The developer should make clear whether the framework can be reused by extension only and whether provisions for integration are available. It should also be made clear whether the framework is intended for two-way communication or one-way communication. Since the design intention for most existing frameworks (generally implicit) is Figure 3. Relationships between reuse by way of extension and integration problems and causes. one-way communication from the framework to the newly writPrimary Causes ten application-specific code, this design intention can cause Design Domain Framework Lack of Intention Coverage Cohesion Standard the framework integration problems we have experienced. Access to source code. Access to the source code is important, since framework integration can Architectural Overlap of Framework Legacy Inversion Integrating require editing the framework Mismatches Gap Systems of Control Functionality Components code to add the behavior needed and Existing Tools for other frameworks. If the source code is not available, wrappers provide the only way to achieve the behavior required from the framework. However, Framework Design Lack of as shown in [8], wrapper soluCohesion Intention Standard tions can cause such problems as Complicating Factors the need for significant amounts of additional code, along with serious performance degradahas to represent the appropriate domain behavior tion. Moreover, wrappers can’t extend behavior in but the correct cohesive behavior as well. Since the response to intra-framework communication. For cohesive behavior is specific to the framework, it is example, one framework object invoking another unlikely that a class from an independently devel- object in the framework may need an object in yet oped framework would fulfill these requirements. another part of the application to be notified. But Domain coverage. When integrating two or more since the wrapper can’t intercept this communicaframeworks, application and framework developers tion, it is not possible for the application to achieve may experience domain overlap. Some domain over- such notification of other parts of the application. lap is relatively easy to deal with, as it requires only Lack of standards. OO frameworks represent a the adaptation of a few classes in both frameworks. relatively new technology, and there are still no stanConsiderable overlap, however, may mean more dards for modeling, representing, and adapting effort is required to reuse one of the frameworks existing frameworks. Lack of standardization is a than to write the code from scratch, especially for major motivation for framework integration for long-lived applications. Moreover, the frameworks framework and application developers wanting to on which an application is based often evolve over integrate frameworks, since it allows and requires time, along with the application itself. Considerable framework designers to employ ad-hoc solutions. repeated redesign of a framework is then required Unfortunately, the framework components and for every consecutive version of the application—if their interfaces for interoperation are complex. Such

Underlying Causes These problems all result from five primary causes: Framework cohesion. The functionality of a class in the framework can be divided into two types: the domain-specific behavior corresponding to the realworld entity the class represents and the interaction behavior for communicating to other framework entities for mutual updating. We call the latter type “cohesive behavior,” because it establishes cohesion between the entities in the framework. So, for a class from a class library or from another framework to replace a class in the framework, this class not only

84

October 1999/Vol. 42, No. 10 COMMUNICATIONS OF THE ACM

complexity stems from the fact that there are multiple OO techniques for both static and dynamic modeling and no uniform, unified standards for creating framework architectures or for adapting and integrating multiple frameworks. Among the many reasons why two or more frameworks fail to interoperate are the various assumptions made by framework and application developers about representations, synchronization, control, and connectors.

Solutions What are the relationships among the causes, the problems, and solution approaches [3]? The arrows in Figure 3 describe whether the cause is the primary source of the problem (solid arrow) or complicates the solution of the problem (dotted arrow), that is, a secondary cause. Inversion of control. The main cause for this problem is that the frameworks are intentionally designed for adaptation, not for integration, preventing them from giving up control. Since the control loop is often embedded deep in the framework’s source code, lack of access to this code complicates resolving the problem. Some changes to the control loop may be impossible to achieve without changing the actual source code. For example, events that are internal to the framework, such as notification of another framework, and are required externally in the application at hand cannot be intercepted by framework wrappers or adapters but require changing the framework code. Another factor complicating integration of calling frameworks is the cohesive behavior inside the framework. Because this behavior indicates the behavior of framework classes for updating the other framework classes, the classes mix the event behavior with the domain behavior of classes. Since the event loop becomes implicit through cohesive behavior, making changes to the event loop is more difficult in light of the potentially numerous locations where code changes are required. Integrating framework control from the composed frameworks requires changes to the event loops in the frameworks being used. Solutions to changing the event loops include: • Concurrent threads. Give each framework its own thread of control, rather than merging the control loops. This approach can be used only when there is no need for the frameworks or the application code to be notified about events from other frameworks. A disadvantage of this approach is that the application-specific objects that may be

accessed by more than one framework need to be extended with a synchronization code. An advantage is that access to the source code is not required. • Wrapping. Encapsulate each framework by using a wrapper that intercepts all messages sent to and from the framework. Upon receipt of relevant messages, the wrapper can notify interested entities in the framework. This notification allows for some level of integration of event handling in the framework-based application, but only for integration based on events external to the framework. Internal framework events are not intercepted and consequently cannot be addressed. Integration with legacy systems and existing tools. Integration of frameworks, existing tools, and legacy components is difficult because of the cohesive behavior of the frameworks, in turn making it difficult to replace a framework class with a legacy class. Moreover, there may be typing conflicts in the programming language of the frameworks being integrated. A complicating factor in solving such integration is that the framework is designed for adaptation and extension, not for integration. Solutions include: • Roles. Design the framework for integration by means of the “role” concept [3, 9]. Access to the source code of the framework simplifies integration, since application and framework developers can change the framework to refer to the legacy class rather than to a framework class. But changing the reference requires adding frameworkcohesive behavior to the legacy class. • Adapter design pattern. Integrating a legacy component with a framework is an almost schoolbook example of a situation that the Adapter design pattern [3, 6] was designed for. Provided there are no name clashes, this solution is quite suitable, although it results in some implementation overhead. For each operation in the class interface that has to be adapted, there have to be methods for forwarding the request to the equivalent method in the legacy class. • Change the framework. If a framework’s source code is available, the framework classes or parts of classes can be replaced with legacy code; otherwise acquire services from existing tools with the help of interface languages. Framework gap. The main cause for this problem is insufficient coverage by the frameworks of their COMMUNICATIONS OF THE ACM October 1999/Vol. 42, No. 10

85

respective domains. Since the definition of an application domain is still rather ad-hoc, such insufficient domain coverage may lead to domain overlap or domain gaps when integrating frameworks. Moreover, lack of access to source code can considerably complicate the solution of a framework gap. In either case, application and framework developers can identify a number of approaches for closing the gap, including:

Integrating functionality from different frameworks. The cohesive behavior of a framework complicates the integration of functionality since cohesive behavior makes it difficult to break up the existing collaborations inside the framework and add the necessary functionality. One solution is to extend the application-domain-specific class with notification behavior, by, say, applying the Observer design pattern [6]. The solutions to these two problems are combinations of inheritance, multiple inheritance, and aggregation, solving them in varying degrees. However, all these solutions also involve drawbacks [3, 8, 9]. Architectural mismatches. There is no magical solution for solving the inability of two or more frameworks to integrate, but several tricks are helpful:

• Wrapping. They can extend the framework interface of a called framework with the missing functionality through an added application programming interface. In this case, the wrapping entity aggregates the original framework and the extension for closing the gap, providing a uniform interface so clients are unaware of the internal structures. • Mediating software. For a calling framework, they have to develop • Modifying or changing architecsome kind of mediating software tural components. The developer for managing the interactions can modify one or more of the F R A M EWO R K S A R E framework architectural compobetween the two frameworks. The mediating software not only mannents in order to integrate it DE S I G N E D F O R ages the interaction, it also conwith other frameworks. This tains the functionality required for solution is limited, however, posA DA P TAT I O N A N D closing the framework gap. Potensibly causing negative side effects tial disadvantages are proven diffiand requiring access to the EXTENSION, culty in developing mediating source code. components and the software’s vul• Wrapping. Wrapping framework N OT F O R nerability to future changes of components is common in solvframework versions, which thus ing integration and interoperaI N T E G R AT I O N . become expensive to maintain. tion problems, thus avoiding • Redesign and extend. If access is direct modification of the frameavailable to the source code of the work’s components while being framework and the framework is more flexible. A new wrapper intended for reuse in future applican be developed to solve the cations, the most fruitful approach architectural mismatches and may be to redesign the framework and extend the allow smooth integration of multiple frameworks. source code to achieve better domain coverage, • Introducing multilingual framework components. thus bridging the gap. Allowing different representations of the same framework helps alleviate component-integration Overlapping of framework components. The problems. Two mechanisms proposed in [3] are main cause for this problem is coverage of part of intended to help solve architectural mismatches: the application domain by two or more frameworks, interface bridging and interface standardization. each modeling a real-world entity from different Interface bridging involves two steps: interface perspectives. Integration of the two or more frameadaptation to defined relations between types and work classes is often complicated by the cohesive object mapping to support interoperation at runbehavior of the classes, because, after integration, time. Interface standardization is an approach to actions in one class may have to notify the other standardizing interfaces through an interface defiframework classes. nition language, such as CORBA IDL. 86

October 1999/Vol. 42, No. 10 COMMUNICATIONS OF THE ACM

Related Work Software integration problems and related issues studied in [1] involve using multiple class hierarchies for an application. The problems identified are more implementation-oriented than the problems we identified, though there is some overlap. For example, in [1], “control and communication” is mentioned as a pragmatic issue related to the inversion-of-control problem discussed earlier. The main difference is that [1] focuses on pragmatic issues at the class-integration level, primarily addressing the fundamental issues in framework integration. We explore the underlying causes and the solutions available for handling the identified problems. In [8], the discussion focuses on integration of independently developed components, analyzing the problems associated with wrappers, among other things. However, the emphasis is individual components, not OO application frameworks. The notion of architectural mismatch was first mentioned in [7], and two solutions were proposed in [10]. An architectural design language for software development described in [11] has a rich set of rules, notation, and patterns for dealing with software architectural issues. Four aspects of a long-term solution application and framework developers should pursue when seeking to solve the architectural mismatch problem, as suggested in [7], include: • Make architectural assumptions explicit, such as through better documentation and an architectural description language [11]; • Construct large pieces of (framework) software using orthogonal subcomponents, including a building block approach to framework development; • Provide techniques for bridging architectural mismatch, such as mediating software and wrappers, and for easing the integration process, such as “navigator” and “configurator” patterns [2]; and • Develop sources of architectural design guidance, including framework architectural design tools and environments.

Conclusion The increasing availability of frameworks for various domains often necessitates the use of two or more frameworks in an application’s development. But they have to be integrated with one another to fulfill the application’s requirements, possibly leading to integration problems. The most common of these problems are caused primarily by the cohesion of the frameworks, the domain coverage of the frame-

works, design intentions, lack of source code, and lack of standards. Fortunately, some solutions are now available, including wrappers, design patterns, and mediating software. But these solutions also are limited—technically, as in performance, and managerially, as in the extra effort they consume for programming and design. Moreover, most of them still do not solve the problems completely. Still needed are framework standards and framework development guidelines for overcoming these framework integration problems. c References 1. Berlin, L. When objects collide: Experiences with reusing multiple class hierarchies. In Proceedings OOPSLA‘90 (Ottawa, Canada, Oct. 21–25). ACM Press, New York, 1990, pp. 181–193. 2. Fayad, M. and Hamu, D. Object-oriented enterprise frameworks: Make vs. buy decisions and guidelines for selection. Submitted to IEEE Comput. 3. Fayad, M., Schmidt, D., and Johnson, R. Building Application Frameworks: Object-Oriented Foundations of Framework Design. John Wiley & Sons, New York, 1999. 4. Fayad, M., Schmidt, D., and Johnson, R. Implementing Application Frameworks: Object-Oriented Frameworks at Work. John Wiley & Sons, New York, 1999. 5. Fayad, M., and Johnson, R. Building Domain-Specific Application Frameworks: Frameworks Experience by Industry. John Wiley & Sons, New York, 1999. 6. Gamma, E., Helm, R., Johnson, R., and Vlissides, J. Design Patterns— Elements of Reusable Object-Oriented Software. Addison-Wesley Publishing, Reading, Mass., 1995. 7. Garlan, D., Allen, R., and Ockerbloom, J. Architectural mismatch, or why it’s hard to build systems out of existing parts. In Proceedings of ICSE‘95 (Seattle, Apr. 23–30). IEEE Computer Society Press, Los Alamitos, Calif., 1995, pp. 179–185. 8. Holzle, U. Integrating independently developed components in objectoriented languages. In Proceedings of ECOOP‘93 (Kaiserslautern, Germany, July). Springer-Verlag, 1993. 9. Lundberg, C. and Mattsson, M. On using legacy software components with object-oriented frameworks. In Proceedings of Systemarkitekturer‘96 (Boras, Sweden, 1996). 10. Sametinger, J. Software Engineering with Reusable Components. Springer Verlag, 1997. 11. Shaw, M. and Garlan D. Software Architecture: Perspectives on an Emerging Discipline. Prentice Hall, 1995. 12. Sparks, S., Benner, K., and Faris, C. Managing object-oriented framework reuse. In “Managing OO Software Development” theme issue, M. Fayad and M. Cline, Guest Eds. IEEE Comput. 29, 9 (Sept. 1996), 53–61.

Michael Mattsson ([email protected]) is an assistant lecturer in software engineering in the Department of Computer Science and Business Administration at the University of Karlskrona in Ronneby, Sweden. Jan Bosch ([email protected]) is a professor of software engineering in the Department of Computer Science and Business Administration at the University of Karlskrona in Ronneby, Sweden. Mohamed E. Fayad ([email protected]) is an associate professor of computer science in the Department of Computer Science and Engineering at the University of Nebraska in Lincoln, Neb.

© 1999 ACM 0002-0782/99/1000 $5.00

COMMUNICATIONS OF THE ACM October 1999/Vol. 42, No. 10

87