Appendix A
Coding Conventions
This section is based largely upon our original coding conventions appendix in our first edition, written by Mark Hurst and Peet Morris. It describes the coding conventions we used in preparing most of the source code for this book. These conventions are based on extracts from our in-house TMS Visual Basic programmer's manual, VB Vogue (also included as part of the TMS Developer's Framework). You can use this appendix purely to look up type or scope prefixes you don't understand, but you might also want to use our conventions in your own code. Or you might decide to adapt them to suit your own preferences. The important thing is that you have coding conventions and that you apply them uniformly across your code. (If your company is interested in purchasing VB Vogue, please send e-mail to the alias requesting details and availability.)
The Need For Coding Conventions
Consistently applied coding standards can improve the following in a software project:
- Productivity. Productivity, as applied here to the actual writing of code, means saving "code time" without suffering some inherent quality penalty.
- Quality. The quality of code is chiefly measured by its relative conformance to some technical specification and the ease with which it can be maintained.
- Maintainability. Maintainable code is both repairable and extensible. Additionally, and in all cases, maintainable code is easy to comprehend, which facilitates achieving speedy, accurate modification.
- Comprehensibility. Comprehensible code is both conformant (with some recognized standard) and consistent.
Naming Conventions
We use a simplified form of Hungarian notation, a naming convention that takes its name from the nationality of its creator, Charles Simonyi. Certain elements of Hungarian notation are used in Microsoft's Visual Basic manuals. Microsoft also uses Hungarian notation internally as part of its coding conventions, as do many developers around the world. Our simplified form of this notation is used to attach both type and scope information to various object names. Hungarian notation uses character prefixes to denote type, aggregation, and scope, and the full system gets rather complicated. The subset we've chosen for our purposes is defined in the following sections and in the tables that appear at the end of this appendix.
Type Information
Hungarian type prefixes have two parts: a base type to represent the base data type and a modifier to denote an aggregate type. An example of a base-type prefix is n, which denotes an integer, while adding the a modifier to the base type denotes an array of integers. An example should make this clearer:
Dim nCounter As IntegerDim anCounters(1 To 10) As Integer
Notice that the variable name itself starts with an uppercase letter, which shows us where the prefix stops and the variable name starts. Sometimes we need to use more than one modifier, such as a multidimensional array:
Dim aanStateTable(1 To 10, 1 To 10) As Integer
The base types and modifiers we use are listed at the end of this appendix. In fact, we use only one aggregate modifier since arrays are the only single-type aggregates that Visual Basic supports.
Where calls are made to Windows API functions, you might see type prefixes such as LPSTR and sz that don't appear in our tables: these prefixes are used in the Microsoft Windows documentation. We've found that changing these to match our Visual Basic data types can often conceal errors in the declarations. You might also see p used as a modifier to denote a pointer and pcb to denote the address of a callback function.
For variables defined with user-defined types (UDTs) and classes, the special base-type prefixes t and C are used. Although C breaks the lowercase rule, we've adopted it because it's used throughout the industry.
Menus are named with the type prefix mnu, but the names are aggregated to show the menu structure. For example, the Open item on the File menu is called mnuFileOpen. Here are some more standard menu names:
mnuHelpAboutmnuFileExit
Scope Information
We also use prefixes to denote an object's scope. Our scope prefixes come between the type prefix and the object name, so we need to make sure they start with an uppercase letter and end with a lowercase letter. This way, the scope prefixes stand out from both the type prefix and the object's name. For example, a private integer variable (scope prefix Pi) defined at the module level would be named like this:
Private nPiCounter As Integer
Variables
Variables are named like this:
The name part is simply the variable name written in mixed case, and the type part is a Hungarian type as defined earlier. We don't use type and scope prefixes when naming properties and methods of classes and forms.
The base types and modifiers are given in a table at the end of this appendix. The scope part is defined in the following sections.
Local variables
Local variables do not have a scope prefix. Here are some examples of local variable definitions:
Dim nCounter As IntegerDim sMessage As StringDim tThisCell As tTableEntry ' A user-defined typeReDim anLookupTable (1 To 10) As Integer
Private variables
Private variables defined at the module level have Pi as a scope prefix. Some examples follow:
Private nPiCounter As IntegerPrivate sPiMessage As StringPrivate tPiThisCell As tTableEntry ' A user-defined typePrivate anPiLookupTable () As Integer
Global variables
Public variables defined at the module level of a standard module (that is, a BAS file) have the module identifier as a scope prefix. The module identifier is a unique two-character prefix that suggests the module name. For example, we might choose Er for an error handling module or Db for a database module. We also use an additional scope prefix, pu, to identify the variable as public. Here are some examples.
Public nPuErCounter As Integer ' Er for "error handling"Public sPuErMessage As StringPublic anPuTbLookupTable () As Integer ' Tb for "table functions"Public tPuTbThisCell As tTableEntry ' A user-defined type
Form and class properties (unprotected)
Public variables defined at the module level of classes and forms are properties and do not have scope or type prefixes.
Functions and Subroutines
Public functions and subroutines have scope prefixes in the same way that variables do. Public and private functions also have a type prefix that reflects the type of value returned. The rules for choosing the type prefix are the same as those for variables.
Private subroutines
Private subroutines and functions do not require scope prefixes. Here are some examples of private subroutines:
Private Sub OpenLogFile()Private Sub ClearGrid()
And here are some private functions:
Private Function nGetNextItem() As IntegerPrivate Function sGetFullPath(ByVal sFileName As String) _As StringPrivate Function CGetNextCell() As CTableEntry
Public subroutines
The rules for choosing scope prefixes for public subroutines are exactly the same as those for variables, as shown here:
Public ErReportError()Public TbInsertTableEntry()Public DbDeleteItem()
Form and class methods
Public functions and subroutines defined in classes and forms are properties and do not have type or scope prefixes.
Form and class properties (protected)
Property Let, Property Set