Abstract:
A system and method for identifying viable refactorings of program code using a comprehensive test suite is presented. Program code is maintained, including program statements written in accordance with a programming language and defining operations executed following transformation into machine code. A test suite associated with the program code is specified and includes one or more additional program operations to determine satisfactory generation of expected results during the operations execution. A plurality of refactorings are speculatively applied to the program code by evaluating one or more of the program statements against a set of refactoring rules and restructuring the program statements pursuant to at least one refactoring rule. The test suite is executed against the program code following each restructuring of the program statements and each refactoring that passes the test suite is determined.

Description:
FIELD  
       [0001]     This application relates in general to program code refactoring and, in particular, to a system and method for identifying viable refactorings of program code using a comprehensive test suite.  
       BACKGROUND  
       [0002]     Commercial software development is a maturing discipline, which has historically been characterized by divergent approaches to design, coding, testing, and maintenance. Extreme programming, one of several emerging, so-called “agile methodologies,” attempts to unify the software development cycle into a holistic process to improve code quality and product viability, such as described in K. Beck, “Extreme Programming Explained: Embrace Change,” Addison-Wesley (2000), the disclosure of which is incorporated by reference. Extreme programming is practiced through simple design, small releases, metaphors, testing, refactoring, pair programming, and continuous integration.  
         [0003]     Refactoring is an inherent part of extreme programming and has been adopted to facilitate the process of adding features to existing program code. Refactoring, however, is not exclusive to extreme programming and can be applied to other software development methodologies. Refactoring is defined as the process of changing software such that the changes do not alter the external behavior of the code, yet improve the internal code structure. As a result, refactoring improves code design after the code has been written by removing duplication, improving communication, simplifying structure, and adding flexibility.  
         [0004]     Testing is also an inherent part of extreme programming, which divides testing into two categories. First, programmer or unit tests are written and maintained as part of the development activity in the same programming language as the code. Unit tests are integrated at the class level, preferably independently of each other and test the classes to verify complicated functionality and unusual circumstances. Unit tests also document code by explicitly indicating what results should be expected for typical cases. Second, user or acceptance tests evaluate the functionality of an entire system, generally as specified by a customer or end user. Acceptance are typically written in a scripting language or in the same programming language as the code to check the overall functionality of the program by treating the code as a black box and omitting specific knowledge of system internals. Acceptance tests touch at application programming and graphical user interfaces to apply domain-specific data. When properly written, unit tests and acceptance tests can form comprehensive test suites that can dynamically verify program correctness at runtime. As well, either unit tests or acceptance tests can, by themselves, be considered comprehensive when each point of functionality has a set of covering tests, which ensure correct functioning and show some resistance to easily foreseen faults.  
         [0005]     In contrast, refactoring is static activity that is conventionally applied to code as a structured, yet subjective methodology. In the general case, refactoring is as creative a process as the development of original program code. The critical points that distinguish general programming and refactoring are that: (1) the needed functionality is not changed as the result of the software changing, and (2) the software is improved in some way, such as being smaller, simpler, or made amenable to a subsequent development. Although refactoring can be applied to all forms of structured program code, refactoring is most effectively applied to object oriented code, preferably within the context of a testing framework. Refactoring can involve selecting and restructuring code according to well-accepted refactoring rules, such as listed in the catalogue of refactoring rules described in M. Fowler, “Refactoring Improving The Design Of Existing Code,” Chs. 6-12, Addison-Wesley (1999), the disclosure of which is incorporated by reference. The validity of refactoring rules can be determined through testing or semantic proofs, which can also be subject to assumptions regarding the code.  
         [0006]     Ideally, refactoring should be applied as a continuous process integral to the overall software development cycle. Identifying opportunities within code to apply refactoring is nevertheless subjective and relatively ad hoc, involving visual inspection and manual rewritings of code. Moreover, the set of refactoring rules chosen tends to be highly dependent upon the experience and preferences of the developers involved. Consequently, automated refactoring methodologies generally are conservative and apply only to those refactorings, which can be proven semantically correct, or can be proven semantically correct after making certain assumptions. Thus, the code is only evaluated within the context of literal class definitions and runtime constraints and other factors placed on the code in the dynamic environment are ignored during refactoring selection. In addition, automated refactoring methodologies require human initiation, often through the use of an integrated development environment. As a result, code refactored through automated methodologies often remains suitable for further refactoring.  
         [0007]     Therefore, there is a need for an approach to providing automated identification of a range of useable refactorings for code determined within a static and dynamic context. Preferably, such an approach would allow a wider range of refactorings than only those refactorings proven semantically correct and would apply comprehensive testing to validate the program correctness.  
       SUMMARY  
       [0008]     One embodiment provides a system and method for identifying viable refactorings of program code using a comprehensive test suite. Program code is maintained, including program statements written in accordance with a programming language and defining operations executed following transformation into machine code. A test suite associated with the program code is specified and includes one or more additional program operations to determine satisfactory generation of expected results during the operations execution. A plurality of refactorings are speculatively applied to the program code by evaluating one or more of the program statements against a set of refactoring rules restructuring the program statements pursuant to at least one refactoring rule. The test suite is executed against the program code following each restructuring of the program statements and each refactoring that passes the test suite is determined.  
         [0009]     Still other embodiments of the present invention will become readily apparent to those skilled in the art from the following detailed description, wherein are described embodiments by way of illustrating the best mode contemplated for carrying out the invention. As will be realized, the invention is capable of other and different embodiments and its several details are capable of modifications in various obvious respects, all without departing from the spirit and the scope of the present invention. Accordingly, the drawings and detailed description are to be regarded as illustrative in nature and not as restrictive. 
     
    
     BRIEF DESCRIPTION OF THE DRAWINGS  
       [0010]      FIG. 1  is a block diagram showing, by way of example, a development workstation upon which to execute automated refactorings.  
         [0011]      FIG. 2  is a process flow diagram showing the identification of viable refactorings of program code using a comprehensive test suite in accordance with one embodiment.  
         [0012]      FIG. 3  is a functional block diagram showing software modules for identifying viable refactorings of program code, such as used in the system of  FIG. 1 .  
         [0013]      FIGS. 4-8  are block diagrams showing, by way of example, pseudo code for a series of refactorings.  
         [0014]      FIG. 9  is a flow diagram showing a method for identifying viable refactorings of program code using a comprehensive test suite, in accordance with one embodiment. 
     
    
     DETAILED DESCRIPTION  
       [0000]     Development Environment  
         [0015]      FIG. 1  is a block diagram  10  showing, by way of example, a development workstation  11  upon which to execute automated refactorings. Program code  16  is written in accordance with the programming language on a development platform  11  and is refactored through a refactoring engine, as further described below with reference to  FIG. 3 .  
         [0016]     Preferably, the development platform  11  is a general-purpose computer executing an operating system and providing an application development environment. The development platform  11  includes components conventionally found in a personal computer, such as, for example, a central processing unit (CPU)  12 , display  13 , keyboard  14 , mouse  15 , and various components for interconnecting these elements. Further user interfacing means for inputting and displaying information from and to a human developer could also be provided. Program code, including software programs, and data is loaded into memory for execution and processing by the CPU and results are generated for display, output, transmittal, or storage.  
         [0000]     Process Flow  
         [0017]      FIG. 2  is a process flow diagram  20  showing the identification of viable refactorings of program code  16  using a comprehensive test suite in accordance with one embodiment. Processing occurs in five stages. Initially, the program code  16  is maintained (operation  21 ), generally as part of a software development project by a team of developers, who design, code, test and maintain the program code  16  within an integrated development environment. As an integral part of code design, the developers specify a comprehensive test suite (operation  22 ) that provides verification of correct program execution. Throughout the development process, the program code is speculatively refactored (operation  23 ) by applying one or more refactoring rules to restructure the program code  16  without affecting external behavior. During refactoring, the refactored code is continually tested (operation  24 ) using the comprehensive test suite, which verifies that the proposed refactorings do not alter the external behavior of the program code  16  as specified by the comprehensive test suite. Lastly, acceptable refactorings may be periodically presented to the developers (operation  25 ).  
         [0000]     Software Modules  
         [0018]      FIG. 3  is a functional block diagram  30  showing software modules for identifying viable refactorings of program code  16 , such as used in the system of  FIG. 1 . The development platform  11  includes a refactoring engine  31  and code tester  32 . The refactoring engine  31  applies refactorings by selecting one or more rules from a set of refactoring rules  36  to original program code  33 . The refactoring rules  36  specify improvements to the internal structure of the code without changing the external behavior of the code during execution. The refactoring rules  36  can be selected from a catalogue, such as described in M. Fowler, supra., and can also include other refactoring rules specified by the developers, including individual refactorings, which can be proven semantically correct or testably correct, or compound refactorings, such as described in commonly-assigned U.S. patent application Ser. No. ______, entitled “System And Method For Identifying Effective Compound Refactorings of Program Code through Quantitative Metric Analysis,” filed Dec. 3, 2004, pending, the disclosure of which is incorporated by reference. The refactoring engine  31  generates refactored code  34  after the application of each refactoring rule  36 . The refactored code  34  can include one or more refactorings, which each can include the application of one or more of the refactoring rules  36 .  
         [0019]     The code tester  32  tests the refactored code  34  to ensure program correctness using a comprehensive test suite  35 . The test suite  35  must be sufficient to subjectively satisfy the developers and can include unit tests, acceptance tests, or a combination of tests. Critically, the test suite  35  must be in an executable form to enable automated correctness testing, yet not be limited to ensuring only syntactic correctness. The code tester  32  determines that each of the refactorings applied to the original code  33  is acceptable if the refactored code  34  passes the test suite  35 . Those refactorings  37  that pass the test suite  35  may be presented to the developers. In addition, there may be other criteria for determining whether a refactoring should be presented to developers, as well as whether the refactoring is valid.  
         [0000]     Refactoring Examples  
         [0020]      FIGS. 4-8  are block diagrams showing, by way of example, pseudo code for a series of refactorings. Referring first to  FIGS. 4-6 , a syntactically correct but testably incorrect refactoring that can be speculatively applied is shown. Referring initially to  FIG. 4 , an original code segment  40  is shown and includes two non-parametered conditional statements, if (key.equals(“DESC”)) {something( );} and if (key.equals(“DESC”)) {something( );}, that represent potentially duplicated code. Referring next to  FIG. 5 , a first refactored code segment  50  is shown. The pair of conditional statements have been refactored by removing the conditional test values into separate assignment statements, string temp1=“DESC”; and string temp1=foo( ), and replacing the test values by the local variable temp1. Referring finally to  FIG. 6 , a second refactored code segment  60  is shown. The pair of assignment statements, string key=tok.next( ), has been “bubbled” downwards, attempting to increase the number of sequential identical statements the two code fragments have in common.  
         [0021]     While syntactically correct, the validity of this refactoring cannot be determined unless verified by testing or by programmer inspection because the reordering of the calls to foo( ) and tok.next( ) may or may not be valid. The refactoring might be invalid, for example, if the method foo( ) itself accesses or changes the state of the token input stream. This refactoring would be identified as improper upon execution of the comprehensive test suite  35  and would be backed out of the refactored code.  
         [0022]     Referring next to  FIGS. 7-8 , a second example of a syntactically correct but testably incorrect refactoring that can also be speculatively applied is shown. Referring initially to  FIG. 7 , an original code segment  70  is shown and includes a pair of assignment statements, Token t1=in.getToken( ), that receive values through a call on a method in.getToken( ) that reads an input stream in. Superficially, the assignment statements appear to constitute duplicated code. Referring next to  FIG. 8 , a refactored code segment  80  is shown. The pair of assignment statements have been refactored by replacing the calls on the input stream method in.getToken( ) with a local variable temp. In addition, the method call in.getToken( ) has been bubbled upwards and introduced in a new assignment statement, Token temp=in.getToken( ). While also syntactically correct, this refactoring is improper because the constraints on the ordering of calls on the input stream method call in.getToken( ) are ignored. This refactoring would also be identified as improper upon execution of the comprehensive test suite  35  and would be backed out of the refactored code.  
         [0000]     Method  
         [0023]      FIG. 9  is a flow diagram  90  showing a method for identifying viable refactorings of program code  16  using a comprehensive test suite  35 , in accordance with one embodiment. The purpose of the method is to speculatively refactor and test program code against a comprehensive test suite  35  to identify those refactorings, which are correct and viable and, therefore, worthy for presenting to developers working in an automated refactoring environment, depending on other criteria. The method is described as a sequence of process operations or steps, which can be executed, for instance, by a development platform  11 .  
         [0024]     Initially, the original program code  33  to be refactored and the test suite  35  are retrieved (block  91 ). In one embodiment, the program code  33  is written in an object-oriented programming language in conjunction with a framework that supports unit testing. In a further embodiment, the test suite  35  specifies acceptance tests written in a scripting language that can be executed against the refactored code  34 . The program code  16  is then speculatively refactored (block  92 ) by applying one or more refactorings through an automated process with each refactoring requiring the application of one or more refactoring rules  36 . The test suite  35  is executed against the refactored code (block  93 ) following one or more refactorings. If the refactored code does not successfully pass the execution of the test suite  35  (block  94 ), the refactoring can optionally be backed out of the program code  16  (block  95 ) or left in, if the refactoring is performed on a copy of the program code  16 . Otherwise, the refactoring is acceptable. Further refactorings could be speculatively applied (block  96 ) and, upon completion of the last refactoring, the refactorings are presented to the developers (block  97 ).  
         [0025]     While the invention has been particularly shown and described as referenced to the embodiments thereof, those skilled in the art will understand that the foregoing and other changes in form and detail may be made therein without departing from the spirit and scope.