A Proposal for Supporting Software Evolution in Componentware Andreas Rausch Technische Universit¨at M¨unchen Institut f¨ur Informatik Arcisstrasse 21, 80290 Munich, Germany
[email protected]
Abstract In practice, a pure top-down and refinement-based development process is not applicable. A more iterative and incremental approach is usually applied with respect to changing requirements. We call such an approach an evolutionary approach. As existing methodologies rely on refinement concepts they do not support an evolutionary development. In this paper, we present the basic concepts of a suitable overall methodology based on componentware and software evolution. We clarify the difference between refinement steps and evolution steps in a document-based development methodology. We propose an evolutionary development process during system design. To support this process at the best, we need to be able to model and track the dependencies between the various development documents. Currently there is no adequate modeling technique available. To close this gap, we introduce the concept of Requirements/Assurances Contracts. These contracts could be rechecked whenever the specification of a component evolves. This allows the impacts of that evolutionary step to be determined. Developers are able to track and manage the software evolution process. A short example shows the usefulness of the presented concepts and introduces a description technique for requirements/assurances contracts in componentware.
1. Introduction Once a software is developed it is constantly improved. If this evolution is not enforced by a very rigid maintenance process, it results in a divergence of the product from This paper originates from the research in the project A1 “Methods for Component-Based Software Engineering” at the chair of Prof. Dr. Manfred Broy, Institut f¨ur Informatik, Technische Universit¨at M¨unchen. A1 is part of “Bayerischer Forschungsverbund Software-Engineering” (FORSOFT) and supported by Siemens AG, Department ZT.
its original specification. Parnas [33] refers to this phenomenon as “software aging”. The maintenance community has done a lot of work to cope with this kind of code evolution [20, 23, 25, 26]. If the mismatch between implementation and specification becomes too large one can find some useful approaches in the reengineering community [2]. However, all these approaches focus on issues that belong to tasks after the initial system development. Indeed, software is not really aging (in contrast to Parnas [33]), but we belive software is build and designed by aging its specification (evolution-based development). Albeit, instead of an evolution-based design process, most of the today’s software engineering methodologies propose a top-down devlopment process, e.g. the Object Modeling Technique (OMT) [35], the Objectory Process [22], the Rational Unified Process (RUP) [21], or the German standard for information systems development in the public service, called V-Modell [39]. All these methodologies share a common basic idea: During system development a model of the system—the specification—is built and step-wisely refined. A refinement step adds additional properties of the desired system to the model. At last the model is a sufficiently fine, consistent, and correct representation of the system under consideration. It may be implemented by programmers or even partly generated. Surely, all of these processes support local iterations, for instance the RUP allows interations during analysis, design or implementation. However, the overall process is still based on refinement steps to improve the specification model and finally come up with the desired system. In approaches, like ROOM [8] or F OCUS [9] the concept of refinement is even more strict. Such a pure top-down or refinement-based development involve some severe drawbacks: Initially, the customer often does not know all relevant requirements, cannot state them adequately, or even states inconsistent requirements. Consequently, many delivered systems do not meet the customer’s expectations. In addition, top-down development leads to systems that are very brittle with respect to chang-
ing requirements, because the system architecture and the involved components are specifically adjusted to the initial set of requirements. This is in sharp contrast to the idea of building a system from truly reusable components, as the process does not take already existing components into account with respect to reuse. However, in practice a pure top-down or refinementbased approach is not applied. Hence, more sophisticated methodologies provide partial support for software evolution, like for instance methodologies supporting change of requirements and traceability [17], rapid prototyping approaches [6], reuse-based development [3, 1] or componentbased methodologies [4, 38]. Recent research in this area tries to close the gap between software and model evolution [29]. Nevertheless, software and model evolution as a basic concept is currently not well supported. In our opinion, this is partly due to the lack of a suitable overall componentware methodology with respect to software evolution. Such a methodology should at least incorporate the following parts, as illustrated in Figure 1:
These description techniques must be based on the system model including well-defined consistency criteria between different evolution steps. Software Evolution Process: Development should be organized according to a process model tailored to software evolution and component evolution. This includes guidelines for the usage of the description techniques as well as reasonable evolution steps. Evolution-Resistant Architectures: To minimize the costs of software evolution, systems should be based on evolution-resistant architectures. Such architectures contain a common basic infrastructure for components, like DCOM [7], CORBA [30], or Java Enterprise Beans [15]. But even more important are business oriented standard architectures, that are evolution resistant. Whereas the latter one rely on the former one. Tools: At last, all former aspects should be supported by tools. Instances of the system model are stored in repositories and changed by editors, which support the description techniques. Specialized tools may be able to verify the correctness of these evolution steps. An overlying workflow tool organizes the software evolution process. Programming tools support evolutionresistant architectures.
System Model: A well-defined conceptual framework for componentware and software evolution is required as a reliable foundation. It contains the basic notions and concepts, e.g. definitions for an evolution step, a component, or an interface. Description Techniques: Based on the system model, description techniques for componentware are needed. Developers need to model and document the evolution of a single component or a whole component system.
In the following sections we will discuss some of these aspects in detail. Section 2 introduces our view of 2
document-based development. Based on this we are able to come up with a clear definition of a refinement step and an evolution step. In Section 3, an evolution-based development process in the large is characterized. New description techniques are needed to support this process. In Section 4 we introduce the concept of Requirements/Assurances Contracts to model explicitly the dependencies between development documents. Section 5 provides a small example to show the usefulness of the proposed concepts in case of software evolution. A short conclusion ends the paper.
CORBA IDL [32]) only allow to specify the syntax of component interfaces. The behavior of interfaces is usually described in prose. Enhanced descriptions that also capture behavioral aspects use pre- and postconditions, e.g. Eiffel [28] or the Java Modeling Language [24]. Protocol Documents describe the interaction between a set of components. Typical interactions are messages exchange, call hierarchies, or dynamic changes in the connection structure. Examples of protocol descriptions are: Sequence Diagrams in UML [31], Extended Event Traces [11], or Interaction Interfaces [12].
2 Development Documents and Software Evolution
Implementation Documents describe the implementation of a component. Program code is the most popular kind of those descriptions, but we can also use automatons, like in [36, 18] or some kind of greybox specifications [13]. Especially in componentware the implementation of a component can be (recursively) described by a set of structural, interface, protocol, and implementation documents.
Usually, during the development of a system, various documents are created. A document is separate unit that describes a certain aspect of, or “view” on the system under development. In componentware we typically have the following kinds of documents: Structural Documents describe the internal structure of a system or component. The structure of a component consists of its subcomponents and the connections between the subcomponents and with the supercomponent. Usual structural documents describe the static structure of the system (e.g. aggregation or inheritance in UML Class Diagrams [31]). More sophisticated ones can also describe the structural changes over time (e.g. architecture description languages [10] or formal models in componentware [5]).
During development we describe a system by sets of those documents. Let be the infinite set of all possible documents. Let be the infinite set of all possible systems. The semantics of a given set of development documents can be defined by the function :
Interface Documents describe the interfaces of components. Currently most interface descriptions (e.g.
Intuitively, calculates for a given set of development documents the set of systems that are described by these 3
documents or—in other words—that “fulfill” the specification given by the development documents. Most current development methods are based on refinement as already outlined in Section 1. On the left side in Figure 2 three refinement steps of an arbitrary system under development are shown. Based on the semantic function we are able to formulate the correctness of a refinement step (cf. the middle of Figure 2): A refinement step (e.g. from to ) is formally correct if the set of systems described by is a subset of the systems described by , or if the condition holds. Formal methods, like for instance F OCUS, allow us to prove the semantic correctness of such refinement steps [9, 36]. More informal methods provide tools to perform syntactical correctness checks. As Figure 2 illustrates, a correct refinement step adds additional properties to the set of documents describing the desired system. Let be the infinite set of all properties that might ever exist. Thus, we can define another semantic function which assigns to a given set of documents a set of properties characterizing the system:
We call an evolution step of a set of documents
refinement, if the condition holds, abstraction, if the condition holds, strict evolution, if the condition
holds, or total change, if the condition holds. Obviously, we should pay our main attention to the strict evolution. In the remaining paper we use evolution and strict evolution as synonymous, unless if we explicitly distinguish the various kinds of evolution steps. Note, the given definition of an evolution step is a simple and solid foundation. We have to refine this definition and come up with evolution rules for a single document of a certain type. A full treatment is beyond the scope of this paper, as the resulting formulae are rather lengthy (cf. [5]).
Again, a refinement step is formally correct, if the condition holds, or more intuitively, if the new set of properties is consistent with the former one (cf. the right side of Figure 2). As already discussed in Section 1, a refinement-based development does not help developers in a reasonable way. Developers need support for an evolutionary approach. Based on the semantic function , we can now formulate the concept of an evolution step and show the difference between refinement and evolution steps. Figure 3 shows three typical evolution steps during system development. An evolution step in our sense causes changes in the set of development documents within a certain time step as given by the function :
3 Development Process As illustrated in Figure 3, in case of software evolution (strict evolution), the basic condition of classical refinement-based approaches does not longer hold. However, for the development of complex systems, we still need methodical guideline and help. Obviously, we need new techniques to prove the “correctness” of evolution steps. These techniques have 4
4 Requirements/Assurances Contracts
to be well integrated in a suitable evolution-based development process. The essential goal of such a development process is to offer an “as natural as possible” framework for developers. This framework must provide a “playground” for developers enabling their creativity and intuition to the full extent. Figure 4 illustrates such an evolution-based process in an idealized form.
If a document changes via an evolution step, the consequences for documents that rely on the evolved document are not clear at all. Normally, the developer who causes the evolution step has to check whether the other documents are still correct or not (see calculate and visualize indirectly involved components in Figure 4). As the concrete dependencies between the documents are not explicitly formulated, the developer has usually to go into the details of all concerned documents. For that reason we claim that an evolution-based methodology must be able to model and track the dependencies between the various development documents. To reach this goal we have to make the dependencies between the development documents more explicit. Currently, in description techniques or programming languages dependencies between different documents can only be modeled extreme rudimentary. For instance, in UML [31] designers can only specify the relation uses between documents or in Java [14] programmers have to use the import statement to specify that one document relies on another. Surely, more sophisticated specification techniques exist, e.g. Evolving Interoperation Graphs [34], Reuse Contracts [37, 27], or Interaction Contracts [19]. Evolving interoperation graphs provide a framework for change propagation if a single class changes. These graphs take only into account the syntactical interface of classes and the static structure (class hierarchy) of the system, but not the behavioral dependencies. Reuse contracts address the problem of changing implementations of a stable abstract specification. There, evolution conflicts in the scope of inheritance are discussed, but not conflicts in component collaborations. This might be helpful to predict the consequences of evolving a single component, but the effects for other components or the entire system are not clear at all. At last, interaction contracts are used to specify the collaborations between objects. Although the basic idea of interaction contracts—to specify the behavioral dependencies between objects—seems to be a quite good suggestion, this approach takes neither evolution nor componentware sufficiently into account. Interaction contracts strongly couple the behavior specification of the component seen as a island and the behavioral dependencies to other components. Hence, the impacts of an evolutionary step can not be determined. To avoid these drawbacks and support an evolutionbased process (cf. Section 3) at the best, we propose to decouple the component island specification from the behavioral dependencies specification. The following two functions calculate the behavior specification of a single component seen as an island. Let be the infinite set of
Let us consider a running project where actually some requirements have changed. To fulfill the changed requirements designers improve the system design. Developers “play” with the model of the system until they have the “feeling” that the changed model meets the new requirements (edit development documents). Then, a tool or another developer should calculate and visualize the directly changed components, e.g. the syntactical changes of the interfaces or even all dismissed and new properties of the directly changed components1. Based on this the developer can decide whether these changes are not OK or the changes are OK and he can proceed (validate changes). As complexity of systems increases, a single developer cannot predict the effects of his changes at a single component to the entire system. Hence, again a tool or another developer should calculate and visualize the indirectly involved components and the origin developer again has to validate these changes. As already mentioned, novel tools and techniques are needed to support the process, in particular the two steps calculate and visualize directly changed components and calculate and visualize indirectly involved components. Nowadays there are first prototype tools and techniques already available for the first step. For instance, developers may use a XMI based CASE tool to edit documents. The changes can be automatically visualized via a XML diff tool. However, there isn’t almost any support for the second step. The next section discusses this issue in detail. 1 Note,
dismissed properties are formally given by and new properties are formally given by .
5
components.
quired properties of a component and the assured properties of other components:
Intuitively spoken, the function calculates for a given set of documents and a component the set of properties the component expects from its environment and the function calculates the set of properties the component provides to its environment. We need specialized description techniques to enable the designer to model the required and assured properties of a certain component explicitly within this development document. Such description techniques must be strongly structured. They should have at least two additional parts capturing the set of required and assured properties (cf. Figure 5):
A given contract is , if all required properties of a component are assured by properties of other components. Let be the function that calculates the set of documents describing a given component:
Requirements: In the requirements part the designer has to specify the properties the component needs from its environment.
In the case of software evolution the designer or a tool has to re-check whether requirements of components, that rely on the assurances of the evolved component, are still guaranteed. Formally the tool has to re-check whether the predicate
Assurances: In the assurances part the designer describes the properties the component assures to its environment, assuming its own requirements are fulfilled.
still holds. For instance, in Figure 5 component C has changed over time. The designer has to validate whether Contract B still holds. More exactly, he has to check whether the requirements of component C are still satisfied by the assurances of component A or not. The advantages of requirements/assurances contracts come only fully to validity if we have adequate description techniques to specify the requirements and assurances of components within development documents. We still have to elaborate a consistent set of description techniques to support evolution in componentware at the best. In the next section we provide a small sample including some simple description techniques to prove the usefulness of requirements/assurances contracts.
Once these additional aspects are specified (formally given by the functions and ), the designer can explicitly state the behavioral dependencies between the components by specifying for each component the assurances that guarantee the requirements. We call such explicit formulated dependencies Requirements/Assurances Contracts. Figure 5 illustrates the usage of those contracts. The three development documents include the additional requirements (white bubble) and assurances (black bubble) parts. Developers can explicitly model the dependencies between the components by requirements/assurances contracts shown as double arrowed lines. Formally a requirements/assurances contract is a mapping between the re6
5 Evolving a Help Window – A Short Sample
part is the ASSURES part capturing all interfaces the component provides to its environment. For each interface the assured properties (again syntax and behavior) are explicitly described. The notation and semantic within these parts is equal to the one used for the interaction contracts (cf. [19]). But note, the interaction contracts are not equal to our requirements/assurances contracts (cf. Section 4). We only reused the specification technique, as an own specification language is beyond the scope of this paper. The re-used language allows description of behavior in terms of ordered sequences of actions to be performed and conditions to be made true. The language only supports the actions of sending a message to a component , denoted by , and change of a value , denoted by . The ordering of actions can be explicitly given by the operator “ ”, an IF-THEN-ELSE construct, or be left unspecified by the operator . The language also provides the construct for the repetition of an expression separated by the operator for all variables which satisfy . Now, we can start out with a textual specification of the requirements and assurances of the two components HelpText and HelpList—the components island specification:
To illustrate the practical relevance of the proposed requirements/assurancescontracts we want to discuss a short example. Consider a windows help screen as shown in Figure 6. It contains two components: a text box and a list box control element. The content of the text box restricts the presented help topics in the list box. Whenever the user changes the content of the text box—simply by adding a single character—the new selection of help topics is immediately presented in the list box.
COMPONENT HelpText REQUIRES INTERFACE Observer WITH METHODS update() : void ASSURES INTERFACE TextBox WITH LOCALS observers : Set(Observer) text : String WITH METHODS getText() : String addText(t : String) : void
A simple implementation of such a help screen may contain the two components HelpText and HelpList. The collaboration between these two components usually follows the Observer Pattern (cf. [16]). In the case of an “observable” component (HelpText) changing parts of its state, all “observing” components (HelpList) are notified. Components in a system often evolve. To make the windows help screen more evolution resistant, one should specify the help screen in a modular fashion. Thus, we use two different kinds of descriptions as proposed in Section 4:
The component HelpText requires an interface supporting the method update():void. Note that, in the context of this specification the required interface is named Observer. This represents neither a global name nor a type of the required interface. Later, we can explicitly model the mapping between the various required and assured interface and method names via the proposed requirements/assurances contracts. Additionally, the component HelpText assures an interface TextBox with the two methods getText():String and addText(t:String):void. When addText(t) is called the method update() is invoked for all observers. Correspondingly, the component HelpList requires an interface named Observable that includes the method getText():String. Moreover, whenever the return
Descriptions of the behavior of a single component seen as a island start with COMPONENT and descriptions of the behavioral dependencies between components start with RA-CONTRACT. In the example description technique we use, keywords are written with capital letters. Each component island specification consists of two parts in the specification: The first part is the REQUIRES part containing all interfaces the component needs. For each interface the required properties (syntax and behavior) are explicitly specified. The second 7
value of getText() changes, the update() method of the component HelpList has to be called via the interface ListBox. This is the basic behavior requirement the component HelpList needs to be assured by its environment. COMPONENT HelpList REQUIRES INTERFACE Observable WITH METHODS getText() : String WITH INVARIANTS
RA-CONTRACT HelpTextContract INSTANTIATION hl : HelpList ht : HelpText ht.TextBox.observers.add(hl) hl.ListBox.observable = ht PREDICATE MAPPING: REQUIRED ht.Observer ASSURED BY hl.ListBox
ASSURES INTERFACE ListBox WITH LOCALS observable : Observable WITH METHODS update() : void
Once the windows help screen is completely specified and implemented, it usually takes a couple of months and at least one of the components appears in a new, improved version. In our example, the new version of the component HelpText has been evolved. The new version assures an additional method addChar(c:Char):void. For performance reasons, this method does not guarantee that the observers are notified if the method is invoked:
Now, we can specify two requirements/assurance contracts: One to satisfy the requirements of the component HelpList and the other for the requirements of component HelpText. Such a contract contains two sections: The first section, the INSTANTIATION section, declares the participants of the contract and their initial configuration. For instance, in the contract HelpListContract are the two participants hl:HelpList and ht:HelpText instantiated and the initial connection between both is established. The second section, the PROPERTY MAPPING section, maps the required interfaces to assured interfaces of the participants. Additionally, it contains the most important part of the contract: the “proof”. There, the designer has to validate the correctness of the contract, means he has to proof whether the syntax and behavior of the requirements/assurance pair fits together. The contract HelpListContract includes a proof. It simply starts with conjunction of all assured properties of the interface ht.TextBox and has to end with all required properties of the interface hl.Observable:
COMPONENT HelpText REQUIRES INTERFACE Observer WITH METHODS update() : void ASSURES INTERFACE TextBox WITH LOCALS observers : Set(Observer) text : String WITH METHODS getText() : String addText(t : String) : void
addChar(c : Char) : void The assurances part in the specification of the component HelpText has changed. Therefore, the designer or a tool should search for all requirements/assurances contracts where HelpText is used as an insurer. Once, all of these contracts are identified, the corresponding proofs have to be re-done. In our example the contract HelpListContract is concerned. The designer has to re-check whether the goal still can be reached. But the premises have been changed. The conjunction of all assured properties of the interface ht.TextBox is now:
RA-CONTRACT HelpListContract INSTANTIATION hl : HelpList ht : HelpText ht.TextBox.observers.add(hl) hl.ListBox.observable = ht PREDICATE MAPPING: REQUIRED hl.Observable ASSURED BY ht.TextBox
8
tures like CORBA, DCOM, or Java Enterprise Beans. More work has to be done concerning a complete embedding of the concept of evolution into a formal componentware methodology. Moreover, we will provide mappings from the presented description techniques into this formal model. At last, we have to develop tool support and provide a set of evolution resistant architectures.
Obviously the goal cannot be derived, as a call of changes the return value of the method but does not result in an for the HelpList. Thus, the requirement of the component HelpList—whenever the text in HelpText changes update() is called—are no longer satisfied by the new component HelpText. The current design of the system may not longer meet the expectations or the requirements. Now, the designer can decide to keep the former component in use or to realize a workaround in the HelpList component. However, this is out of the scope of the discussed concepts. To sum up, the example illustrates the usage of requirements/assurances contracts. Developers can explicitly model the dependencies between the different components. Whenever a component or the entire system changes contracts help to show the consequences for other components and help the developer to manage the evolution of the complete system. Additionally, syntax compatible checkers, theorem prover, and model checker could be included to run the correctness proof for evolution steps semi-automatically or even full-automatically.
Acknowledgments We thank Klaus Bergner, Manfred Broy, Ingolf Krger, Marc Sihling, and Alexander Vilbig for interesting discussions and comments on earlier versions of this paper.
References [1] D. Ansorge, K. Bergner, B. Deifel, N. Hawlitzky, A. Rausch, M. Sihling, V. Thurner, and S. Vogel. Managing componentware development – software reuse and the V-Modell process. In Proceedings of CAiSE ’99, Lecture Notes in Computer Science. Springer-Verlag, 1999. [2] R. S. Arnold, editor. Software Reengineering. IEEE Computer Society, 1993. [3] K. Bergner, A. Rausch, M. Sihling, and A. Vilbig. A componentware development methodology based on process patterns. Technical Report I-9823, Technische Universit¨at M¨unchen, Institut f¨ur Informatik, 1998. [4] K. Bergner, A. Rausch, M. Sihling, and A. Vilbig. An integrated view on componentware - concepts, description techniques, and development process. In R. Lee, editor, Software Engineering : Proceedings of the IASTED Conference ‘98. ACTA Press, Anaheim, 1998. [5] K. Bergner, A. Rausch, M. Sihling, A. Vilbig, and M. Broy. A formal model for componentware. In K. Spies and B. Schtz, editors, Formale Beschreibungstechniken f¨ur verteilte Systeme FBT’99. Herbert Utz Verlag, 1999. [6] Bischofberger W. R. and Pomberger G. PrototypingOriented Software Development - Concepts and Tools. Springer-Verlag, 1992. [7] D. Box. Essential COM. Object Technology Series. Addison-Wesley, 1998. [8] Bran Selic and Garth Gullekson and Paul T. Ward. RealTime Object-Oriented Modeling. Wiley & Sons, 1994. [9] M. Broy, F. Dederichs, C. Dendorfer, M. Fuchs, T. Gritzner, and R. Weber. The design of distributed systems - an introduction to FOCUS. Technical Report TUM-I9203, Technische Universit¨at M¨unchen, Institut f¨ur Informatik, January 1992. [10] M. Broy, E. Denert, K. Renzel, and M. Schmidt (eds.). Software architectures and design patterns in business applications. Technical Report TUM-I9746, Technische Universit¨at M¨unchen, Institut f¨ur Informatik, 1997. [11] M. Broy, C. Hofmann, I. Kr¨uger, and M. Schmidt. Using extended event traces to describe communication in software architectures. In Asia-Pacific Software Engineering Conference and International Computer Science Conference, Hong Kong. IEEE Computer Society, 1997.
6 Conclusion and Further Work In this paper, we have outlined the overall idea of an evolution-based development methodology for componentware: it consists of a system model, description techniques, a software evolution process, evolution resistant architectures, and tools supporting the methodology. During software development, a set of documents are created and edited. Hence, a methodology based on refinement is not suitable. We introduced an evolution-based development process, that helps showing the consequences of a local evolution step to the entire system. This process must be supported by specialized techniques and descriptions. Therefore we proposed the concept of requirements/assurances contracts to explicitly model the behavioral dependencies between components. Thus, in case of the evolution of a single component, we can point out the effects for the rest of the system. In a short sample, we presented a description technique for requirements/assurances contracts and illustrated the usefulness of these contracts in practice. Further work will include a more detailed discussion of the presented evolution development process. Additionally we have to provide more sophisticated graphical description techniques. A complete development example will show these description techniques in practice. Finally, must present mappings into technical componentware infrastruc9
[12] M. Broy and I. Krger. Interaction Interfaces - Towards a scientific foundation of a methodological usage of Message Sequence Charts. In Proceedings of the ICFEM 98. IEEE Press, 1998. [13] M. B¨uchi and W. Weck. A plea for grey-box components. Technical Report 122, Turku Center for Computer Science, Presented at the Workshop on Foundations of ComponentBased Systems, Z¨urich, September 1997, 1997. [14] D. Flanagan. Java in a Nutshell. O’Reilly & Associates, Inc., 2nd edition, 1996. [15] D. Flanagan, J. Farley, and W. Crawford. Java Enterprise in a Nutshell. O’Reilly & Associates, Inc., 1999. [16] E. Gamma. Objektorientierte Software-Entwicklung am Beispiel von ET++ — Design-Muster, Klassenbibliotheken, Werkzeuge. Springer-Verlag, 1992. [17] A. K. Ghose. Managing requirements evolution: Formal support for functional and non-functional requirements. In Proceedings of the 1999 International Workshop on Principles of Software Evolution, Fukuoka, Japan. IEEE Press, 1999. [18] D. Harel. On Visual Formalisms. Communications of the ACM, 31(5):514–531, May 1988. [19] R. Helm, I. M. Holland, and D. Gangopadhyay. Contracts: Specifying Behavioral Compositions in Object-Oriented Systems. ECOOP/OOPSLA ’90 Proceedings, pages 169– 180, Oct. 1990. [20] B. Henderson-Sellers and J. Edwards. The object-oriented systems life cycle. Communications of the ACM, 33(9), 1990. [21] Ivar Jacobson and Grady Booch and James Rumbaugh. The Unified Software Development Process. Addison Wesley, 1999. [22] I. Jacobson. Object-Oriented Software Engineering — A Use Case Driven Approach. Addison-Wesley, 1992. [23] D. Kung, J. Gao, P. Hsia, F. Wen, Y. Toyoshima, and C. Chen. Change Impact Identification in Object-Oriented Software Maintenance. In Proceedings of the International Conference on Software Maintenance. IEEE Press, 1994. [24] G. T. Leavens, A. L. Baker, and C. Ruby. Preliminary design of jml: A behavioral interface specification language for java. Technical Report 98-06f, Iowa State University, Department of Computer Science, 1999. [25] M. M. Lehman. Programs, life cycles and laws of software evolution. In Proceedings of the IEEE. IEEE Press, 1980. [26] K. J. Lieberherr and C. Xiao. Object-oriented software evolution. IEEE Transactions on Software Engineering, 19(4), 1993. [27] C. Lucas, P. Steyaert, and K. Mens. Managing software evolution through reuse contracts. Technical Report vub-progtr-97-01, Vrije Universiteit Brussel Faculteit Wetenschappen, BELGIUM, 1997. [28] B. Meyer. Object-Oriented Software Construction. Prentice Hall, 2nd edition, 1997. [29] R. T. Mittermeir, H. Pirker, and D. Rauner-Reithmayer. Object Evolution by Model Evolution. In Proceedings of the 2nd Euromicro Conference on Software Maintenance and Reengineering ( CSMR’98). IEEE Press, 1998. [30] OMG. The Common Object Request Broker: Architecture and Specification. Object Management Group, February 1998.
[31] OMG. OMG Unified Modeling Language Specification. Version 1.3, Object Management Group, 1999. [32] R. Orfali and D. Harkey. Client/Server Programming with Java and CORBA. John Wiley & Sons, 1997. [33] D. L. Parnas. Software aging. In Proceedings of 16th International Conference on Software Engineering, pages 279– 87, Sorrento, Italy, 16–21 May 1994. IEEE. [34] V. Rajlich. Modeling Software Evolution by Evolving Interoperation Graphs. In Software Change and Evolution 1999 Workshop Proceedings, Technical Report No. 05.99.061. Universita degli Stui del Sannio, Facolta di Ingegneria, Italy, 1999. [35] J. Rumbaugh, M. Blaha, W. Premerlani, F. Eddy, and W. Lorensen. Object-Oriented Modeling and Design. Prentice Hall, 1991. [36] B. Rumpe. Formale Methodik des Entwurfs verteilter objektorientierter Systeme. PhD thesis, Technische Universit¨at M¨unchen, 1996. [37] P. Steyaert, C. Lucas, K. Mens, and T. D’Hondt. Reuse Contracts: Managing the Evolution of Reusable Assets. In OOPSLA 1996 Conference Proceedings, ACM Sigplan Notices, pages 268–285. ACM Press, 1996. [38] C. Szyperski. Component Software - Beyond ObjectOriented Programming. Addison Wesley Ltd., 1997. [39] W. Dr¨oschel and W. Heuser and R. Midderhoff. Inkrementelle und objektorientierte Vorgehensweisen mit dem VModell 97. R. Oldenbourg Verlag M¨unchen, 1998.
10