Windows DevCenter    
 Published on Windows DevCenter (http://www.windowsdevcenter.com/)
 See this if you're having trouble printing code examples


Refactoring in Visual Basic 2005

by Matthew MacDonald, author of Visual Basic 2005: A Developer's Notebook
07/26/2005

Ever since Visual Basic developers heard about C# refactoring--a set of features that help developers restructure code--they've been green with envy. Surely it makes just as much sense to give VB'ers a similar set of refactoring tools for managing and modifying their code.

Although VB 2005 refactoring was a top developer request, the VB team had no way to fit in such a significant change late in the beta cycle. (Instead, they're hard at work putting the finishing touches on edit-and-continue and a library of more than 500 code snippets.) However, they came up with an innovative solution that might be just as good--partnering up with another company to include support for basic refactoring. Today, you can download a free version of Refactor, the Developer Express refactoring software. By the final release of .NET 2.0, Refactor will be included with Visual Studio, and you'll be able to buy a more configurable and extensible version of the same tool from www.devexpress.com.

Refactoring Basics

Refactoring is the one-size-fits-all name given to a set of coding shortcuts that help you rework code on the fly. The distinguishing characteristic of refactoring is that it's intelligent. For example, you're already familiar with basic IDE features like cut and paste or search and replace. The refactoring versions of these features understand VB syntax. That means they can dynamically tailor other portions of your code to keep it synced up and simplify your work.

The best way to learn to work with refactoring is to try it out. So download the free Visual Basic 2005 refactoring tool, and then experiment with some of the techniques in the following sections.

Visual Basic 2005: A Developer's Notebook

Related Reading

Visual Basic 2005: A Developer's Notebook
By Matthew MacDonald

Encapsulate Method

This refactoring trick is a great way to tame large blocks of code by splitting a portion off into a separate method. It's also one of the easiest refactoring tools to get under your belt.

Imagine you start with the following console application:


Module InvestmentCalculator

    Sub Main()
        Dim InterestRate, Years, FinalValue, MonthlyPayment As Double
        Console.Write("Interest Rate: ")
        InterestRate = Val(Console.ReadLine())
        Console.Write("Years: ")
        Years = Val(Console.ReadLine())
        Console.Write("Final Value: ")
        FinalValue = Val(Console.ReadLine())
        MonthlyPayment = Pmt(InterestRate / 12 / 100, _
            Months, 0, -FinalValue, _
                DueDate.BegOfPeriod)
        Console.WriteLine("Result: " & MonthlyPayment.ToString("C"))
    End Sub

End Module

The code here is quite straightforward. It asks the user to enter three pieces of information (an interest rate, number of years, and final value) and calculates the final value with compounded interest using the Pmt() function. The problem is that the calculation code is intermingled with the code for getting the user input and displaying the result. Although it's still manageable in this example, it's not hard to imagine a much more complicated set of calculations that would introduce some real organizational headaches. To start simplifying this code, you can use refactoring.

Once you've installed Refactor, you have three ways to trigger it. First, position your code to a place where refactoring is available. This part takes a little getting used to, but as you play with the tool you'll start to learn where the refactoring points are in your code (for example, in a variable declaration, a method declaration, and so on). When your code is in the right place, you'll see a small smart tag marker appear. In this case, start by selecting the content of the Main() method.

Now, simply click on this marker to pop open a menu with your current refactoring choices (see Figure 1). Alternatively, you can press Ctrl-tilde (~), or right-click on the program element and look for the Refactor submenu.

Figure 1
Figure 1. The refactoring tag

If you don't see the refactoring marker when you expect to, the problem could be an error in your code, as the refactoring smart tags won't appear if there's an active IntelliSense tag flagging an error.

In this example, choose Extract Method from the refactoring smart tag. A red arrow will appear in the editor window, which you can move using the up and down arrow keys (Figure 2). Once you've found the place where you want to create the new method, press the Enter key.

Figure 2
Figure 2. Positioning the new method

The refactoring tool will create a new method and replace the code in Main() with the method call. The name of the method is generated automatically based on the containing method, with the word Extracted added to the end. So in this example, refactoring creates a method named MainExtracted(). However, the name is highlighted in green, and you can change it by typing in a more suitable choice. As you type, both the method name and the method call will be adjusted (Figure 3).

Figure 3
Figure 3. Naming the new method

Once you're finished, you'll end up with this unspectacular result:


Private Sub CalculateInterest()
    Dim InterestRate, Years, FinalValue, MonthlyPayment As Double
    Console.Write("Interest Rate: ")
    InterestRate = Val(Console.ReadLine())
    Console.Write("Years: ")
    Years = Val(Console.ReadLine())
    Console.Write("Final Value: ")
    FinalValue = Val(Console.ReadLine())
    Dim Months = Years * 12
    MonthlyPayment = Pmt(InterestRate / 12 / 100, _
      Months, 0, -FinalValue, _
      DueDate.BegOfPeriod)
    Console.WriteLine("Result: " & MonthlyPayment.ToString("C"))
End Sub

Sub Main()
    CalculateInterest()
End Sub

This gives you the starting point for rearranging your code, but it doesn't offer much more. The input code and the calculation code is still thrown unceremoniously together in the same method.

But now that you understand the basic technique, you can also do something much more useful. To try this out, undo your changes so that you return to the initial code version. Then select just the calculation code, which in this case constitutes the following lines:


Dim Months = Years * 12
MonthlyPayment = Pmt(InterestRate / 12 / 100, _
  Months, 0, -FinalValue, _
  DueDate.BegOfPeriod)

Extract this method. Now the refactoring tool gets much more intelligent. It notices that the values you're using--InterestRate and Years--are defined elsewhere in the method and thus need to be supplied to the method. It also spots the fact that the MonthlyPayment result is displayed afterward, and so must be a return value. The resulting code is much closer to what you want:


Sub Main()
    Dim InterestRate, Years, FinalValue, MonthlyPayment As Double
    Console.Write("Interest Rate: ")
    InterestRate = Val(Console.ReadLine())
    Console.Write("Years: ")
    Years = Val(Console.ReadLine())
    Console.Write("Final Value: ")
    FinalValue = Val(Console.ReadLine())
    MonthlyPayment = GetMonthlyPayment(InterestRate, Years, FinalValue)
    Console.WriteLine("Result: " & MonthlyPayment.ToString("C"))
End Sub

Private Function GetMonthlyPayment(ByVal InterestRate As Double, _
  ByVal Years As Double, ByVal FinalValue As Double) As Double
    Dim MonthlyPayment As Double
    MonthlyPayment = Pmt(InterestRate / 12 / 100, _
      Months, 0, -FinalValue, _
      DueDate.BegOfPeriod)
    Return MonthlyPayment
End Function

In this example, you don't even need to rename the extracted method. The refactoring tool realizes you're returning a value that you've named MonthlyPayment, and defaults to the sensible method name GetMonthlyPayment().

Reordering Parameters

At this point, you might decide that you have a near-perfect method declaration, but you want to change the order of the parameters. To accomplish this, move to one of the variables in the function declaration:


Private Function GetMonthlyPayment(ByVal InterestRate As Double, _
  ByVal Years As Double, ByVal FinalValue As Double) As Double

When you select the refactoring tag, you'll see the option for reordering the parameters. Choose this. You'll now be able to slide variables from one place to another using the left and right arrow keys. When you've rearranged them the right way, press Enter. Here's one possibility:


Private Function GetMonthlyPayment(ByVal Years As Double, _
  ByVal FinalValue As Double, ByVal InterestRate As Double) As Double

The refactoring tool will show you all the places in the code where you call this method, and you can choose to change them individually (click on the checkmark icon) or all at once (click on the double checkmark icon). Without this tool, you'd be exposed to the possibility of error. Because all the variables are the same type, you might inadvertently keep a piece of code that calls the method but has these values in the wrong order.

Define Constant

The last trick I'll cover allows you to make your code more explicit by breaking down log lines of code. Currently, the Pmt() function performs an inline interest rate calculation.


MonthlyPayment = Pmt(InterestRate / 12 / 100, _
  Months, 0, -FinalValue, _
  DueDate.BegOfPeriod)

It might clarify your code to expand that with a separate variable. (And even if it doesn't, keep in mind that these tools are great for examples where your code is that much more complex--we've all seen hideously tangled lines of code that do too much at once.)

To refactor this code, move to the interest rate calculation and choose the refactoring option Introduce Local. You'll be prompted to name a new local variable, and will end up with this code:


Dim MonthlyInterestPercent As Integer = InterestRate / 12 / 100
  MonthlyPayment = Pmt(MonthlyInterestPercent, _
  Months, 0, -FinalValue, DueDate.BegOfPeriod)

You can use a similar technique to replace hardcoded values with constants.

Summary

To learn more about refactoring, surf over to www.devexpress.com/Support/BestPractices/IDE/Refactor, which has an exhaustive list of refactoring features. Or, better yet, download the Refactor 2005 tool and start experimenting.


In April 2005, O'Reilly Media, Inc., released Visual Basic 2005: A Developer's Notebook.

Matthew MacDonald is a developer, author, and educator in all things Visual Basic and .NET. He's worked with Visual Basic and ASP since their initial versions, and written over a dozen books on the subject, including The Book of VB .NET (No Starch Press) and Visual Basic 2005: A Developer's Notebook (O'Reilly). His web site is http://www.prosetech.com/.


Return to the Windows DevCenter.

Copyright © 2009 O'Reilly Media, Inc.