Visual Basic Style Guide, 3BSE016636/-

Category: BU APS, BU MES Draft

SUMMARY

This guideline gives recommendation for Visual Basic (Visual Basic) programming within ABB BU APS and BU MES.
The document summarizes rules and recommendation for making a good code in Visual Basic. This is the first version of Visual Basic Style Guide and it will certainly pass several revisions as new experience and number of programmers grow.
The document includes the following chapters:
  1. INTRODUCTION - Includes the purpose of the document and the reference literature

  2. VISUAL BASIC OPTIONS SETTINGS - gives a recommendation for some editing options.

  3. MODULARIZATION - explains in which modules put the code.

  4. DECLARATIONS - defines standards for declaring variables.

  5. CLASSES - gives rules and recommendations for classes, properties and methods.

  6. PROCEDURES AND FUNCTIONS - describes standards for Visual Basic procedures and functions.

  7. CONTROLS - gives naming conventions for controls.

  8. CODING STANDARDS - Gives some Basic principles for coding. 

  9. ERROR HANDLING - describes a method for managing errors.

  10. FORMATTING ISSUES -  specifies how to format the code, spacing and usage of blank lines.

  11. COMMENTS - describes how to comment the code.

1 INTRODUCTION

This document gives recommendations of how to write programs in Visual Basic for applications within BU APS and BU MES. The main purpose of this style guide is to state rules and hints in order to
This style guide is not intended as a primer for the language; on the contrary, the reader should already be familiar with Visual Basic.
The document is based on different style guides:

VISUAL BASIC OPTIONS SETTINGS

You can setup certain options which facilitate your work while editing code. The following options are of special interest:
To automatically get the Option Explicit statement in every file containing source code, do the following: In the Environment Options dialog, set Require Variable Declaration to Yes. The Option Explicit statement requires you to declare all the variables in your Visual Basic program.

MODULARIZATION

Generally, a module should contain things that are logically related. Modules have an interface part that defines how to access the module, and an implementation part that encapsulates the internal representation.
Dependencies between modules should be minimized. A good modularization is characterized by locality , i.e. the knowledge of the representation is local. This facilitates maintenance and understanding of the system.
There are three types of modules in Visual Basic - Standard Modules, Forms and Classes.

DECLARATIONS

4.1 Scope

Variables should always be defined with the smallest scope possible. Global variables can create enormously complex state machines and make the logic of an application extremely difficult to understand. Global variables also make the reuse and maintenance of your code much more difficult.
Variables in Visual Basic can have the following scope:
 
Scope 
Variable Declared In:
Visibility
Procedure-level
Event procedure, sub, or function
Visible in the procedure in which it is declared
Form-level, Module-level
Declarations section of a form or code module (.FRM, .BAS)
Visible in every procedure in the form or code module
Global
Declarations section of a code module (.BAS, using Global keyword)
Always visible
 
In a Visual Basic application, only use global variables when there is no other convenient way to share data between forms. You may want to consider storing information in a control's Tag property, which can be accessed globally using the form.object.property syntax.
 
If you must use global variables, it is good practice to declare all of them in a single module and group them by function. Give the module a meaningful name that indicates its purpose, such as GLOBAL.BAS.
With the exception of global variables, procedures and functions should only operate on objects that are passed to them.

Global variables that are used in routines should be identified in the general comment area at the beginning of the routine.

Write modular code whenever possible. For example, if your application displays a dialog box, put all the controls and code required to perform the dialog's task in a single form. This helps to keep the application's code organized into useful components and minimizes its run-time overhead.

4.2 Data declarations

Declare variables in the header part of the scope: Global variables in modules directly after the Option Explicit statement, public and class variables after the class declaration, local variables within a function directly under the function declaration part.
Always define the type of variable and avoid using the Variant Data Type whenever possible.
GOOD STYLE:

Dim FirstState as Integer ' Initial Engine State

BAD STYLE:
Dim FirstState ' Initial Engine State

Each variable should be declared on a separate line and commented.

GOOD STYLE:
Dim FirstState as Integer ' Initial Engine State

Dim NextState as Integer ' Current Engine State
BAD STYLE:

Dim FirstState, NextState as Integer ' States of the Engine

