Java interpreter and a case-based class retrieval tool. The Java interpreter ... tation dependencies. Software development in Java is intended to allows appli-.
R e t r i e v a l of Java Classes for C a s e - B a s e d R e u s e Bj~rnar Tessem 1, R. Alan Whitehurst 2, and Christopher L. Powell 2 1 Dept. of Information Science, University of Bergen, 5020 Bergen, Norway Bj ornar. Tes sem~ifi, uib. n o 2 Computer Science Department, Brigham Young University, 3361 TMCB, PO Box 26576, Provo, Utah 84602-6576, USA {whir ehur, bulls23}@escalante, cs. byu. e d u A b s t r a c t . Rapid prototyping in object-oriented programming requires effective retrieval of reusable classes. This paper describes the methods used in the retrieval phase of a case-based component in a prototyping tool for the Java programming language. The case-based tool aids in class retrieval and reuse. Java has a reflective ability in the sense that classes may be asked for their methods, fields, constructors, and other information. We use this information to automatically generate features used to index the Java classes. We use both the reflected information, and knowledge inferred from that information. We describe the retrieval algorithm used in the case-based tool, and show some example runs.
1
Introduction
The ever increasing need for higher productivity in software development has led to research on how to reuse already made and tested software components [4]. The introduction of object-oriented p r o g r a m m i n g languages is perhaps the most useful step in our pursuit of more effective reuse in software development, but still there are problems when it comes to retrieving and understanding objectoriented classes [15]. Rapid prototyping of systems is a process where the developer uses new or ready made code components to implement a quick solution to a specified system. We are building a system t h a t supports rapid prototyping in Java. J a v a has the inherent problems of object-oriented p r o g r a m m i n g languages when it comes to retrieval and understanding, and we therefore intend to give support for class retrieval, understanding, and reuse in the rapid prototyping tool. In particular, there are two components in the tool t h a t will give this support: A J a v a interpreter and a case-based class retrieval tool. The J a v a interpreter allows the user to test run uncompiled J a v a statements; thus, the user can i m p o r t J a v a classes to the environment, and test their functionality in the interpreter. The case-based class retrieval component supports retrieval and reuse of classes, utilizing the reflective capabilities of Java. T h r o u g h reflection it is possible to ask a J a v a class for information a b o u t its methods, constructors, and
149
fields. This is possible even in the case where we do not have the source code. From these signatures we m a y also extract knowledge a b o u t what kind of component this is. For instance, whether it is a collection of some kind, whether it is a p a r t of a design p a t t e r n [9], or whether it has some other features we can infer from the signatures. In this p a p e r we focus on the retrieval process of the case-based component. Our approach is to use the signatures and some features inferred from these in retrieval. In the remainder of this paper we give a description of the rapid p r o t o t y p i n g tool (section 2), We continue with a more thorough introduction to software reuse, Java, and case-based reasoning (section 3). We describe how we extract the features used for retrieval in section 4. In section 5 we present the retrieval process. We give some example runs in section 6, and describe some related work in section 7, before we conclude with a discussion and ideas for further work in section 8.
2
RapidPrototyping Using JAVA
The environment we are building consists of several components which interactively work together to aid the user in rapid prototyping. These components are: E d i t o r The editor is a standard editor with extentions for interaction with the other environmental components. The editor provides partial class descriptions from which a case description is extracted and provided to the class retriever as a target case. The set of classes returned as the results of the class retriever are displayed in and selectable from the editor windows. The class adapter interacts with the editor to assist the user in the process of reusing a retrieved class. For example, in highlighting code segments of the target class which m a y need to be changed due do to suggested mappings to a selected base case. S o u r c e - l e v e l I n t e r p r e t e r The interpreter makes it possible to evaluate arbit r a r y Java statements to see their effects on the objects we are currently working with. C l a s s B r o w s e r The browser makes it possible to search in specified directories for classes t h a t m a y be of interest to the current project. C a s e - b a s e d C l a s s R e t r i e v e r The retriever complements the actions of the browser by supporting the user through a u t o m a t e d retrieval of classes for possible reuse. C l a s s A d a p t e r T h e adapter encapsulates knowledge of reuse strategies to support the a u t o m a t e d modification of retrieved classes. These components work together to assist the developer in rapidly building J a v a applications. As the developer imports various classes a n d / o r enters J a v a statements, the interpreter evaluates the statements and gives immediate feedback on design and coding decisions. T h r o u g h this process, the developer begins to build an incomplete specification of a target class. Once a p r o t o t y p e target
150
class has been sufficiently developed, the developer can compile it into Java bytecode for storage in a . c l a s s file. The developer can invoke the case-based class retriever to return possible base cases for reuse. The adapter takes the possible base cases and determines the best way each base case may be reused. The three options are, either extending (subclassing) the retrieved class, instantiating the retrieved class directly, or through lexical selection and adaptation of code segments. The building of the repository and comparison algorithm used to extract components is discussed in the following sections.
3
Java P r o g r a m m i n g and C a s e - B a s e d R e a s o n i n g
Object-oriented software development differs from conventional software development approaches in its emphasis on encapsulation, inheritence and polymorphism; concepts that guide system organization and that are intended to promote the reuseability of the resulting software components [5]. Java is a class-based object-oriented programming language, which extends conventional object-oriented reuse support by specifically minimizing implementation dependencies. Software development in Java is intended to allows application developers to write a program once and then be able to run it anywhere on the internet.[10] Software reuse in Java is founded upon a compositional model. Under the compositional model, software development may be viewed as a constructive activity wherein a system is composed from a set of existing components. When building object-oriented systems from components, development can be characterized by a number of processes, including:
Conceptualization A model of the application domain is formulated which partitions the desired functionality of the system into components. A c c u m u l a t i o n Existing components are evaluated against a partial set of requirements and those satisfying various aspects of the requirements for each component are identified. Evaluation The best existing component (or set of components) is selected for each component of the conceptual design. Adaptation The selected components are adapted to the specific requirements of the conceptual components. Composition The components are composed to meet the desired characteristics of the system under construction. Expansion Any newly developed components are added to the repository of reusable components. Implementation The alternative to compositional reuse; if a suitable candidate cannot be found, then it must be implemented from scratch. When object-oriented reuse methods are correctly employed, the developer has access to a set of powerful mechanisms that directly support software reuse. However, with respect to the difference-based reasoning that underlies the early stages of the compositional development process, the methodological support that conventional object-oriented programming offers is in what occurs after a
151
component has been identified and analyzed; in other words, only during the adaptation and expansion phases of the compositional development process. Because the developer is left without support for the process of creating the mental mappings necessary to the accumulation and evaluation phases of the software reuse process, the developer must aquire an intimate knowledge of the contents of all the class libraries that are available for reuse in order to be effective. This explains why object-oriented programming has such a steep learning curve [15]: much of the effort of becoming an effective programmer in an object-oriented environment is expended in becoming familiar with the existing class libraries. If the class repository is dynamic, this problem is compounded in that any time a new class is added to the environment, a period of adjustment and retraining must occur. This is an important point, because if programmers are not familiar with the class hierarchy or are unaware of how the class hierarchy is being extended, efficiency is lost and redundancy in the class library will occur. In order to minimize redundancy in software development and support the difference-based reasoning that is at the heart of the compositional software development model, it is desirable to provide tools to assist the developer in accumulating, evaluating and adapting software components. Case-Based Reasoning (CBR) is a technique for building AI systems that captures problem-solving expertise in the form of specific problem/solution representation and utilizes similarities in problem descriptions to select and adapt previous solutions to new situations[12, 1]. Instead of general knowledge about a domain the system stores case descriptions and their associated solutions that are retrieved, adapted and utilized in the solution of new problems. There are four phases in a case-based reasoning process [1]: retrieval, reuse, revision, and retainment. Retrieval is the process of finding a similar case in a case base (base case). Reuse is the mapping and adaption of the base case to the present problem (target case). Revision is the evaluation and correction of the solution. Retainmeat is the learning process whereby the new case (problem description and adapted solution) is stored in the case base for future reuse. Through a comparison of the activities described in the compositional software reuse model and the phases of case-based reasoning, we can draw an analogy between the accumulation and evaluation steps of compositional reuse and the retrieval phase of the case-based reasoning process. Likewise, adaptation and composition of the compostional model are analogous to the reuse phase of the case-based reasoning process. From this observation we can conclude that if it were possible to develop an adequate set of features for describing a software component case, then case-based reasoning could provide an effective mechanism for automating the retrieval and adaptation of reuseable software components. However, to avoid the problems of initial high investment with little return that plague most automated software reuse strategies, it is imparative that case descriptions be constructed from the software artifacts themselves without requiring additional work on the part of the software developers. Satisfying this
152
requirement will ensure that the automated retrieval and adaptation strategies will be immediately useful and work with existing software repositories. 4
Automated
Feature
Extraction
As software development practices have continued to evolve, the proliferation of available application software has given rise to a number of software classification schemes. For example, Prieto-Di~z proposed a software classification scheme based on sets of descriptors (or facets) that capture attributes relating to functionality, approach, and implementation details[17]. Prieto-Di~z advocates tuples of descriptor/value pairs and attempts to identify which descriptors are required to adequately retrieve typical software components. This is very similar to the CBR approach. However, these past classification schemes, including the descriptors advocated by Prieto-Dis relate primarily to the implied functional semantics of the reusable software component, and would be very challenging to attempt to automatically extract from existing program code. To increase the chances for adoption in real programming environments, we chose to concentrate on the use of descriptors that would lend themselves to automatic extraction. Such information includes the type signatures of methods and instance variables, inheritence relationships, and limited semantics infered from the names of variables, methods, and classes. In implementing the automated faceting, we utilized the Java language facilities for reflection. Reflection enables Java code to discover information about the fields, methods and constructors of loaded classes, and to use reflected fields, methods, and constructors to operate on their underlying counterparts[19]. This capability of the Java language allows us to extract feature descriptions from compiled classes without having access to the source code. However, it should be noted that the same approach to feature extraction could be implemented in any other programming environment in which the source code for a component is available. In addition to the features extracted directly from the reflective class knowledge in Java, it is possible to derive new features from these features. One example is the ADT collection feature, which describes a class as an instance of a canonical collection class, like LIST, STACK, HASHTABLE, etc. Other types of knowledge may also be deduced from the signatures of classes, like other kinds of canonical classes (streams, strings, persons), patterns of the kind found in Gamma et al. [9], and other features more like the facets described by Prieto-Dis [17]. So far we have focused on the extraction of the ADT Collection Feature. The knowledge used to extract the collection ADT kind of a class is, in addition to the class signature, knowledge about what kind of signatures you would find in a particular collection kind. The example below illustrates how we represent this type of knowledge. The description shows the description of a STACK class.
ADT STACK { Data { Vector\List\Array; int countericount\elementcountinumberofelements;}
153
Constructors { Stack();} Operations { Object\void remove\pop (); void push (Object); Object top\first\peek (); boolean isemptykempty (); void\boolean clear ();} } It has information about d a t a fields, constructors, and operations you would typically find in a LIST class, with their names, types, and p a r a m e t e r lists. The interpretation of the line " 0 b j e c t \ v o i d r e m o v e \ p o p ( ) ; " is t h a t there is a method either being v o i d or returning an O b j e c t with one of the names remove or pop, and the p a r a m e t e r of this method is usually empty. The p a r a m e t e r list would usually list the p a r a m e t e r types only. When computing the A D T collection feature we need to establish a good match between the sets of signature, field, and constructor features for a class and the contents of a class. In principle, what we do, is to compute a similarity between each of the signature/field/constructor features of a class and each of the canonical m e t h o d s / d a t a fields/constructors of the collection type. Then we run an assignment algorithm (weighted bipartite matching) [16] so t h a t the sum of similarities between features and canonical elements is maximized for each set of features. The similarity between each pair of features from the class and canonical element is a weighted sum of the similarities between types, names, and arguments where we give most weight to names. The reason for this is t h a t names seem to be very similar in all text books on d a t a structures and hence is the attribute that discriminates best. Similarity between terms is so far only syntactic similarity, but we do not only consider equality in strings. We also use substring similarity and alignment similarity. Substring similarity occurs when a t e r m is a substring of the other. Alignment similarity occurs when large parts of the strings are similar, but neither is a substring of the other, for instance n a m e s e l e m e n t N o and t h e E l e m e n t A t which m a y b o t h be used for methods of t h a t get the element in a particular position of a list or a vector. When the pairwise similarities are found and the assignment algorithm has been run, we compute a total similarity value from a weigthed sum of each of the similarites for the field features, constructor features, and signature features. In a run comparing the signature, field, and constructor features of Java's j a v a . u t i l . S t a c k and some A D T descriptions the S T A C K canonical A D T got a similarity of 0.645. The Q U E U E canonical A D T was a runner-up with a similarity of 0.470. The features of j a v a . u t i l . S t a c k is given below:
{Name:Stack; Features: [ ,
154
]} We plan t o i m p l e m e n t s i m i l a r a p p r o a c h e s f o r e x t r a c t i n g other k i n d s o f A D T s , and also to in~r a design pattern a class represents o r i s a p a r t of.
5
The Retrieval Algorithm
The retrieval process starts by identifying the features of the target case. When this is done, the algorithm searches for . c l a s s files in a chosen directory or a set of directories. By default this is the J a v a classpath, which is the paths where the J a v a virtual machine looks for class definitions. T h e next step is to compare the . c a s e files for each . c l a s s file with the target case features. T h e best few matches are then presented for suggested reuse.
5.1
Feature E x t r a c t i o n for t h e Target Case
In this phase of the retrieval process, the user specifies the content of the target case class. The information needed is
1. A class heading, consisting of class name and information a b o u t any superclasses. 2. Any fields known to be needed as parts of the class. Both types and names are relevant. 3. Any constructors known to be needed. The i m p o r t a n t information here are the p a r a m e t e r types for the constructor 4. Any methods known to be needed. The i m p o r t a n t information here are the return types, names, and p a r a m e t e r s of the methods. 5. T h e user also specifies any A D T collection type the class m a y be an instance of. This is extracted automatically for the base cases, but since the target class specification usually is incomplete, we ask the user for this feature. A class specification has a J a v a like syntax, and the example below shows a partial specification of a string class.
class MyString { char[] data; int length; MyString () ; MyString(char c) ;
155
MyString(int i); boolean equals(Object anObject); int length(); int charAt(int i);
5.2
T h e Case C o m p a r i s o n L o o p
The extraction of the features for all classes in a repository is time consuming, hence the the Case description for a class is made only in two situations. 1. There is no previous Case description for the class. In this case a new Case decription is made and stored in a . c a s e file. 2. The . c a s e file corresponding to a . c l a s s file is older t h a n the compiled Java class ( i . e . . c l a s s file). Then an u p d a t e d Case description is m a d e and stored in the . c a s e file. In any other situations the Case description found in the . c a s e file is read and used for comparison. The whole process of running through a repository is handled with the help of an iterator class n a m e d TreeWalker. T r e e W a l k e r runs through a directory tree, finds all . c l a s s files, computes cases or reads t h e m from . c a s e files. T r e e W a l k e r ' s n e x t C a s e ( ) method returns one case to be compared at a time. 5.3
T h e Case S i m i l a r i t y C o m p u t a t i o n
The comparison of the target case and the base cases are very similar to the approach used when comparing features for the derivation of the the A D T collection feature. However, in this case we do also consider the A D T feature and the ISA feature of the target case. Similarity in those two features are given high weighting compared to similarity in signatures, fields, and constructors. The weightings are 10 for A D T and ISA features if applicable, 3 for each m e t h o d signature, 2 for each field and 1 for each constructor. In the comparison of the signature and field features we also put less weight on the names t h a n when in the ADT feature case. T h e reason for this is t h a t the names chosen in a hastily made specification should not affect the retrieval too much. Another i m p o r t a n t distinction from the c o m p u t a t i o n of the A D T feature is t h a t we do not use the assignment algorithm during the computation. This algorithm is computationally expensive (O(N3)), and hence should only be used when matching few cases. In the search through the repository we m a y go through hundreds of classes, and in a tool like this we can not expect a user to wait too long. Instead, the matching is done in an incremental way. For instance, for the signature features, we use the order in the specification to first find the best match for the first method of the target, then continuing in the order the methods are given. We continue till all methods in the target are matched.
156
Methods in the base case are not allowed to m a t c h more t h a n once, and hence we may see t h a t the best match for a m e t h o d is taken when we try to m a t c h it. However, we accept this for the sake of efficiency. The matching of fields and constructors are done in the same way. To avoid some of the problems with this approach, we do not accept similarities below a certain threshold (0.5). This way, a poorly matched method signature will not "steal" the best m a t c h for a target method signature t h a t has high similarity to a base method signature. This strategy also places some burden on the user in the sense t h a t he must think about the sequence of signatures in his specification. For instance, it would be smart to always specify constructors with the shortest p a r a m e t e r lists first as this is the sequence found in most classes (it is almost conventional). This also applies for methods with same names and returnType, but different p a r a m e t e r lists. If the user does it the opposite way, the m e t h o d with the longest p a r a m e t e r list may be matched to the method with the shortest list and vice versa. The result would be lower similarity t h a n the optimal match.
6
Example Runs
In section 5 we gave an example of a typical class specification to be used as a description of the target case. We ran a search for the class most similar to this among more than 1,700 classes in the libraries delivered with java 1.1.4. Not surprisingly, the best m a t c h found was the j a v a . l a n g . S t r i n g class. T h e e q u a l s and l e n g t h methods found perfect matches, whereas the c h a r A t m e t h o d did not match in return type to j a v a . l a n g S t r i n g ' s c h a r A t method, so it matched to other methods with identical return types and argument lists. T h e reason for this is that we have chosen not to give much weight to method names in our search. The d a t a array matched to a similar array in the S t r i n g class, whereas the l e n g t h field of MyString did m a t c h an i n t field of the S t r i n g c l a s s . Among the constructors only the e m p t y one found a match. T h e eight most similar classes were: 1. j a v a . l a n g . S t r i n g 2. j a v a . t e x t . C o m p a c t C h a r A r r a y
3. 4. 5. 6. 7. 8.
java.util.BitSet java.text.CompactStringArray java.util. Calendar java.text.CompactIntArray java.util.Vector java.util.GregorianCalendar
Except for the calendar classes we find t h a t the retrieved classes are not to dissimilar to strings at an abstract level, so we feel t h a t this is acceptable. We also did a search for a queue class as defined below:
class queue { Vector data;
157
int length; queue () ; void addElement (Object o) ; Object peek() ; boolean isEmpty() ; Object remove();
} We also specified that this was a queue A D T collection type. Quite surprisingly the search found a class s u n . m i s c . Queue t h a t we were not aware of. We were expecting to see one of the collecion classes of the j a v a . u t i l package, which does not contain a queue class in java version 1.1.4. Among the following most similar classes we found j a v a . u t i l . V e c t o r , j a v a . awt. L i s t , and j a v a . u t i l . Hasht a b l e . In the design patterns book by G a m m a et. al [9] there is a C + + description of classes t h a t are possible to observe, as a part of the observer pattern. We made J a v a versions for the signatures of such a class. The specification is given below: class subject { Vector observers ; subject(); void Attach(Observer o); void Detach(0bserver o); void Inform() ;
) The result of a search for a class like this was t h a t the most similar class was the j a v a . u t i l . 0 b s e r v a b l e class. Note t h a t the main similarity here lies in the return types and the argument lists, as the O b s e r v a b l e uses a d d 0 b s e r v e r , d e l e t e 0 b s e r v e r and n o t i f y 0 b s e r v e r s as names for the methods matched found in the target class. Even though the retrieval algorithm seems to give the wanted results, it takes some time. It takes approximately 13 minutes to run on the class libarary delivered with version 1.1.4 of the java development kit. This class library consists of over 1700 classes, and 7 of the 13 minutes was used to read the cases for each of these classes in from file to the internal memory. We believe we still can reduce the time to 2-3 minutes for a search in a repository this big by careful programming. P r o g r a m m i n g was done in java and the examples were run on a Sun SPARC 10 computer.
7
Related Research
There have been several a t t e m p t s to use case-based reasoning or analogical reasoning to support software engineering. Some of t h e m focus on the earlier phases of a software development process [14, 13, 18, 20], whereas others discuss the possibility of reuse of code by identifying similarity in designs or specifications,
158
assuming t h a t this similarity would lead to similarity in code [6, 21]. A couple of authors focus on case-based reasoning as a tool to enhance organizational learning in software factories [11, 2]. More typical case-based tools to support the coding phase are Bhansali and Harandi's work on synthesis of UNIX scripts [3], Fouqu~ and Matwin's work on the case-based reuse of C code blocks [8], and Ferns et al's work on retrieval of object-oriented classes combining information retrieval and case-based indexing techniques [7]. T h e last one is the most similar to ours approach as they also extract features from the component in the addition to the possibility to index cases manually. They use statistical techniques to identify i m p o r t a n t word combinations in documentation of a class and use these as their main features. Their reuse assistant uses both the extracted features and user-specified indices in search. If we compare their work to ours, we see t h a t it is similar in m a n y ways. However, we extract features directly from the class definitions of a class, without the need for neither high-level code or documentation. We also propose techniques to infer other features for a class, features t h a t would be given manually in Fern~ndezChamizo et al's reuse assistant.
8
Conclusions and Further Work
In this p a p e r we have presented the idea of using the reflective properties of the Java p r o g r a m m i n g language to support reuse of J a v a classes. This has given us the ability to extract signatures of methods, fields, and constructors in the classes, and use these to infer other features of the classes. In the paper we do this by inferring the canonical collection A D T a class represents. These features are then used for the retrieval of classes with the purpose of reuse by subclassing, modification, or direct use. The example runs indicate t h a t the described similarity measures work well and leads to wanted retrieval. To make the tool a full-fledged case-based reasoning tool we also need support for the reuse phase, i.e., to a d a p t the retrieved class to the new problem. We intend to continue our work to support this phase, with a particular emphasis on reuse by modification of code. We will also continue our work to integrate a J a v a interpreter, a class browser, and the case-based components of into a rapid prototyping workbench for Java programmers.
References 1. Agnar Aamodt and Enric Plaza. Case-based reasoning: Foundational issues, methodological vaxiations, and system approaches. A I Communications, 7(1):3959, 1994. 2. K.-D. Althoff, A. Birk, Gresse von Wangenheim, and C. Tautz. Case-based reasoning for experimental software engineering. In M. Lenz, B. Bartch-SpSrl, H.-D. Burkhard, and S. Wess, editors, Case-Based Reasoning Technology - From Foundations to Applications, pages 235-254. Springer-Verlag, 1998.
159
3. Sanjay Bhansali and Mehdi T. Harandi. Synthesis of UNIX programs using derivational analogy. Machine Learning, 10:7-55, 1993. 4. Ted Biggerstaff and Charles Richter. Reusability framework, assessment, and directions. In Ted J. Biggerstaff and Alan J. Perlis, editors, Software Reusability. Vol. I. Concepts and Models, chapter 1, pages 1-17. Addison Wesley, 1989. 5. Dennis de Champeaux. Object-Oriented Development Process and Metrics. Prentice-Hall, 1997. ISBN 0-13-099755-2. 6. Nachum Dershowitz. Programming by analogy, volume II of Machine Learning: An artificial intelligence approach, chapter 15, pages 393-421. Morgan Kaufmann Inc., Los Altos, California, 1986. 7. Carmen FernAndez-Chamizo, Pedro A. GonzAlez-Calero, Luis HernAndez-YAnez, and Alvaro Urech-Baqu@. Case-based retrieval of software components. Expert Systems with Applications, 9(3):397-405, 1995. 8. Gilles Fouqu@ and Stan Matwin. A case-based approach to software reuse. Journal of Intelligent Information Systems, 1:165-197, 1993. 9. E. Gamma, R. Helm, R. Johnson, and J. Vlissides. Design Patterns: Elements of Reusable Object-Oriented Software. Addison-Wesley professional computing series. Addison-Wesley Publishing Company, Reading, MA, 1995. 10. James Gosling, Bill Joy, and Guy Steele. The Java Language Specification. The Java Series. Addison-Wesley, Reading MA, 1 edition, 1996. ISBN 0-201-63455-4. 11. Scott Henninger. Tools supporting the creation and evolution of software development knowledge. In Proceedings of the 12th Annual Conference on Automated Software Engineering, pages 46-53. IEEE Computer Society Press, 1997. 12. J.L. Kolodner, R.L. Simpson, and K. Sycara-Cyranski. A process model of casebased reasoning in problem solving. In Proceedings IJCAI-9, pages 284-290, Los Angeles, CA, 1985. 13. N.A. Maiden and A.G. Sutcliffe. Exploiting reusable specifications through analogy. Communications of the ACM, 35(4):55-64, 1992. 14. Kanth Miriyala and Mehdi T. Harandi. Automatic derivation of formal software specifications from informal descriptions. IEEE Trans. Software Engineering, 17(10):1126-1142, 1991. 15. Tim O'Shea. The learnability of object-oriented programming systems. In OOPSLA '86 Proceedings, pages 502-504, New York, NY, September 1986. ACM, ACM Press. 16. Christos H. Papadimitriou and Kenneth Steiglitz. Combinatorial Optimization: Algorithms and Complexity. Prentice-Hall, Inc., Englewood Cliffs, N.J., 1982. 17. Rub@n Prieto-D~az. A software classification scheme. Technical Report 85-19, University of California, Irvine, Irvine, California 92717, 1985. Department of Information and Computer Science. 18. George Spanoudakis and Panos Constantopoulos. Analogical reuse of requirements specifications: A computational models. Applied Artificial Intelligence, 10(4):281306, 1996. 19. Sun Microsystems, Mountain View, CA. JDK 1.1.5 Documentation, 1998.
http: / /java.sun.com/products/ jdk /1.1/ docs/index.html. 20. Bjornar Tessem and Solveig Bjornestad. Analogy and complex software modeling. Computers in Human Behavior, 13(4):465-486, 1997. 21. R. Alan Whitehurst. Systematic Software Reuse Through Analogical Reasoning. PhD thesis, University of Illinois, Urbana-Champaign, IL, 1995.