AddThis Social Bookmark Button

Listen Print

Fifty Ways to Improve Your Visual Basic Programs

by J.P. Hamilton
09/27/2001

If you are fairly new to Visual Basic, here are 50 things you can do today to make your VB code more effective and easier to maintain. Although there are usually exceptions to anything called a rule, my intent is to help you learn from my experience programming with VB. I'll go into great detail on some items, while others will take the form of general advice. If you find that I am being vague, it is probably for one reason: I want you to research it yourself. And honestly, I don't have the space to discuss everything that I would like to cover in detail.

I don't expect you to agree with everything presented here. Programmers can be passionate about their beliefs as to what is good or bad. But hopefully, there is a tidbit or two you can take with you and use to improve your VB programs.

I originally submitted many of the topics discussed in this article as a book idea to O'Reilly. But shortly after, .NET appeared on the scene, and doing a whole book was not a viable option any more. Many of these topics can be adapted for .NET, but some will not be applicable. Regardless, this discussion is targeted towards the beginning Visual Basic programmer that is already writing code.

No doubt you will look at some of these topics and say, "Well, of course you should do that!" or "Who the - does that?" Every single one of these topics is something that I do, or something I have seen done in corporate America, where I work as a contract software architect and developer. With that said, let's get to the tips.

The Basics

  1. Use error handling everywhere. Whether you are writing a function or simply accessing a simple property, define an error handler using On Error Goto. This should look similar to the following:

    Private Sub Encryptolizer()
    
        On Error GoTo Errs
        
        'Code goes here
    
        Exit Sub
    Errs:
        'Call error handler here
    End Sub
    

    Even if your Function, Property, or Sub only contains one stinking line of code, put that error handler in there. The drawback to this is a substantially larger executable. The benefit is code that will eventually have little to no errors. The error handler itself can be a standard function located in a module or a class that encapsulates all of the required functionality of the handler.

    Related Reading

    VB Shell Programming
    Integrating Applications with the Windows Shell
    By J.P. Hamilton

    Table of Contents
    Index
    Sample Chapter

    Read Online--Safari Search this book on Safari:
     

    Code Fragments only

    However you decide to implement it, make it as robust as possible. And try this: Next time you start a project, write the error handling code first, so that it is in place. If you treat your exception handling code as the most important part of an application (it is actually) instead of as a footnote to be tacked on at the end of the development cycle, you will be amazed at how strong your application will be by the time it goes to testing.

  2. Never use On Error Resume Next. Using On Error Resume Next not only violates "tip #1", it also makes code difficult to debug. This statement should be avoided at all costs. It breeds the most hard to find and unpredictable bugs you could ever imagine. And for those of you who know assembly language, try disassembling code with an On Error Resume Next statement embedded in it. What you will find is a massive jumble of spaghetti code that is injected into the function by the compiler in order to implement this functionality. Imagine a 9-year-old programmer who likes GoSub and Goto and you will get the idea.

  3. Indent, use white space, and comment your code. This is a simple suggestion meant to make your code more readable. First, all code should be indented once (4 spaces) within the block where it resides. Second, all code should have at least one line of white space separating it from the block where it resides. Third, declare all variables on their own line so that they can have comments associated with them. It can also be beneficial for large blocks of code to have a comment on the End statement (End If, Loop, etc) of the block that points to the start of the block. Well-formatted code looks like this (squint your eyes and pretend that the function does something):

    Public Function CrispAndClean() As Boolean
    
        On Error Goto Errs
    
        Dim x As Integer    'x coordinate
        Dim y As Integer    'y coordinate
        Dim z As Integer    'z coordinate
    
        If (x > 10) Then
    
            If (z < 20) Then
    
                'code starts here
    
            End If
    
        Else
    
            x = x * 10
            y = y * 20
            z = z * 30
           
        End If    'If (x > 10) Then
    
        Exit Sub
    
    Errs:
        'Error handler here
    
    End Function
    
  4. Know the language. There are many great functions hidden away in VB that you may not know about. Spend time learning the language. The VB help file is a great place to start. Go to the index, start at the top, and read about any keyword you don't know. After you have done that, get a solid desktop reference. Hands down, VB & VBA in a Nutshell is the best language reference on the market. Believe it or not, that is my unbiased opinion. I owned a copy before I ever wrote a single word for O'Reilly.

    This topic comes up for a reason. One time I was working on a project with a really great programmer, who was in the process of writing a really great string parser. Imagine his surprise when I showed him the Split function. Amazingly enough it could do in one line of code what his was doing in over 20. Needless to say, he chucked his code out the window.

    Believe it or not I meet people all the time who have never heard of Split, Join, InStrRev, or Filter.

  5. Avoid legacy BASIC. Do your part to rid the world of legacy BASIC. Avoid using DefInt, GoSub, QBColor, REM, and Let. And unless you are writing an application with accessibility considerations, consider avoiding Beep as well. Users find it annoying. Also, avoid declaring data types with suffixes instead of the name of the data type:

    Dim name$    'This looks like my old Atari 800 code
    Dim num%     
    Dim bignum&
    

    I mention the declaration syntax for reasons of clarity. A good rule of thumb is that you should always be clear versus, well, not being clear. Don't be afraid to type. I almost forgot, don't put more than one statement on the same line:

    If x = 4 Then: x = 5: y = 6
    

    Nobody likes reading code like this.

  6. Don't sacrifice maintainability for speed. There are many things that can be done in VB to make an application run faster. Global variables, undocumented pointer functions, and loop unrolling are just a few. Unless you are maintaining your own code for your own software company avoid these things and try to make your code as readable as possible. If you work in the corporate world this is very important. The person who inherits your code when you've moved on to greener pastures will praise your name instead of curse you. Believe me, the folks who pay you don't care how slick you can code. Ultimately they want something that will not only work, but is flexible and easy to maintain. If you are doing something that requires intimate knowledge of the black arts of coding, don't do it.