Don't use the same variable for different purposes. Declare a new variable for each purpose, and define it close to the place where it is used. This is particularly important for temporary variables and loop indices.

Use locally declared loop variables where possible. Never use the loop variable outside the loop.

4.3 Naming conventions

The Hungarian notation is a very common notation principle in Visual Basic. This standard says that you in the variable names describe both "meaning" and type of variables. For example iStatus an Integer variable showing a status.
We do not use Hungarian notation except in some special cases (see See CONTROLS ). There are several reasons for this. One of them is the requirement that all variables are explicitly defined where it is easy to see of which type the variable is. Another reason is a tradition - we do not use the Hungarian notation in any other language.
Visual Basic does not differ upper case from lower case letters. It is however very convenient to use a combination of both letters. If a variable or a function or any other declaration has a combination of upper case and lower case letters, Visual Basic automatically converts lower and upper case letters to the exact declaration value by the line completion during the editing. If, for example, you define a variable Status and then later enter status, Visual Basic will convert it to Status when you press CR. This way of editing provide you with a spelling control!

Names start always with an upper case letter followed by lowercase letters in most cases.

Names should contain only alphanumeric characters (a-z, A-Z, 0-9) and underscore (_).

Names (identifiers) shall always be descriptive, i.e., they shall describe the purpose of the things they denote. All names shall use the English language. Use long names because it makes the code easier to read and understand. Names must be pronounceable.

Single-word names should be given in full length, without abbreviations. If the name is constructed from several English words, an abbreviation may be used as part of the name, but only if the meaning is clearly understandable in the context of its use. Abbreviate a name only if it saves more than three characters.

Consistency and uniformity are very important. Try to use the same words everywhere you refer to a concept, both in identifiers, comments and design documents. It can often be good to make a dictionary of the words that are common in the application domain. Good use of names makes it considerably easier to understand programs and documentation. When maintaining old code, use the same naming style as the original code uses.
Variables should be named as qualified type names , e.g. adjective + type name.
Counter variables can use the abbreviation NoOf meaning number-of.
Types (classes and user defined types) should be named with noun phrases .
Functions and procedures should be named with verb phrases , e.g. verb + type name.
When you declare objects of class type, try to give them names so that the total appearance "object.function" makes sense and is readable. The class designer should also consider this when the names of member functions are selected.

Names that consist of several words should be constructed in a way that makes the division clearly visible. This is done by capitalizing the first letter of each word (do not use underscore for this purpose).

Constants often describe a limit within a program. In these cases it is appropriate to use the prefix "max" in connection with the type name. Otherwise treat the names for constants like variable names. Constants start, as any other name, with a upper case letter. To emphasize that it is a constant, it may be written in all capital letters.
 
Variables types define particular attributes and these attributes should be seen in the variables names, without using Hungarian notation. Here follows a list of some variable types:
        Examples: PrinterIsREady, QueueIsEmpty, IsEmpty.
        Use
        Dim CustomerName as String
        instead of
        Dim CustomerName$

CLASSES

At a very general level, a class describes a group of similar objects. The class defines the properties and methods for all objects created (instantiated) from the class.
Visual Basic allows you to define your own classes with their associated class properties and methods. Afterwards you can create objects from that class. You define your own classes by inserting class modules into your project. You write the declarations and code for the properties and methods in these class modules. Since the class modules contain both the properties and the methods for the class, they encapsulate all of the information for the class. You can set the properties and call the methods anywhere in the application without concerning how they were implemented. The class can be modified at any time without affecting the rest of the application (assuming the interfaces to the properties and methods do not change). This makes the code easier to develop, test, and maintain.
In constructing an application, it is important to define the pertinent set of classes and appropriate properties and methods for each class. This ensures that the correct set of information is encapsulated in each class, making it easier to work with and maintain the class.

5.1 Creating a Class

Creating a class in Visual Basic involves inserting a class module into your project and then adding code to the module.
No matter how complex the class, the steps for creating the class are the same. Each time you create a class, you will need to follow these steps:
  1. Insert a class module.The class module will contain the definition of the properties and the implementation of the methods for the class.
  2. Define the properties for the class.
  3. Create the methods for the class.
  4. Create the events for the class.

5.2 Data Members

