Maintenance and modification of legacy software systems are the most costly activities in the life cycle of a long-lived system. Central to this activity are techniques for effectively finding and modifying code which implements features. The tool, Vue, is tailored to this need and has a state of the art graphical user interface to allow the maintainer or programmer to quickly locate code that is associated with features of the system.
In general, the first step towards software maintenance is to locate the code relevant to a particular feature. There are two methods of achieving this. First, a systematic approach can be followed which requires a complete understanding of the program behavior before any code modification. Second, an as-needed approach can be adopted, which requires only a partial understanding of the program so as to locate, as quickly as possible, certain code segments that need to be changed for the desired debugging/enhancement. The systematic approach provides a good understanding of the existing interactions among program features, but is often impractical in a real work environment due to the pressures of time and cost when working with large complicated software systems. On the other hand, the as- needed approach, although less expensive, may ignore some non-local interactions among the features and cause a program modification to result in disastrous side-effects. Thus, a need arises to identify those parts of the system that are crucial for the maintainer to understand. A possible solution is to read the documentation; however, in many cases, this may not be effective. The documentation may not exist; or even if it exists it may be incomplete, difficult to comprehend or not updated. Also, programmers/maintainers may be reluctant to read it. Perhaps a faster and a more efficient way of identifying the important segments of the code is to let the system speak for itself. It is this issue that the tool, Vue, attempts to address.
The execution slice-based technique is a solution which helps programmers and maintainers locate the implementation of different features in a software system. To find, for example, where the call forwarding feature is implemented in a telephone switching system, one would run a small, carefully selected, set of tests -- some that invoke the call forwarding feature and others that do not. Such tests are classified as invoking tests and excluding tests, respectively. Traces of program execution are analyzed to look for code components that were executed in the invoking tests but not in the excluding tests. Although this technique may not find all relevant code that makes up the call forwarding feature, it does identify a small number of program components that are unique to this feature. The identified code can then be used as a starting point for studying this feature. This is especially useful for those features that are implemented in many different modules in a large, complicated and poorly documented system.
It is important to note that code segments so identified rely heavily on the test cases used. Different sets of code may be identified by different sets of invoking and excluding tests. This implies poorly selected tests will lead to inaccurate identification by either including components that are not unique to the feature or excluding the ones that should not be excluded.
There are many ways in which execution traces of invoking and excluding tests may be compared to identify pieces of code that are related to a given feature, say f. One approach is to identify code that is executed by any invoking test case but not executed by any excluding test case. Another approach is to identify program components that are executed by every invoking test case but not executed by any excluding test case. The latter approach identifies only those program components that are always executed when feature f is exhibited but not otherwise. Another, simpler, approach is to compare the execution trace of just one invoking test with that of one excluding test. To minimize the amount of relevant code identified, the invoking test selected may be the one with the smallest execution trace and the excluding test selected may be the one with the largest execution trace. Depending on how features are implemented in the program, programmers/maintainers may have to try all these approaches, or construct their own approaches, in order to find the best set of code related to a given feature.
Ideally, the excluding tests used should be as similar as possible to the invoking tests in order to filter out as much common code as possible. To illustrate how to select the invoking and excluding tests, consider the example code in Figure 12-1. Suppose we want to find the code that is uniquely used to identify an equilateral triangle. We first construct an invoking test t1 that exhibits this feature and two excluding tests t2 and t3 which assign isosceles and rectangle, respectively, to class. Clearly, t1 is closer to t2 than t3. The difference between the execution traces of t1 and t2 shows that only statements s10 and s13 are unique to this feature, whereas additional code such as the statements s3- s7 would also be identified should t3 be used in place of t2 as the excluding test. Furthermore, this example also indicates we do not even need to use the feature that identifies a rectangle to find code that is unique to equilateral triangle. The ability to identify program components unique to a feature without even knowing all the program's features greatly enhances the feasibility of using the execution slice technique to quickly highlight a small number of program components.
12.2 A Tutorial
The use of Vue is most easily understood by an example. In this chapter we use the same
wordcount program as used in the previous chapters to illustrate how the basic features of
Vue can be used in identifying functional features. To copy these files, create a new
directory, cd to it, and copy the contents of the directory in which the tutorial files are
installed into the new directory.
After the compilation, two .atac files (main.atac for main.c and wc.atac for wc.c) and the
executable wordcount(.exe) are created. Note one .atac file is created for each instrumented
.c file, i.e., the .c files compiled with atac cc.
prompt:> xsuds *.atacThen, pull down the ``Tool'' menu and select the ``xvue'' option. Figure 12-2 shows the initial main window of Vue.
|
prompt:> wordcount -x input1 (wordcount.1) prompt:> wordcount -wlc input1 (wordcount.2) prompt:> wordcount -wl input1 (wordcount.3) prompt:> wordcount -w input1 (wordcount.4) prompt:> wordcount nosuchfile (wordcount.5)
The file input1 contains the following line:
test input file 1After the execution, a trace file wordcount.trace is created containing the execution information used in feature analysis.
To tell Vue to incorporate the dynamic information from this trace file into its display, click with the left mouse button on the ``File'' button in the top button bar. This will cause the ``file'' menu to pop-up. Click on the ``open trace file...'' entry in the menu. This will open a dialog box as shown in Figure 12-3. (The Windows dialog box looks slightly different.) Select wordcount.trace and click on the ``Open'' button. This will cause Vue to read in the trace file.
|
|
prompt:> wordcount -c < input2 (wordcount.6) prompt:> wordcount -l input3 (wordcount.7)
Running these two additional tests causes their dynamic information to be added to the trace file. Note that Vue has highlighted the ``Update'' button in the top button bar, as shown in Figure 12-5, to alert you to this fact. Vue continuously monitors the specified trace files to see if any new information has been added to them. If so, it highlights the ``Update'' button to indicate this to you. You may choose to click on this button now to update the display with the information from the test case you have just run, or you may choose to wait until you have run several test cases.
|
|
|
Tests wordcount.3, 4 and 7 do not involve this feature. Thus, they should be categorized as excluding tests. To achieve this categorization, select wordcount.3 by clicking on it with the left mouse button and then with the right arrow button between excluding_tests and dont_know. Apply the same procedure on wordcount.4 and wordcount.7. This will move wordcount.3, 4 and 7 from the dont_know category to the excluding_tests category. For tests wordcount.1 and wordcount.5, suppose we don't care. Hence, they remain in the dont_know category. Figure 12-8 shows the resulting display. If all the information is correct, click on the ``ok'' button to close this editing window. This will update the main Vue window as shown in Figure 12-9.
|
|
You can save the present feature description in a file by clicking on the ``save_as'' button in the middle button bar. This will cause a dialog box to appear as shown in Figure 12-10. (The dialog box on Windows looks slightly different.) Enter wc as the name of the file in the rectangle next to the label File name and click on the ``Save'' button. A file named wc.features is created in your working directory containing all the feature descriptions you have entered. (The file extension .features is appended automatically by Vue.) Once you have saved your feature description in a file, you can update it by simply clicking on the ``save'' button in the middle button bar. Vue will reuse the last selected file name and overwrite it with the latest feature descriptions.
|
To delete a feature, select it by clicking on it, (character_counting in our case) and click on the ``delete'' button in the middle button bar. A dialog box as shown in Figure 12-11 will appear. If you wanted to confirm the deletion, you would click on the ``yes'' button. This would cause the selected feature to be deleted and the main Vue window to be updated accordingly. Since we do not want to delete the feature, click on the ``cancel'' button to close the dialog box and return to the main window of Vue as displayed in Figure 12-9.
|
To use features that were previously saved in another feature file, click on the ``open'' button in the middle button bar. This will cause a dialog box to pop up as shown in Figure 12-12. (The dialog box for Windows looks slightly different.) You would select the file which contains the feature(s) to be imported and then click on the ``Open'' button to have them displayed in the main window of Vue. In our case, there is no need to do so because the feature (character_counting) is already displayed. So, click on the ``Cancel'' button to close the dialog box and return to the main window of Vue as displayed in Figure 12-9.
|
The next step is to answer the question: ``Where in wordcount is feature character_counting (i.e., the -c option) implemented?'' To look for program components that are uniquely related to character counting, first select this feature by clicking on character_counting under the ``Feature Name'' button and click on the ``heuristics'' button in the middle button bar. This will cause a heuristics window to appear as shown in Figure 12-13.
|
You can switch to heuristic B or heuristic C as shown in Figure 12-14, by clicking on the corresponding button with the left mouse button. With heuristic B, program components that are commonly executed by all invoking tests (wordcount.2 and wordcount.6 in our case), but not any excluding test (wordcount.3, wordcount.4 and wordcount.7 in our case), are identified. In other words, program components that are in the intersection of wordcount.2 and 6, but not in the union of wordcount.3, 4 and 7, are identified. With heuristic C, program components that are executed by the smallest invoking test (wordcount.6 in our case), but not by the largest excluding test (wordcount.3 in our case), are identified.
|
|
The source code of main.c is displayed in Figure 12-16. The scroll bar is a thumbnail sketch of the entire file indicating there are two red spots. Clicking with the left mouse button at any spot in the scroll bar brings the corresponding region of the file into the source window. You can use the arrows at the top or the bottom of the scroll bar to scroll up or down the source file a few lines at a time. You can also drag the mouse up or down the scroll bar with the left mouse button pressed to rapidly scroll up or down the file. In addition, Vue also provides keyboard shortcuts. Pressing the Up or Down arrow key will move the file up or down one line at a time. The PageUp and PageDown keys scroll up and down the file one page at a time, respectively. The Home key scrolls to the beginning of the file, whereas the End key goes to the end of the file.
|
The display in Figure 12-16 shows the resulting code after the first red spot is selected. Analysis of the code reveals that all the highlighted blocks are indeed ``unique'' to the character_counting feature (the -c option).
Similarly, you can view the feature at the decision, c-use or p-use level by selecting the corresponding criterion from the ``Options'' menu as shown in Figure 12-17. For example, the decisions in main.c that are unique to character_counting are shown in Figure 12-18. For each highlight, Vue can further indicate which branch of it is uniquely related to a given feature. In our case it is the true but not the false branch of dochar that is unique to character_counting.
|
|
You can make your own customized heuristic by moving tests around as shown in Figure 12-19. In this case, program components that are executed by wordcount.2 but not wordcount.3 are identified. Recall that test wordcount.2 is:
prompt:> wordcount -wlc input1 (an invoking test)and test wordcount.3 is
prompt:> wordcount -wl input1 (an excluding test)
|
In some situations, the highlighted code may be a super set of the unique code with respect
to a certain feature. Nevertheless, code so selected provides a good starting point for
mapping features to program components at different levels of granularity.
prompt:> xsuds *.atac *trace *featuresto import them directly as command line arguments instead of loading them interactively through the graphical interface.