Variables and Declarations

  1. Always use Option Explicit. By default, VB is set for Sloppy Mode. In Sloppy Mode, variables don't have to be declared before they are used. Why is this bad? It leads to some really hard to find bugs should you happen to misspell a variable name:

    Public Function Vague()
    
        position = (x * y) + 5
    
        'more code here
    
        If (positon > 10) Then
    
            'This code will never be executed
            'because "position" is misspelled
    
        End If
    
    End Function
    

    To take VB out of Sloppy Mode, open the Tools/Options dialog from the menu. On the first tab, named Editor, check the option that says "Require Variable Declaration". If you are doing this after you have already started a project, make sure any forms, classes, or modules that you have already created have Option Explicit at the top of the file.

  2. Don't use Hungarian notation. Gasp! I am going to go against popular opinion on this and argue against using Hungarian notation in any way, shape, or form. This is my opinion, but I think well named variables are better. I am actually a recent convert to the dark side. I used to use Hungarian notation religiously, but I have since been shown the error of my ways.

    The first reason I will give you is that the design guidelines for the up and coming .NET framework say not to use it. It would be an easy cop out to say that this is the reason this tip exists; that I am just preparing you for the future. And anyway, everything in .NET is an object. You can't really go around putting an "o" in front of everything can you?

    But there are other reasons:

    • VB is not coded outside of the VB IDE. I am sure there are a few renegades out there that use vi for Windows, but for the other 99.9% of us, the IntelliSense built into the IDE works just great for telling you the type of all your variables.

    • Another argument for using Hungarian notation is: "When I print out my code to read it I want to be able to see what I am dealing with". This is a valid argument. On the other hand, some people prefer looking at well-named variables instead of a bunch of gobbledygook.

    • What if the data type changes? You have explicitly tied the variable name to its type. In addition to having to re-declare your variables to the new type, you have to change every single place where the variable was used to use the new Hungarian prefix. Think about the repercussions of this. Some of you out there will say that global find and replace was created for things like this. But I say that this is a clue that Hungarian notation is lacking.

  3. If you are going to use Hungarian notion anyway, maintain style. Use the same style that is being used in the project. If everyone else is prefixing integers with an n, follow suit. If you are the only one on the project, at least make sure your style is consistent. Read this Microsoft document for more information.

  4. Don't use hard-coded values. Avoid using literal values always. Even if you know a value will never change, you should at least use a constant.

  5. Don't use global variables. Global variables lead to global problems, especially when you are working on a large project with several developers. However, in some circumstance a global will be necessary. There are "just those times" when you need to get something done instead of designing the application properly (this is a barb, yes). In these cases, create accessor functions to get to the global instead of using it directly:

    'Global
    Public GlobalNumber As Integer
    
    'Accessor functions
    Public Function Get_GlobalNumber() As Integer
        Get_GlobalNumber = GlobalNumber
    End Function
    
    Public Function Set_GlobalNumber(ByVal number As Integer)
        GlobalNumber = number
    End Function
    

    It is especially important to do this if your global variable needs to be validated in anyway. But unfortunately there is no way to force other developers to use the accessor methods. When faced with a situation like this, ask yourself why GlobalNumber isn't a private member of a class like it should be.

  6. Think small. What does this mean exactly? It means several things. One, it means that you should strive to limit the scope of all your variables as much as possible. In the ideal situation every variable is private.

    Two, make your class interfaces as small as possible. Accomplish as much as you can with the fewest number of public functions that have the smallest number of parameters (tip 15 is the exception).

  7. Expose as little as possible. The more that is hidden from the outside world, the more flexible your code will be. This is most true when you are dealing with objects. The less you expose to the outside world, to your clients, the more you can change on the inside world without breaking anything. This topic is closely related to a very important object-oriented concept called encapsulation.