A class module can have variables or data elements associated with it just as any other module has module-level data elements. Each data element is called a class data member.
Some of these data members store the values of the object properties and others are for internal use. It is a good practice to use the Property functions Get and Let to read or set the object's properties instead of having Public data.
In some cases it is convenient to put "m_" prefix in the names of the private data. This notation helps to easier see the mapping between a property and internal variable keeping the property value.

5.3 Class Properties

Class properties identify the attributes of all objects created from a class. Each object has a specific value for each property. The properties for a class can be any of the following:
There are three types of Property procedures:

5.4 Class Methods

Class methods define the behaviors of all objects created from a class.
 
To create a method, do the following:
  1. Determine if the method will be public or private. Only those methods that will be accessed from outside of the class should be declared as Public. All others should be Private.
  2. Determine whether or not the method will return a value. If a method needs to return a value, it will be defined as a Function procedure. Otherwise it will be a Sub procedure.
  3. Write the code for the method. The methods for a class are implemented as normal Sub or Function procedures.

5.5 Events

Class modules have two events: Initialize and Terminate. The Initialize event provides an opportunity to perform initialization of the objects created from the class. The code in the Initialize procedure executes first, prior to setting any properties or executing any methods. The Initialize event is similar to a class constructor used in other object-oriented languages.
The Terminate event provides a place to perform and clean up processing.

5.6 Using the Class

A class instance is an object. There are two common techniques for creating an object:
The second alternative is better because you have control when the object is created.
Object variables use memory and system resources. When the object variable is no longer needed, the resource used by the object variable should be released. This is done with the following statement:

Set ObjectVariable = Nothing

It will also be done automatically when the object variable goes out of scope. For example, if the object is declared as a local variable, the object variable will be released at the end of the local routine.

PROCEDURES AND FUNCTIONS

A procedure (Sub) or a function (Function) can be either a separate function in a module or a member of a class. In the latter case we call them methods.
The difference between a procedure and a function is that a function returns a value of a particular type.
Scoping rules for procedures and functions are rather inconsistent in Visual Basic. Procedures are global in modules and unless they are declared Private. In forms they are by defaulty defined as Private.

Always specify the Private or Public attribute explicitly when defining a procedure.

6.1 Parameters

Always make sure you are absolutely clear about how each parameter is to be used. Is it used to communicate a value to the procedure or to the caller or both? Where possible, declare input parameters ByVal. Unfortunately, there are some data types that cannot be passed ByVal, notably arrays and user defined types.
Note that parameters are passed as references by default.

6.2 Function Return Values

In Visual Basic, you specify the return value of a function by assigning a value to a pseudo-variable with the same name as the function. This is a fairly common construct for many languages and generally works well.
There are, however, a couple of limitations imposed by this scheme. One of them is that it is not possible to reference the currently-assigned return value from within the body of the function itself.
Always declare a local variable called Result inside every function procedure to use it for the return value. Make sure that you assign a default value to that variable at the very beginning of the function. At the exit point, assign the Result variable to the function name immediately before the exit of the function.

Example:

Function DoSomething() As Integer

Dim Result As Integer
Result = 42 ' Default value of function
....
DoSomething = Result
End Function

CONTROLS

Controls (ActiveX controls) are widely used in Visual Basic. From Visual Basic 5 it is also possible to develop ActiveX controls. This chapter addresses only the usage of them, in particular the naming standard.
It is very common to use the Hungarian notation when declaring the controls. For this reason we use it when creating instances of controls and we specify the prefixes which should be used.
All controls on a form should be renamed from their default " Text n" names, even for the simplest of forms. The only exception to this are labels used only as static prompts on the surface of a form. If a label is referenced anywhere in code, then it must be given a meaningful name along with the other controls. If not, then its name is not significant and can be left to its default " Label n " name.

Take the time to rename all controls before writing any code for a form, because the code is attached to a control by its name. If you write some code in an event procedure and then change the name of the control, you create an orphan event procedure.

The following table is a list of the common types of controls you will encounter together with their prefixes:
 
