|
|
< Day Day Up > |
|
Even if the preventative measures are followed, you will encounter instances of cut-and-paste that requires reworking. Mistakes can be made, or sometimes it is not worth it initially to
Refactoring is a balancing act between the work expended refactoring and the work saved by the refactored code. There can be no hard-and-fast rules that always apply, but you can follow guidelines as you learn for yourself when refactoring actually
The simplest case occurs when you create the
What happens when you suddenly realize that there is another instance where you require similar code? Refactoring should definitely occur here;
Now we move on to the more difficult topic of refactoring legacy code, which generally comes from a past project. We will assume that the code is currently working; otherwise, refactoring would be required regardless and you should consider scrapping the old code entirely and writing your own. At this point, you might be thinking, if it’s not broke, why fix it? There are several reasons to consider refactoring legacy code. Start by considering what to do when you discover that code you modified also exists in another location. Chances are you want to make the changes in both locations. This is a good time to go looking for more copies, particularly if the ones you did find did not comment on the duplication. This is an indicator of poor coding practices and it would not be surprising to find multiple cut-and-paste copies.
Because duplicate code can cause considerable problems and be difficult to track down, it is a good idea to consider refactoring an entire module if you expect to make major changes to that module. This also can lead to a better understanding of what the module does and how.
One of the reasons why many programmers avoid refactoring is the tedium of making the necessary modifications, which can sometimes involve sweeping changes that cover large sections of the code base. Without the necessary refactoring work, cut-and-paste code is easy to create and can have long-
The optimal tool for refactoring must understand the language that is being refactored and provide support for common refactoring operations. An example of this, and one of the first refactoring tools available, is the refactoring browser for the Smalltalk language. The refactoring browser allows refactoring to be achieved with minimal work from the programmer by automatically taking care of aspects such as renaming and temporary
Other languages generally do not offer such strong support for refactoring tools, but this will change over time. Java is perhaps the only other language to have robust refactoring tools available, among them the IDEA integrated development environment from IntelliJ. IDEA supports many standard refactoring operations in the Java language, removing the need for
A couple of examples should provide a better understanding of the true advantages provided by refactoring tools in IDEA. We will start with a simple renaming example for the following class:
public class RenameField { boolean fieldToRename; // ... RenameField(boolean renamedField) { fieldToRename = renamedField; } // ... }
Now we want to change the
public class RenameField { boolean renamedField; // ... RenameField(boolean renamedField) { renamedField = renamedField; } // ... }
Notice the assignment renamedField = renamedField, which should be this.renamedField = renamedField. However, by invoking the Rename refactoring in the IDEA interface, it correctly handles the change, resulting in:
public class RenameField { boolean renamedField; // ... RenameField(boolean renamedField) { this.renamedField = renamedField; } // ... }
Now let us look at a slightly more complex example. We start with the following class:
class ExtractMethod { int length; int width; // ... boolean isLargerThan(int height, int volume) { return(volume < length * width * height); } // ... }
Now imagine we want to use the volume calculation for another function. Since we do not want to duplicate the code involved, we select length * width * height and apply the Extract Method refactoring option to that. This results in the following functions with the only
boolean isLargerThan(int height, int volume) { return(volume < volume(height)); } private int volume(int height) { return length * width * height; }
Notice that it correctly creates the necessary parameter and
Other languages do not have as complete of support for refactoring, but there are still tools available that can help. The first tool that is a necessity is a good multiple-file search utility, which is included in most modern integrated development environments (IDEs). While you might be tempted to look for a multiple-file
While human involvement will still be necessary for a long time to come, it is possible to perform some refactoring to remove code duplication using an automated process. This automatic restructuring of code would provide considerable benefits to the development process by removing the
A taste of what is to come can be found by looking at Guru , a hierarchy-restructuring tool for the Self programming language. This tool was developed at the University of Manchester as part of the PhD research of Ivan Moore. This is an initial example of automatic refactoring of an object-oriented language. Expect automated refactoring to eventually become a standard part of future IDEs.
When we talked about premature optimization, the importance of testing was stressed to achieve maximum optimization with minimal risk. The same treatment of testing applies when dealing with cut-and-paste. Fixing cut-and-paste code often involves major changes to the application code, but this should produce no changes in application functionality. A proper set of application functionality tests can minimize the risk that this will occur. These tests should be automated and run after each individual change, as with any other form of refactoring. Throughout this book, the importance of testing will continue to be stressed. Although this might seem repetitive, testing is an extremely important and often overlooked aspect of minimizing development risk. If you are not already using at least a minimal set of tests, you would be well advised to consider how testing can be integrated into your development process.
Just as with the automation of cut-and-paste operations, the majority of tests should be automated as well. In this case, minimizing human involvement is not so much to prevent error, although that is a concern, but to make it less bothersome to perform the tests. Without this necessary step, many programmers will often skip the testing phase of coding and just pray that the code works. This can be disastrous,
|
|
< Day Day Up > |
|