Function Design

  1. Procedures should be designed to complete a single task. Avoid writing procedures that try to accomplish too much. Failing to follow this rule will make your code less modular, which ultimately could lead to code that is harder to manage or extend.

  2. Pass as much information as possible when using remote objects. If you are using remote objects such as ActiveX DLL's in a COM+ setting or an ActiveX EXE, design your objects so they can be initialized from a single method call. You want to minimize calls across the network to use as few calls as possible, otherwise your performance will suffer greatly.

  3. Functions and Subs have one entry, and they should also have one exit. Avoid using Exit Function and Exit Sub. Use a GoTo to jump to your cleanup block (see next tip), or see if you can restructure your code differently. As a general rule, your code should flow from top to bottom. Exit Loop and Exit For are fine, because they do not disrupt program flow. I think you will find that your code will be easier to debug if you know there is only one place a function can exit.

  4. Use GoTo for function cleanup after error conditions. In error conditions it is valid to use GoTo in order to jump to the program exit (I didn't make this up, I started doing this years ago, after reading Writing Solid Code).

    Using GoTo allows you to implement generic error handling and allows the function to place any cleanup code in a single location, rather than repeating it throughout the routine. Here's some pseudo-code:

    Public Function GetData() As Boolean
        On Error Goto Errs
    
        'Allocate resources that need cleaning up
        Dim conn As ADODB.Connection
        conn.Open(.)
    
        Dim rs As ADODB.Recordset
        Set rs = conn.Execute(yadayadayada)
    
        If (something bad happens) Then
            Goto Cleanup
        End If
    
        If (another bad thing happens) Then
            Goto Cleanup
        End If
    
        'More code here
    
    Cleanup:
        rs.Close
        Set rs = Nothing
        conn.Close
        Set conn = Nothing
    
        Exit Sub
    
    Errs:
        'Call error handler here
    
    End Function
    

    Using GoTo is bad, but only if you don't know what your doing. This is one of the few valid reasons to ever use them.

  5. Use ByVal for function parameters. I am not going into much detail on this topic, because it is actually bigger than it looks. There are reasons for calling ByVal that deal with performance, but the reason this tip exists is for the simplest of all purposes. If you do not pass ByVal you are modifying the variable that was passed in. This variable will remain modified once the function exits, which can cause problems for the beginning programmer.

  6. Default functions to failed condition upon entry. After you declare your local variables, the first line of code in a function should either set the return value to a default value or a False condition. There are usually a lot more things that can go wrong, but only a few things that will satisfy a True result.

    Yes, VB will automatically set a Boolean value to False, but do it yourself anyway. It states your intent clearly. And seriously, this topic would not exist if I didn't see the following all the time (I literally saw this last week):

    Public Function Foo() As Boolean
    
        If (success) Then
            If (more success) Then
                If (greater success) Then
                    Foo = True
                Else
                    Foo = False
                End If
            Else
              Foo = False
            End If
        Else
            Foo = False
        End If
    
    End Function
    

    The first clue something is wrong is that Foo is being set to False 3 times. If you assume a False condition from the onset, you can rewrite the function to look like this:

    Public Function Foo() As Boolean
    
        Foo = False
    
        If (success) Then
            If (more success) Then
                If (greater success) Then
                    Foo = True
                End If
            End If
        End If
    
    End Function
    

    Here, each condition is only set once.

Classes, Objects, and Object Models

  1. If you want to use a UDT (User defined type), think about a class instead.

    This is true if you find yourself writing module level functions that take the UDT as a parameter. In this case, what you actually want is a class so that you can encapsulate your data along with the functions that manipulate that data. UDT's should only be used to group small pieces of related data. This data should only consist of primitive data types (Integer, Long, Double) and not object references.

  2. Understand when to use properties versus methods. Properties describe an object's state: like a color, a name, or a quantity. A function describes a behavior: Open, Close, Release. Properties are nouns. Methods are verbs.

  3. Model "Has A" relationships through containment. Containment or aggregation is when one object contains another (usually as a private member of the class). For instance, a Car class could contain an Engine class. A Boat class could contain an Engine class, too.

  4. Model "Is A" relationships with interfaces. Define common object behaviors with an interface. For instance, if you were writing objects for an online retailer you might have a Visa class, a Discover class, and a MasterCard class. While each might need to be validated differently, all cards need to be authorized, billed, and credited. You should define these behaviors using an interface.

  5. Build Classes by Implementing Interfaces. This allows classes to grow over time yet keeps them backwards compatible. Keep your interfaces as small as possible, and build your objects through the use of interface composition.

  6. Implement several interfaces to define object behavior. Interfaces should represent a service that your object provides. These services are not necessarily intrinsic to the object itself. For instance, an IPlay interface could be implemented by VCR, DVD, or CDPlayer. Each of these classes handles a different media in a different way, but the interface (play, pause, stop, etc.) is the same.

  7. Never break an interface--no matter what! This is pretty self-explanatory. Once an interface has been used, don't change it. Apply this rule to published classes as well, and you will do even better.

  8. Use Implements in a way that supports polymorphism. Consider the credit card classes discussed in tip 23. Basing each class on an interface, would allow you to write code that could manipulate these objects polymorphically:

    Dim v As Visa
    Set v = New Visa
    
    .
    .
    .
    Call BillOrder(Visa)
    .
    .
    .
    
    Public Sub BillOrder(ByVal pCreditCard As ICreditCard) 
    
        If pCreditCard.Bill Then
            'Ship the order
        End If
    
    End Function
    

    Why is this great? Well, what if you add more credit card types, or even a gift certificate? You would not have to rewrite the BillOrder method every time you added a new type of payment.

  9. Free object references. Be aware of the objects you are using and set them equal to Nothing as soon as they are no longer needed. Don't necessarily wait for the cleanup code for your function to finish. If you can free an object before, do it.

  10. Restrict input to class methods with enumerations. Use an Enum when a method requires numerical data that must be within a certain range.

  11. Design your object model on paper first. I am not necessarily saying to go out and learn UML and start drawing object diagrams. Write out the methods you think the class should have. Draw pictures and use a pencil. Sure, this is unorthodox, but the idea here is to contemplate instead of diving head first into the code without thinking first. UML is a helpful tool, though.

  12. Be aware of how your object looks in an object browser. This topic is tied to tip 8 somewhat. Go take a look at ADO in the Object Browser and you will notice that none of the parameters for any of the Public methods use Hungarian notation. I once worked with a guy who used to name his functions using Hungarian notation, too. Since every one of his functions returned a Boolean, IntelliSense was pretty much rendered useless because everything began with a "b". Keep in mind how the object browser and IntelliSense will present your code to other developers.

The User Interface

  1. Read "Official Guidelines for User Interface Developers and Designers." This is another Microsoft document worth reading, dealing with user interfaces.

  2. Separate the business logic from the user interface. Forms should only contain data validation and persistence code. Business logic and database access code should be in another tier.

  3. Persist your forms. Persistence means that the user interface should save its state between invocations. It should default to whatever settings the user last selected.

  4. Minimal is better. The simpler the UI the better. Don't distract the user by placing all of the latest and greatest controls on a form, or non-standard UI elements like purple buttons and baby-blue list boxes.

  5. The user interface should be able to convey the result of all input. Whenever the user does something, make sure the UI conveys it.

  6. Don't report normal conditions to the user with dialogs. The less popup windows a user has to look at the better. Try to use other visual queues to get your user's attention. Dialogs interrupt the user and he or she will find it annoying after awhile.

  7. Don't require the user to enter information that can be obtained automatically.

    Do as much as possible for the user. For instance, if 9 times out of 10 the current month is used, make sure your date text box already has the current date in it. Do the most, with the fewest number of clicks and the smallest amount of keyboard strokes.

  8. Forget MDI windows exist. Enough said. If you have no idea what an MDI window is, you are off to a good start. Most people don't do it right anyway, so it is not worth the risk.

  9. Work to eliminate tedium. Make sure the user can get related information as quickly as possible (but not at the expense of the user interface).

  10. Visually show the progress of an operation and provide the user the means to cancel it. Visual cues are very important to a user, but they hate feeling like they are committed to an operation. Always give the user a way to bail out, especially if the procedure is time consuming.

  11. Don't forget about the keyboard. Assume there is no mouse. Provide the means to do everything (if possible) from the keyboard. This is somewhat tied to tip 40. Keyboard shortcuts are a must, especially on applications that will be used for any considerable amount of time.

  12. Use popular applications as a model. I like to use Word or SQL 2000 as a model for user interface design. You might use a different application. It's up to you. Look at professional applications and model yours after them. The sad truth is that most programmers are not very good at designing user interfaces. There is no shame in stealing someone else's ideas.

  13. Don't display errors that should have been prevented. A user shouldn't have to look at a dialog box stating that your application has performed a divide by zero error. For one thing, this error never should have made it this far.

  14. Eliminate the possibility of errors by restricting input. Pre-populate form fields whenever possible, and limit what a user can do in the UI. Try to prevent the user from entering as much free form data as possible. For instance, if you have numerical data between 1 and 1000 make sure the MaxLength property of the textbox is set to 4. If you have numerical data between 1 and 20, use a dropdown with the numbers 1-20 in it.

    Provide lists through dropdown combos instead of allowing users to enter information into a textbox. Where I am working at this moment, there is a reporting application that asks the user to enter in the "account types" they wish to filter on. Why this is not presented through a multi-select listbox, I don't know; the account types are stored in a database.

    The point to this topic is that the more you can restrict the input of the user, the less validation code you will have to write.

  15. User interface should be consistent. All visual elements of your UI should be the same in terms of style. One form should not vary wildly from another.

Miscellaneous

  1. Avoid Option Base. Arrays should start with element 0 because most people are used to using them that way. Using Option Base makes looking at your code somewhat of a guessing game.

  2. Avoid ReDim. ReDim can be an expensive operation because every time you do this you are actually allocating a new block of memory. ReDim Preserve is even more expensive because an additional memory copy is used to move all of the elements from the old block of memory to the new block. Use of these commands here and there is okay if you are aware of the penalties involved. I bring this up because I have seen ReDim used in loops so many times (I can't count that high) that is is unbelievable. Think about how you could use a collection in situations where you are using ReDim in a loop.

  3. Avoid the operator precedence guessing game. Use parenthesis to guarantee the outcome equations and logical branches. Yes, even professional programmers can get tripped up over operator precedence. I avoid having to think about it by using parenthesis around every operation:

    x = (((x * y) + z) / q)
    
  4. Consistency is the cornerstone of style. Whatever you decide to do code wise, do it consistently. Develop your style. This will do more for you than any tip that someone gives you. If you take nothing else with you from this article but this tip, then you are off to a good start. You might have noticed that consistency has been discussed during several of the tips here. It really is the foundation of good programming.


J. P. Hamilton is an independent software developer who lives and works in Houston, Texas, perhaps the largest underrated city in the known universe. He was born and raised on the 6502 processor (long live Atari) and punk rock, but now devotes much of his time to the .NET framework. Currently, when he is not programming, he is reading about programming, writing about programming, or dreaming about programming. But he hopes to start building a Japanese garden at his home this fall when the weather cools down and the mosquitoes are dead.


O'Reilly & Associates published (July 2000) Visual Basic Shell Programming.