Prefix
Control
Prefix
Control
Prefix
Control
cbo
Combo box
chk
Checkbox
cmd
Command button
dat
Data control
dir
Directory list
dlg
Common dialog
drv
Drive list box
ela
Elastic
fil
File list box
fra
Frame
frm
Form
gau
Gauge
gra
Graph
img
Image
lbl
Label
lin
Line
lst
List box
mci
MCI control
mpm
Mapi Message
mps
Mapi Session
ole
OLE control
opt
Option button
out
Outline control
pic
Picture
pnl
Panel
rpt
Report
sbr
Scroll bar 
shp
Shape
spn
Spin
ssh
Spreadsheet
tgd
Truegrid
tmr
Timer 1 
txt
Textbox
1. There is often a single Timer control in a project, and it is used for a number of things. That makes it difficult to come up with a meaningful name. In this situation, it is acceptable to call the control simply "Timer".
 

Menu controls should be named using the tag "mnu" followed by the complete path down the menu tree. Here are some examples of menu control names:

CODING STANDARDS

8.1 General coding principles

Programming is not just to get a working version of the program; in order to maintain and understand the program, the program must be well-structured, symmetric, and consistent. Data modeling, data abstraction, structured programming, modularization, etc. are methods that can be applied to make the inherent structure explicit.
These ideas can be applied also on the lowest level, when the function definitions are coded, as sketched below.
Try to avoid code duplication. One algorithm should only be coded in one place . If you need a variant of the algorithm, try to see if these two algorithms has common subparts, which can be made into common functions.

Do not duplicate a complicated expression or subexpression.

Do not duplicate a sequence of statements.

8.2 Procedure Length

There has been an urban myth in programming academia that short procedures of no more than "a page" (whatever that is) are good. Actual research has shown that this is simply not true. There have been several studies that suggest the exact opposite. For a review of these studies (and pointers to the studies themselves) see the book Code Complete by Steve McConnell (Microsoft Press, ISBN 1-55615-484-4 ). If you feel that this routine should be 200 lines long, just do it. Be careful how far you go, though.
Of course, a procedure should do ONE thing. If you see an "And" or an "Or" in a procedure name, you are probably doing something wrong. Make sure that each procedure has high cohesion an low coupling, the standard aims of good structured design.

8.3 IF

Write the nominal path through the code first, then write the exceptions. Write your code so that the normal path through the code is clear. Make sure that the exceptions don't obscure the normal path of execution. This is important for both maintainability and efficiency.
Make sure that you branch correctly on equality. A very common mistake is to use ">" instead of ">=" or vice versa.
Put the normal case after the If rather than after the Else. Follow the If with a meaningful statement.

Always consider using the Else clause.

Simplify complicated conditions with boolean function calls. Rather than test twelve things in an If statement, create a function that returns True or False. If you give it a meaningful name, it can make the If statement very readable and significantly improve the program.

Don't use chains of If statements if a Select Case statement will do. The Select Case statement is often a better choice than a whole series of If statements.

8.4 SELECT CASE

Put the normal case first. This is both more readable and more efficient.
Order cases by frequency. Cases are evaluated in the order that they appear in the code, so if one case is going to be selected 99% of the time, put it first.
Keep the actions of each case simple. Code no more than a few lines for each case. If necessary, create procedures called from each case.

Use the Case Else only for legitimate defaults. Don't ever use Case Else simply to avoid coding a specific test.

Use Case Else to detect errors. Unless you really do have a default, trap the Case Else condition and display or log an error message.

8.5 DO and FOR

Keep the entire body of a loop visible on the screen. If it is too long to see, chances to understand tyhe code are smaller.
Limit nesting to three levels. Studies have shown that the ability of programmers to understand a loop deteriorates significantly beyond three levels of nesting.
Never omit the loop variable from the Next statement. It is very hard to unravel loops if their end points do not identify themselves properly.

8.6 GOTO

Do not use Goto statements.

8.7 EXIT SUB and EXIT FUNCTION

Related to the use of a Goto is an Exit Sub (or Exit Function) statement. Use these two ways to make some trailing part of the code not execute:

8.8 EXIT DO/FOR

These statements prematurely bail out of the enclosing Do or For loop. Do use these when appropriate but be careful because they can make it difficult to understand the flow of execution in the program.
On the other hand, use these statements to avoid unnecessary processing. We always code for correctness and maintainability rather than efficiency, but there is no point doing totally unnecessary processing.
In particular, DO NOT do this:

For Index = LBound(Items) to UBound(Items)

