Two primary factions have polarized Visual Basic: VB6 programmers and OOP programmers. VB6 programmers want VB to be really easy to use; OOP programmers say VB needs to be as powerful a language as C# or C++, or VB is just a toy. VB can’t be a hobbyist’s language and a full-blown object-oriented language at the same time, and Microsoft can’t figure out which constituency to satisfy. So right now, VB is trying to be both. For example, VB.NET includes multithreading and operator overloading, but the IDE doesn’t support VB refactoring. Adding the My feature panders to VB6 programmers, whereas adding operator overloading appeals to OOP programmers. However, Microsoft recognizes that excluding IDE Refactoring support in VB was an oversight and has made Refactor! for VB.NET available as a free download.
What is Refactoring? To paraphrase Martin Fowler, Refactoring is a constructive means of improving the internal structure of code without changing its external behavior. (Martin Fowler is the public voice of Refactoring; William Opdike is considered the inventor.)
Where do I stand? Toy languages are for toy makers. Toy makers have their place (especially at Christmas time), but I have real business solutions to solve and can create toys with business-grade tools but cannot create business-grade tools with toys.
You don’t have to agree with my perspective, but you should know about Refactoring because even cobbled together applications can become very complex; Refactoring is a disciplined way to restore existing code without changing its behavior. Both restructuring and maintaining behavior are critical tenets of Refactoring.
Reasons to Refactor
Refactoring guides you through “uncomplicating” code without breaking or changing it. Each Refactoring has a stated motivation, steps that indicate how to complete the Refactoring, and the desired outcome. Some Refactorings are based on existing techniques whereas others are based on new techniques, but all Refactorings have been named and clearly documented.
An example of a common Refactoring is Encapsulate Field. Encapsulate Field means to take public variables, make them private, and then provide access to them through functions. This Refactoring is so well established that it has been codified as a modern property. That said, some programmers still use public fields, even though this practice generally is eschewed. (My article “Write Macro Code Generators with VS 2005” demonstrates how you can implement Encapsulate Field with VB Macros.)
Visual Studio .NET 2005 supports Refactoring in C# but not in VB.NET 2005. However, VB developers don’t have to write their own Refactoring tools anymore thanks to a neat tool called Refactor! for Visual Basic, a free download from Microsoft. While you can complete any Refactoring manually, tools make them easier, more foolproof, and quicker—plus, they can be fun to use. (Lord knows work needs to be more fun.)
The remainder of this section demonstrates three Refactorings using Refactor! for Visual Basic .Net 2005 version 1.0.31: Encapsulate Field, Extract Method, and Create Overload. (For a complete discourse on Refactoring, see Martin Fowler’s Refactoring: Improving the Design of Existing Code from Addison-Wesley.)
Refactoring: Encapsulate Field
The motivation for Encapsulate Field is the belief that public data is bad—think having-your-heart-outside-your-ribcage bad. To complete Encapsulate Field, change a public field to a private field and add accessor methods for reading and writing the value of the now private field. The getter and setter in VB.NET are really just convenience notations for methods that permit you to externally treat a property like a field while calling methods. The methods mean you can wrap checks around the field.
Suppose you have a public field called HeartRate that modulates a patient’s heart beats per minute. Bad code could set HeartRate to 500 and, like Emeril says, “Bam!” the patient is dead. To prevent HeartRate from being set too high, you could protect it behind property methods. You could right-click on the field HeartRate, select Refactor!, and Encapsulate Field. You would see changes to your IDE similar to those in Figure 1. You then would use the down arrow to move the target picker (the red arrow and line) to the insertion point and press Enter. The revised code would look like Listing 1.
Figure 1: Refactor! Uses Very Good Cues to Guide Your Use of the Tool
Listing 1: The HeartRate Field Has Been Encapsulated by Refactor!
Public Class WillRefactor
Private HeartRate As Integer
Public Property HeartRate1() As Integer
Set(ByVal value As Integer)
HeartRate = value
In the revised code in Listing 1, HeartRate cannot be changed without using the public property HeartRate1. To ensure that HeartRate isn’t set too high, you could add some conditional code to the Set method.
Refactoring: Extract Method
One of the most common problems with code is having functions that are too long. Small functions can be reused and more easily re-orchestrated into new
behaviors. Long, monolithic functions often can be used only under very tight constraints. To make code more reusable, you can extract chunks of code into
named methods. In addition to these named methods being more reusable, the names more clearly explain the purposes of the methods.
To use Extract Method, select a fragment of code that you’d like to convert to a named method, right-click over the selected code, and pick
Refactor!|Extract Method. To demonstrate, I use a simple for loop that writes HeartRate to the Console 100 times.
If you have only one available Refactoring, use One Key Refactoring by typing Ctrl+~, which invokes the Refactoring and shows an Action Hint (see Figure
2). Again, move the target picker above or below its current location and press Enter. After pressing Enter, the method PseudoLongMethod and the new
extracted method are revised, as shown in Listing 2.
Figure 2: The Currently Available Refactoring and the Action Hint, Extract Method
Listing 2: The Method PseudoLongMethod Is Refactored, Making BunchOfCode a Separate Method
Imports System.ServiceProcess Public Class WillRefactor Private HeartRate As Integer Public Property HeartRate1() As Integer Get Return HeartRate End Get Set(ByVal value As Integer) HeartRate = value End Set End Property Public Sub PseudoLongMethod() ' a bunch of code BunchOfCode() End Sub Private Sub BunchOfCode() Dim I As Integer For I = 1 To 100 Console.WriteLine(HeartRate) Next End Sub End Class
Refactoring: Create Overload
Suppose that BunchOfCode were defined to accept a Count parameter. (Count is used as the upper limit for the loop.) Further suppose that in some cases a
default value is known. You can right-click BunchOfCode (see Listing 3) and select Refactor!|Create Overload to create a new method that overloads
BunchOfCode and calls the original method with a default value (see Listing 4).
Listing 3: A New Version of Bunch of Code with a Single Parameter
Private Sub BunchOfCode(ByVal count As Integer) Dim I As Integer For I = 1 To count Console.WriteLine(HeartRate) Next End Sub
Listing 4: The Old and New Overloaded BunchOfCode Method Created by Refactor!
Private Sub BunchOfCode(ByVal count As Integer) Dim I As Integer For I = 1 To count Console.WriteLine(HeartRate) Next End Sub Private Sub BunchOfCode() Dim lCount As Integer = 0 BunchOfCode(lCount) End Sub
Refactored Code Is Good Code
Refactoring is important not because the underlying techniques are all new, but because the techniques are described and the motivation and desired
outcomes are clearly state. Refactoring can improve the internal structure without changing the external behavior of existing code. It removes the
subjectivity of what is good code and what is less-good code: Refactored code is deemed good, and code that is not Refactored is deemed less good. (Perfect
code probably does not exist.)
More important than whether code is good or bad is whether it works. Refactoring increases the likelihood that code will continue to work as it grows and
About the Author
Paul Kimmel is the VB Today columnist for www.codeguru.com and has written several books on
object-oriented programming and .NET. Check out his new book UML DeMystified from McGraw-Hill/Osborne and his upcoming book C# Express for the
Professional Programmer from Addison Wesley (Spring 2006). Paul is an architect for Tri-State Hospital Supply Corporation. You may contact him for
technology questions at email@example.com.
If you are interested in joining or sponsoring a .NET Users Group, check out www.glugnet.org.
Copyright © 2005 by Paul T. Kimmel. All Rights Reserved.