Lecture 8

Reading

Study guide

This lecture introduces refactoring, the process of  improving the internal structure of the code without altering its observational behavior. Refactoring is basically about cleaning up code and thereby improving the design of an existing program. The main hypothesis and motivation behind refactoring is that a well-designed program can easily accommodate change so cleaning up pays off in the long run. In this lecture we will discuss the definition, the motivation and some common objections against refactoring. We will show a few typical refactorings: both some very low-level ones and some more advanced ones. We will also discuss the idea of "code smells" or code aesthetics to show you how possible refactoring candidates can be picked out. Finally, we will talk briefly about how the refactoring activity can be adapted as part of a development process.

We expect you to read the article above by Jukka Viljamaa. It is a very brief and concise introduction to refactoring that lists both some of the key advantages and disadvantages. We have also included two excerpts from Fowler and Kerievsky to show what actual refactoring catalogues look like. Please read these excerpts as well since we will be discussing them in class and use them during the exercises. When you open the pdf files, remember that these documents were first used for the course "VOP2006F".

Auxiliary readings (for this lecture):

Exercises

The exercises this week will be based on a special CVS-branch of the UMLClassDiagramEditor with a couple of unfortunate design mistakes. You can download it here. The refactorings that we have sketched in the lecture have not been applied on this code, so it is your job to do exactly that. The purpose of this exercise  is to give you some hands-on experience with both low-level and high-level refactorings. In order to gain some further familarity with Visual Studio we suggest that you try comparing the results of manual and automatic refactorings.

Write the comments in a file called Refactoring.txt, that you will include in the next handin.

  1. (*) Locate the Write-method in the UMLClassDiagram-class and rename the method to WriteToFile or some other better suited name. Try doing this first manually and then with the help of the refactoring capability in Visual Studio. Why does Visual Studio suggest searching in comments and strings in the refactoring-wizard? Remember to compile and test aggressively during the process.
  2. (*) Locate the addClassButton_Click in the UMLEditorWindow-class and inspect the code. Extract the parts of the method body that does the naming of the new UMLClass. As before we suggest performing this refactoring both manually and automatically. Compile and test to verify that the refactoring succeded. Comment on the extra steps would be needed if the method was virtual and overriden in some subclass.
  3. (*) Locate the GetNoOfClasses-method in the UMLEditorWindow-class. Create a new, suitably named method in the UMLClassDiagram-class and move the body of GetNoOfClasses to the new target method. Consider whether you should leave the old method as a delegating method or if you should remove it? What influence could such a removal for instance have on a program with heavy use of reflection?
  4. (*) Perform the "Extract Superclass"-refactoring that we have shown in the lecture.
    1. Create a new empty class UMLElement in the UMLDiagram-namespace.
    2. Change UMLClass, UMLMethod and UMLField such that they have UMLElement as their superclass.
    3. This class should encapsulate commonalities among the different diagram elements. Pull up fields and properties such as Name, Visibility and possibly others from UMLClass, UMLMethod and UMLField to the new superclass. Remember to compile and test after each pull-refactoring.
    4. Describe how you handle private fields and properties.
    5. Inspect the rest of the program for clients of these classes. Consider whether these clients could possibly use the new superclass-type instead of the original subclass-types?
  5. (*) The NotifyClassChange and NotifyClass methods in UMLClass, UMLMethod and UMLField are somewhat similar. Perform the "Form Template Method"-refactoring that we have sketched in the lecture slides in order to pull up the common elements.
    1. Start by giving the NotifyClassChange and NotifyClass methods an indentical signature and name that conveys the purpose properly.
    2. Create an abstract method with this signature in UMLElement. Change the setter-part of the Name-property such that it references this new abstract method.
    3. Remove the Name-property from the subclasses.
  6. Locate the DrawClass-method in the UMLClassDiagramControl-class. This method is a classical example of the smell "Long Method" ("The longer the method the harder it is to understand it"). This method should be de-composed into several minor methods.
    1. We have put in two markers in the form of comments in the method body. Try and extract this code into a separate method named DoFields using the automated ExtractMethod-refactoring in Visual Studio. Why does Visual Studio suggest the use of ref- and out-parameters? Look these keywords up in the C# specification.
    2. Undo this refactoring. Inspect the method body again and find some suitable pieces of code to extract. Be very careful when performing these changes. Compile and test! (This may prove to be tricky).
  7. One of the refactorings in Visual Studio is "Extract Interface" which creates an interface with public methods and properties based on a given class. In this exercise, you should try and write a tool that can perform this operation such that people using notepad to write programs can also benefit from this operation. One suggestion would be to use reflection to extract information about public methods and properties and then format and write this info into a new .cs-file as a new interface. You can find some inspiration in this tutorial on C# attributes and reflection (here for instance)