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):
- "Refactoring
Object-Oriented Frameworks" by Bill Opdyke, 1992. Opdyke coined the
term "refactoring" in his PhD-dissertation. It is one of the first systematic
account of refactoring.
- "Roots
of Refactoring" by Jan Philipps and Bernard Rumpe in Tenth OOPSLA
Workshop on Behavioral Semantics. Tampa Bay, Florida, USA, October 15, 2001.
This article traces the history of refactoring and its relations to such fields
as refinement and compiler optimization.
- "A
Survey of Software Refactoring" by Tom Mens and Tom Tourwé
in IEEE Transactions on Software Engineering, Volume 30, Number 2, February
2004, pages 126-139. A rather recent and very comprehensive survey.
- "Refactoring to
Patterns" by Joshua Kerievsky, Addison Wesley, 2004. Kerievsky's
book is a catalogue of Java-refactorings, the focus is on high-level
refactorings, close to real life scenarios.
- "Refactoring
- Improving the Design of Existing Code"
by Martin Fowler et al., Addison Wesley, 1999. This book contains
a catalogue of mainly low-level refactorings in Java. Martin
Fowler also has a
site on refactoring that complements the book with links, references and
news.
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.
- (*) 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.
- (*) 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.
- (*) 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?
- (*) Perform the "Extract Superclass"-refactoring that we have shown
in the lecture.
- Create a new empty class UMLElement in the UMLDiagram-namespace.
- Change UMLClass, UMLMethod and UMLField such that they have UMLElement
as their superclass.
- 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.
- Describe how you handle private fields and properties.
- 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?
- (*) 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.
- Start by giving the NotifyClassChange and NotifyClass methods an indentical
signature and name that conveys the purpose properly.
- 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.
- Remove the Name-property from the subclasses.
- 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.
- 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.
- 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).
- 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)