Naming Conventions
General
As novice developer you usually define names for constants, variables and methods as they occur; you look at a problem, think of a function, add some parameters and that's it.
After a few years of coding—especially once you are forced to refactor some of your legacy coding—you will realize that the code is hard to read; it somehow feels "inconsistent".
Also during normal development you will notice that you keep stumpling upon the same issues again and again: you're trying to access variables, which are not accessible, you try to use a variable for a text value and run in to an error as it has been defined for numbers: the list of little annoyances which are implied when not sticking to consistent conventions is long—add your favourite annoyance here.
The naming conventions depend on the language you are using, but for VBA it is common conviction to use either the Reddick VBA Naming Conventions or the Leszynski VBA Naming Conventions, which are both versions of the Hungarian notation.
The main idea is to embed the variable name into prefixes and suffixes in order to give the developer a hint about the scope, purpose and data type of the variable. The general pattern is:
[ Prefix ] Tag [ Discriminator ] [ Name ] [ Suffix ]
where
- Prefix is used to describe the scope of the variable
- Tag is used to indicate the data type of the variable
- Name is a brief description of the variable's purpose or content and
- Suffix standardize often used versions of the same variable and are basically derived
from the database aggregate functions (Count, Min, Max, Sum, Avg, First, Last) or other special properties describing the order like "ByDate", "ByCustomer" etc.
Name
Singular
All names will be in singular form. A table, for example, represents many uniformed records. Do we want to talk about many records or do we talk about the entity that table has been designed for? It is the entity.
Let's look at it with a semantic focus: We have a table "Books" which has a field "ISBN". When we are talking about "Books.ISBN", do we mean all ISBNs of all Books? Or the ISBN of a certain Book? It is usually the latter. It also makes SQL statements and code much more readable besides the fact that mixing plural ("Books") and singular ("ISBN") does not make sense. Example:
SELECT Book.Isbn
FROM Book
INNER JOIN Stock
ON Book.Isbn = Stock.BookIsbn
Collections
Another advantage of generally applying singular names is the option to denote collections and arrays with a plural form, which leads to easily understandable code like
For Each varBook In varBooks
varBook.Isbn = "unknown"
Next varBook
In case
- the singular form should equal the plural like with Status,
- the name itself describes an entity which consists of many items like with List
or similar scenarios there is another collection naming convention: The collection keeps the name of the entity (Status, List) while its elements are suffixed with Item:
For Each varListItem In varList
varListItem.Active = "yes"
Next varListItem
Hierarchy
If a variable has a specific position in a hierarchy, the name should be chosen accordingly; example: The serial number of an item in a position of an order should be defined as intOrderPositionItemSerial and not as intSerial.
This happens out of several reasons: We certainly want to know as exactly as possible which content the variable represents, we cannot be sure that there will never be another serial number (which would lead to two variables wanting the same name) and although the variable name is longer, it is much more descriptive.
Methods
Methods—procedures and functions—always start with a lowercase verb, which describes what the method does.
Public Sub setDiscountRate(sngDiscountRate As Single)
'Set the discount rate
End Sub
Public Function getAverageAmount() As Currency
'Retrieve the average amount
End Function
The only exception to the "what it does" rule are boolean functions, as you want to keep the readability of the code:
Private Function isBlocked() As Boolean
'Find out whether it is blocked or not
End Function
Public Sub adjustAmount()
If Not isBlocked Then
'Adjust the amount
End If
End Sub
If the function was called "getBlock" (which would be correct according to the above mentioned rule), you would end up with something like If getBlock = True Then … which could be translated (and misunderstood) as if you should manage to retrieve a value for 'Block' then …; and that is certainly not what we want to think about when reviewing or refactoring large parts of code.
Another bad wording which should be avoided is the verb "check". In legacy code you will have a good chance that in one half of the occurrences of "check" you deal with boolean functions while the other half carries out a set of checks. And even if a set of checks is carried out, what would a boolean return value True tell us then? That all checks have been executed successfully and some of them might (or not) have been failing or that all checks were carried out where possible and none of them returned an error?
Verbs like "perform", "do" should also be avoided under any circumstances as they simply proove the author's small active vocabulary. Whenever one of these terms come to your mind, think twice before writing it down.
It is also wise to avoid negative descriptions or those who might tend to describe some inherent logic like getNotInvalidErrorCount—put your own arguments against such a method name here.
Labels
Labels are used mainly during error handling in order to allow the developer to jump forth and back. As the nature of labels is rather that of methods than of objects, the Labels should be named accordingly. It is good practice to prefix the method name with handle and to suffix it with Error. In case you should have more than one label you can adjust the prefix and suffix according to the needs of the case where the label is used.
Public Sub setName(strName As String)
On Error GoTo handleSetNameError
'Try to set the name
On Error GoTo 0
exitGracefully:
'Do some cleanup before leaving
Exit Sub
handleSetNameError:
'Take consequences from the fail
GoTo exitGracefully
End Sub
Tag
A tag is a usually three letter long lowercase mnemonic for the variable type. As there is not a tag for every kind of variable, you sometimes need to "invent" a tag of your own. The usual steps for finding an appropriate tag are:
- Take the name of the object type
- Remove all vowels from the name; you may keep the first vowel if necessary
- Take the first three letters
As soon as you found a tag you should consider the following questions too:
- Is the tag already taken by another object type?
- Does it phonetically sound like the object type?
If you should answer one of these questions with "yes", you should adjust the tag name accordingly.
A tag is the minimum used for assigning a proper variable description.
Data Type
Data Type | Tag |
---|---|
Boolean | bln |
Integer | int |
Long | lng |
Single | sng |
Double | dbl |
Currency | cur |
String | str |
Date | dat |
Variant | var |
Array | arr, var |
Collection | col |
Type | typ |
Object | obj |
Classes and User Defined Types
Classes and User Defined Types will get an individual tag representing the name:
Dim rcp As typReceipt
Dim rcpFirst As typReceipt
Dim xml As clsXml
Dim xmlValidator As clsXmlValidator
One thing to note is the fact that is suffices to use a tag as variable name, the other, that you can easily point out the class hierarchy by simply applying the fully qualified rest of the class name. In this case "clsXml" is translated into "xml", so that "clsXmlValidator" becomes "xmlValidator".
Microsoft Office
Microsoft Office Objects
Data Type | Tag |
---|---|
Menu Bar, Tool Bar | cbr |
Menu Item | |
Module | mod |
Class | cls |
Microsoft Office Form Objects
Data Type | Tag |
---|---|
Control | ctl |
Label | lbl |
Text Box | txt |
Combo Box | cmb |
List Box | lst |
Check Box | chk |
Button | btn |
Option Group | grp |
Option Button | opt |
Tab Control | tab |
Tab Control Page | tpg, pag |
Frame | fra |
Frame bound | frb |
Frame unbound | fru |
Image | img |
Line | lin |
Page Break | brk |
The following tags differ slightly from tags proposed by Reddick and Leszynski and should be explained:
- cmb vs cbo
- The control type name is "Combo Box". If you apply the tag rules you will end up with cmb. There is no good reason to call this control type tag "cbo".
- btn vs cmd
- The nature of a "Command Button" is not the command, but the button. The tag "cmd" is also well known for the Windows Shell as well as for the extension of batch files. Although both usually do not appear in Visual Basic code very often it is still a bad habit to "abuse" acronyms.
- tpg/pag vs pge
- The tag "pge" is less phonetic than "pag". A good tag would be "pg", but as we are trying to stick with three-letter tags, we need to find something suitable. Pages do not exist without their container, the "Tab Control", thus it is okay to see this control as "Tab Page" ending up with the tag "tpg".
- tgl vs btn
- You may decide on your own whether you should use a different prefix for a toggle button. In the end it is still a button although it rather behaves like a check box.
Microsoft Access
Data Type | Tag |
---|---|
Table | tbl |
Table Field | fld |
Query | qry |
Form | frm |
Sub Form | sfr |
Report | rpt |
Sub Report | srp |
Microsoft Excel
Data Type | Tag |
---|---|
Workbook | wbk |
Worksheet | wks |
Range | rng |
Chart | cht |
Shape | shp |
Prefix
Scope
Class, Module, Public, Private ...
Discriminator
Constants
Constants get a c after the tag:
Private Const intcAnswer As Integer = 42
Another popular alternative is to define constants in uppercase.
Suffix
Exceptions
Enumerated Types
Reddick recommends a very odd naming convention for these: he proposes a prefix which is built from the enumerated type followed by a c in order to indicate its constant character leading to something ugly as
Public Enum ervcErrorValue
ervcInvalidType = 205
ervcValueOutOfBounds
End Enum
This is not only ugly, it is also misleading and breaks the convention to tag a variable with its data type, which in case of enumerated types is Long.
As especially publically accessible enumerated types are often matter to IntelliSense's autocompletion, we are striving for easily readable code and the intention of tagging variables is to avoid wrong type casting, this proposal does not make sense.
Instead enumerated types should be defined as follows:
Public Enum ArrayError
IsEmpty = 205
OutOfBounds = 42
End Enum
The name of the enumerated type should describe as specific as possible what this type is aiming at, in this case it holds all the possible error codes which might be raised in some array handling routine. Note that terms like "Value" have been removed as they do not deliver any additional useful information.
Later in the code this definition will be nicely referred to with something like
Select Case lngArrayError
Case ArrayError.IsEmpty
MsgBox "Fill the array please."
Case ArrayError.OutOfBounds
MsgBox "You are out of bounds."
End Select
This looks and acts much more like the convenient Object.Property paradigm that most developers are used to; the same logic is applied in the discussion about the naming of Class Properties.
Class Properties
Reddick recommends to apply the naming conventions to class properties as well unless you are distributing the class to customers, who might not be aware of those conventions.
The purpose of a class is to encapsulate business logic and to hide the complexity of the underlying code from the user. In order to make the code more readable it is strongly recommended to leave out the naming convention amendments when it comes to naming the properties of a class module.