If Items(Index) = SearchValue Then
    Found = True
    FoundIndex = Index
End If
Next Index
If Found Then . . .
This will always loop through all elements of the array, even if the item is found in the first element. Placing an Exit For statement inside the If block would improve performance with no loss of clarity in the code.
Do avoid the need to use these statements in deeply nested loops. Sometimes there really is no option, so this is not a hard rule, but in general it is difficult to determine where an Exit For or Exit Do will branch to in a deeply nested loop.

8.9 GOSUB

Do not use it!

ERROR HANDLING

You should use Err object to manage errors. The properties of the Err object are set by the Visual Basic generator or the Visual Basic programmer.
When a run-time error occurs, the properties of the Err object are filled with information that uniquely identifies the error and information that can be used to handle it.
The Clear method can be used to explicitly reset Err.

The example shown below uses the properties of the Err object in constructing an error-message dialog box. Use the Clear method first, when you generate a Visual Basic error with the Raise method, Visual Basic's default values become the properties of the Err object.

Dim Msg As String

' If an error occurs, construct an error message
On Error Resume Next ' Defer error handling.
Err.Clear
....
' Check for error, then show message.
If Err.Number <> 0 Then
    Msg = "Error " & Str(Err.Number) & " was generated by " _
    & Err.Source & Chr(13) & Err.Description
    MsgBox Msg, , "Error", Err.Helpfile, Err.HelpContext
End If
To generate a run-time error in your code, use the Raise method.

10 FORMATTING ISSUES

Fortunately, you do not need to bother a lot about formatting, because Visual Basic does it for you! Here are some rules which you have to take care of.

11COMMENTS

All comments must be written in English.
Each source file must begin with a comment block which includes a short description, author, copyright text, version identity, history messages and if necessary a more detailed description.
This comment block should have the following format (the format is adjusted to DocJet tool which generates documentation from the source code):

' <short description>

' FILE <file>

'
' $Id$
'
' AUTHOR <dept> <name>
'
' All rights reserved. Reproduction, modification, use or disclosure
' to third parties without express authority is forbidden.
' Copyright <Company name>, <Country>, <Year>.
'
' HISTORY:
'
' $Log$
'
'
' ABSTRACT
' <description text>
'
Option Explicit
 NOTE: One empty line follows the description line.
 

Each function or procedure should be proceeded by a comment. The following format should be used:
 

'---------------------------------------------------------------------
'
' DESCRIPTION:
'   <description of method/function>
'
' PARAMETERS:
'   Parameter1 - [in] Description of parameter1.
'   Parameter2 - [in] Description of parameter2. (Default value)
'   Parameter3 - [out] Description of parameter3.
'
' RETURNS:
'   <return value> - Description of return values
'
' REMARKS:
'   <remark text>
'
Private Sub Name(ByVal Parameter1 As Integer, _
                 ByVal Parameter2 As Boolean, _
                 parameter3 As String)

11.1 In-line Comments

In-line comments are comments that appear by themselves on a line, whether they are indented or not. In-line comments are the Post-It notes of programming. This is where you make annotations to help yourself or another programmer who needs to work with the code later.
Here are some examples of appropriate uses of In-line comments:
What we are doing:
' Now update the control totals file to keep everything in sync
Where we are up to:
' At this point, everything has been validated.
' If anything was invalid, we would have exited the procedure.
Why we chose a particular option:
' Use a sequential search for now because it's simple to code
' We can replace with a binary search later if it's not fast  enough
External factors that need to be kept in mind:
' This assumes that the INI file settings have been checked by
' the calling routine
Comment what is not directly seen from the code. Do not re-write the code in English, otherwise you will almost certainly not keep the code and the comments synchronized and that is very dangerous.

11.2 End of Line Comments

End of Line (EOL) comments are small annotations tacked on the end of a line of code. The perceptual difference between EOL comments and In-Line comments is that EOL comments are very much focused on one or a very few lines of code whereas In-Line comments refer to larger sections of code.
 
Think of EOL comments like margin notes in a document. Their purpose is to explain why something needs to be done or why it needs to be done now.
Example:
Private SelectedFiles As String ' Files selected from a Session form
Use EOL comments for every variable you declared. This comment is especially important if you use DocJet for documentation generation