Stan Leszynski and Greg Reddick
Revised: May 25, 1994
The authors wish to thank the individuals who submitted comments on and participated in reviews of the standard.
Stan Leszynski is president of Kwery Corp., which produces several Microsoft® Access® add-on products, including Access To Word and Kwery Control Paks. Stan also manages Leszynski Company, Inc., a consulting group active in database development, which he founded in 1982. He writes and speaks on Access regularly. Stan can be reached at (206) 644-7826 or on CompuServe® at 71151,1114.
Greg Reddick is the president of Gregory Reddick & Associates, a software consulting company specializing in developing solutions in Microsoft Windows using C/C++, Access, and Visual Basic. He worked for four years on the Access development team at Microsoft, and has co-authored two Access books. Greg can be reached at (206) 881-6879 or on CompuServe at 71501,2564.
Editor's Note April, 1998. Although originally written for Microsoft Access 1.x and 2.x, and Access Basic, the naming conventions in this article still apply equally well to current and forthcoming versions of Microsoft Access and to Visual Basic for Applications. The code samples in this article may need slight updating in order to run under Visual Basic for Applications.
If you've ever inherited a project from another developer, you know how frustrating it is to try to dissect another developer's style and maintain his or her code. When developers code with a common style, however, you can minimize these frustrations. To best share ideas and knowledge, the Access development community will benefit greatly if it adopts a common programming style so that we can benefit from each other's expertise with a minimum of translation overhead. Although Microsoft uses certain naming conventions in the Microsoft® Access documentation, to date they haven't published an official or comprehensive standard. Thus, we've formulated a set of naming conventions to better serve Access users and developers.
These conventions were originally published in the Charter Issue of Smart Access. Since then, we've logged thousands of hours of development time and scores of comments from Smart Access readers and other users of the conventions, and we continue to improve the style and make it more useful.
Our naming style ties Access conventions closely to Visual Basic® conventions because we recognize that many Access developers also use or plan to use Visual Basic for some data access applications. Access and Visual Basic are becoming more similar with each released version. We've written these naming conventions so you can also use them with Visual Basic database applications.
There are two levels to the naming style. Level 1 is comprehensive, but doesn't clarify objects as explicitly as Level 2. Level 1 is suitable for beginning developers, while Level 2 is intended for more experienced developers and developers involved in complex development projects and multiple-developer environments. You should experiment and choose the level that works best for you. (Please note that not all parts of the standard have two levels.)
If you're already using any previous version of our conventions, you may need to make a few changes to accommodate the enhancements in this revision. Because Access provides little help in renaming objects, you may wish to leave existing applications as is and apply the revised conventions to new projects, going back to existing applications as time permits.
Our naming style is based on a method of naming called Hungarian, referring to the nationality of its creator, Charles Simonyi (who, incidentally, worked on the first version of Access). Hungarian was first proposed in his doctoral thesis.
Some elements of Hungarian style are used in Microsoft's Visual Basic manuals and Development Kit documentation, among others. Microsoft uses Hungarian internally, and many programmers around the world use it as well. We've adapted the Hungarian style for the Access environment.
In our Access naming style, an object name is made up of four parts: one or more prefixes, a tag, a base name, and a qualifier. The four parts are assembled as follows:
[prefixes]tag[Basename][Qualifier]
Note The brackets denote that these components are optional and aren't part of the name.
The tag is the only required component, but in almost all cases the name will have the base name component because you need to be able to distinguish two objects of the same type. (Having the tag as the only required part may seem counterintuitive, but in Access Basic you can have code that deals with a generic form passed as a parameter. In this case you'd use "frm" as the parameter name; the base name isn't required except to distinguish it from a different form object variable in the code.). Here are a few examples:
Name | Prefix | Tag | Base | Qualifier |
tblCustomer | tbl | Customer | ||
aintPartNum | a | int | PartNum | |
strCustNamePrev | str | CustName | Prev |
Prefixes and tags are always lowercase so your eye goes past them to the first uppercase letter where the base name begins. This makes the names more readable. The base and qualifier components begin with an uppercase letter.
The base name succinctly describes the object, not its class. This is the name you'd likely give the object if you weren't using any particular naming style. For example, in the query name qryPartNum, "PartNum" is the base name; it's an abbreviation for Part Number. Object tags are short and mnemonic. Object prefixes precede some object names and tags and provide further information. For example, if an integer variable intPartNum is an array of part numbers, the prefix "a" for array is added to the front, as in aintPartNum(). Further, a variable that provides an index into the array would use the name of the array prefixed with the index prefix "i", for example, iaintPartNum.
Applying a naming style like this requires more effort up front, but try to imagine which of these two code samples will make more sense to you a year from now when you attemptto modify or reuse your code:
Z = Y(X)
or
intPart = aintPartNum(iaintPartNum)
Object qualifiers may follow a name and further clarify names that are similar. Continuing with our parts index example, if you kept two indexes to the array, one for the first item and one for the last, the variable iaintPartNum above would become two qualified variables—iaintPartNumFirst and iaintPartNumLast.
Database objects (tables, queries, forms, reports, macros, and modules) are the most frequently referenced items in an Access application. They appear in your macro code, in your Access Basic routines, and in properties. Thus, it's important that you standardize how you name them.
Microsoft's examples in the Northwind Database and Access manuals allow for spaces in object names, but we don't use them in our style. In most database engines and programming languages, including Access Basic, a space is a delimiter character between items, it isn't a logical part of an item's name. Also, spaces in field names don't work in most other database platforms or Microsoft Windows®-based applications such as Microsoft SQL Server™ or Word for Windows. Instead, use upper and lowercase designations in names, such as tblAccountsPayable. If spacing is still necessary, use the underscore (_) character instead of a space to be consistent with traditionally accepted SQL syntax and with Access 2.x function naming conventions.
All database container object names in our style have tags. Adding tags to these objects may make them less readable to nondevelopers, but new users will understand their value when they're trying to discern a table from a query in the listbox for a New Report wizard or a form's Control Source property. This is because Access merges table and query names into one long list. Here are Level 1 database container object name tags:
Object | Tag | Example |
Table | tbl | tblCustomer |
Query | qry | qryOverAchiever |
Form | frm | frmCustomer |
Report | rpt | rptInsuranceValue |
Macro | mcr | mcrUpdateInventory |
Module | bas | basBilling |
At Level 1, the only name qualifier (appended to the name) that we use for database container objects is Sub, which we place at the end of a form or report name for a subform or subreport. The form frmProductSupplier would have the related subform frmProductSupplierSub. This allows objects and their subform or subreport to sort next to each other in the database container.
Level 2 tags, shown here, provide more descriptive information.
Object | Tag | Example |
Table | tbl | tblCustomer |
Table (lookup) | tlkp | tlkpShipper |
Query (select) | qry (or qsel) | qryOverAchiever |
Query (append) | qapp | qappNewProduct |
Query (crosstab) | qxtb | qxtbRegionSales |
Query (data definition) | qddl | qddlAddWorkColumn |
Query (delete) | qdel | qdelOldAccount |
Query (form filter) | qflt | qfltSalesToday |
Query (lookup) | qlkp | qlkpStatus |
Query (make table) | qmak | qmakShipTo |
Query (pass-through) | qspt | qsptArchiveQuantity |
Query (union) | quni | quniOrderDetail |
Query (update) | qupd | qupdDiscount |
Form | frm | frmCustomer |
Form (dialog) | fdlg | fdlgLogin |
Form (menu) | fmnu | fmnuUtility |
Form (message) | fmsg | fmsgWait |
Form (subform) | fsub | fsubOrder |
Report | rpt | rptInsuranceValue |
Report (subreport) | rsub | rsubOrder |
Macro | mcr | mcrUpdateInventory |
Macro (for form) | m[formname] | mfrmCustomer |
Macro (menu) | mmnu | mmnuEntryFormFile |
Macro (for report) | m[rptname] | mrptInsuranceValue |
Module | bas | basBilling |
Using our Level 2 style causes objects with similar functions to sort together in the database container in large applications. Imagine that you have a database container with 100 forms in it (we do!), 30 of which are messages that display during the application. Your users now want all message forms to have red text instead of black, so you must change each of the 30 forms. Having the message forms sort together in the database container (because they've all got the same tag) saves you significant effort trying to discern which forms you need to change.
Choose your table names carefully. Since changes to the names of Access objects do not propagate through the database, it is important to name things correctly when the object is created. For example, changing the name of a table late in the development cycle requires changing all the queries, forms, reports, macros, and modules that refer to that table.
You may want to name each database object that refers to a table with the same base name as the table, using the appropriate tag to differentiate them. For example, if your table is tblCustomer, its primary form would be frmCustomer, its primary report would be rptCustomer, and the macros that drive all of the events would be mfrmCustomer and mrptCustomer. We also suggest that you not make table names plural (for example, use tblCustomer, not tblCustomers), because a table usually holds more than one record, so it's plural by implication.
We use four database object prefixes:
Using tags in field names is a hotly debated issue, even between the authors of this article. Greg maintains that tags in field names uniformly apply the naming style across all database elements and further document your work in Access Basic routines and form or report properties. Stan prefers that the database schema remain pure (platform- and data type-independent) for migration and connectivity to other products or platforms. He prefers that a field name remain independent of its data type.
Consider both positions, along with your unique needs, when you choose whether to apply the field name tags shown here:
Field Type | Tag | Example |
Binary | bin | binInternal |
Byte | byt | bytFloorNum |
Counter | lng | lngPKCnt |
Currency | cur | curSalary |
Date/Time | dtm | dtmHireDate |
Double | dbl | dblMass |
Integer | int (C programmers may prefer "w") | intUnit |
Long | lng (C programmers may prefer "dw") | lngPopulation |
Memo | mem | memComments |
Ole | ole | oleEmpPhoto |
Single | sng (Some users find "sgl" more mnemonic ) | sngScore |
Text | str (Used as opposed to "txt" because a textbox control uses "txt". C programmers may prefer "sz") | strFirstName |
Yes/No | ysn (C programmers may prefer "f") | ysnDiscounted |
Notes:
Access forms and reports automatically assign the field name to the Control Name property when you create a new bound control. Having the control name and field name the same creates some ambiguity in the database schema and in some cases may cause errors in Access Basic code referencing both a control and a field with the same name. To resolve this situation, apply the naming style to form and report controls by inserting the appropriate tag from the list below, in front of the control name suggested by Access. For example, the control name for a field whose Control Source is LastName would be txtLastName.
At Level 1, we recognize that users need to know the difference between an active control and a label, but may not be concerned with the type of the control. Thus the control tags are as follows:
Object | Tag | Example |
Label | lbl | lblLastName |
Other types | ctl | ctlLastName |
Level 1 tags provide the minimum differentiation necessary to still prove useful in functions, macros, and program documentation. For example, the control tags above allow you to differentiate between labels, which aren't modifiable at runtime, and other controls, which accept values from code and users.
Level 2 control tags denote the specific type of the control on the form or report (see table below). This makes Access Basic code and macros more explicit with respect to the properties and events of the individual control.
Object | Tag | Example |
Chart (graph) | cht | chtSales |
Check box | chk | chkReadOnly |
Combo box | cbo | cboIndustry |
Command button | cmd | cmdCancel |
Frame (object) | fra | fraPhoto |
Label | lbl | lblHelpMessage |
Line | lin | linVertical |
List box | lst | lstPolicyCode |
Option button | opt | optFrench |
Option group | grp | grpLanguage |
Page break | brk | brkPage1 |
Rectangle (Visual Basic uses the term "shape") | shp | shpNamePanel |
Subform/report | sub | subContact |
Text box | txt | txtLoginName |
Toggle button | tgl | tglForm |
The only prefix for controls, "zs", appears at Level 2. It denotes system-level controls used by the form or code but not displayed to the user. Such controls usually aren't visible at run time but they may store temporary values or parameters passed to the form.
Using standardized and descriptive variable, constant, and function names greatly enhances the ability of developers to share, maintain, and jointly develop code.
Access Basic requires that each nonprivate procedure name in a database be unique. For a function called from a property on a form in Access 1.x, construct the function name as follows:
formname_controlname_propertyname
For example:
frmEmployee_cmdAdd_Push
This tells you that this function is called from the OnPush property of the control cmdAdd on the form frmEmployee. For a property that affects the entire form, just use formname_propertyname, as in frmEmployee_Open. If two or more controls on one form execute the same code, create unique functions for each using the naming style in this section, then have each of these functions call the same private function that contains the common code.
In Access 2.x, the code for controls on a form is stored attached to the form, so the form name is implied in the function and does not need to be in the function name. Thus, the example above becomes:
cmdAdd_Click
Macro names inside a macro group also use this format. In the macro group mfrmEmployee, the macro txtName_BeforeUpdate contains the actions for the txtName control's BeforeUpdate event. For example, the txtName control on your frmEmployee form would have one of these properties, depending on whether you use modules (Access 1.x), attached code (Access 2.x), or macros to implement the task:
1.x code:BeforeUpdate....=frmEmployee_txtName_BeforeUpdate()
2.x code:BeforeUpdate....=txtName_BeforeUpdate()
Macros:BeforeUpdate...mfrmEmployee.txtName_BeforeUpdate
You should prefix procedure names in library databases with a unique set of characters to prevent their names from conflicting with any other names from attached libraries. The prefix should be in uppercase letters, followed by an underscore, and be no more than four letters. For example, we prefix all the library function names for our mail-merge utility, Access To Word, with "ATW_". Global constants and variables in a library should use the same prefix because they must also be unique across the entire database name space. Similarly, it is important to use these prefixes in Declare statements to alias all external dynamic-link library (DLL) function and procedure calls.
Every Access Basic variable should have a type tag from the following list:
Variable Type | Tag | Example |
Container | con | Dim conTables as Container |
Control | ctl | Dim ctlVapor As Control |
Currency | cur | Dim curSalary As Currency |
Database | db | Dim dbCurrent As Database |
Document | doc | Dim docRelationships as Document |
Double | dbl | Dim dblPi As Double |
Dynaset | dyn | Dim dynTransact As Dynaset |
Flag (Y/N, T/F) | f | Dim fAbort As Integer |
Field | fld | Dim fldLastName as Field |
Form | frm | Dim frmGetUser As Form |
Group | gru | Dim gruManagers as Group |
Index | idx | Dim idxOrderId as Index |
Integer | int | Dim intRetValue As Integer |
Long | lng | Dim lngParam As Long |
Object | obj | Dim objGraph As Object |
Parameter | prm | Dim prmBeginDate as Parameter |
Property | prp | Dim prpUserDefined as Property |
QueryDef | qdf (or qrd) | Dim qdfPrice As QueryDef |
Recordset | rec (or rst) | Dim recPeople as Recordset |
Relation | rel | Dim relOrderItems as Relation |
Report | rpt | Dim rptYTDSales As Report |
Single | sng | Dim sngLoadFactor As Single |
Snapshot | snp | Dim snpParts As Snapshot |
String | str | Dim strUserName As String |
Table | tbl | Dim tblVendor As Table |
TableDef | tdf (or tbd) | Dim tdfBooking as TableDef |
Type (user-defined) | typ | Dim typPartRecord As mtPART_RECORD |
User | usr | Dim usrJoe as User |
Variant | var | Dim varInput As Variant |
Workspace | wrk (or wsp) | Dim wrkPrimary as Workspace |
Yes/No18 | ysn | Dim ysnPaid As Integer |
Our style doesn't use data-type suffixes such as $ and % on variable names, because the Access and Visual Basic documentation recommends against using these suffixes.
Tags for database object variables such as the Form and Report types are the same as those used for the objects. This helps when coding, because the variable you assign an object to (for example, tblVendor) usually has the same name as the object it references (tblVendor), providing you with consistent object names when coding.
It is common practice in programming for Windows to use uppercase names for constants, but the authors differ on how to treat constants. Stan prefers using the uppercase notation and adding a scope prefix (see below), so a global constant for a specific error might be gNO_TABLE_ERROR. Greg prefers to treat constants as typed variables without scope, for example, strNoTableError.
In the above table, we've added a variable type tag of "typ" for user-defined types, and suggest a convention that matches that of constants, because you can think of both user-defined types and user-defined constants as persistent, user-created objects. The recommendations for a user-defined data type syntax include the following:
Level 2 of the naming convention introduces scope prefixes for variables and constants. The scope prefix comes before any other prefixes.
Object qualifiers follow the variable name and further differentiate it from similar names. You'll probably devise a list of qualifiers relevant to the types of applications you develop, but here are some of our common ones:
Variable Property | Qualifier | Example |
Current element of set | Cur | iaintCur |
First element of set | First | iaintStockFirst |
Last element of set | Last | iaintStockLast |
Next element of set | Next | strCustomerNext |
Previous element of set | Prev | strCustomerPrev |
Lower limit of range | Min | iastrNameMin |
Upper limit of range | Max | iastrNameMax |
Source | Src | lngBufferSrc |
Destination | Dest | lngBufferDest |
For Access Basic labels, we use a qualifier on the function name to create several standard labels. For On Error GoTo statements, we use the name of the function with the qualifier _Err appended, for example:
cmdAdd_Click_Err:
Some functions also have a label for jumping forward to the end of the function, because it's more appropriate to leave a function only in one place than to scatter Exit Function statements throughout a routine. We use the Done qualifier, as in:
cmdAdd_Click_Done:
Below is an example of an Access Basic routine using the naming conventions. Note these items:
Function EliminateNulls (ByVal vstrFieldName As String, ByVal vstrTableName As String) As Integer
' What: Replaces Null values with unique ascending integers
' A standardized version of a routine from NWIND and Chapter 8
' Author: Microsoft Created: 11/92 Last Revision: 5/25/94 By: grr/swl
' Passed in: field name and table name
' Returns: 0/-1
On Error GoTo EliminateNulls_Err
Dim db As Database
Dim dynTableSrc As Dynaset
Dim varCounter As Variant
Dim varCriteria As Variant
EliminateNulls = 0
Set db = CurrentDB()
Set dynTableSrc = db.CreateDynaset(vstrTableName)
varCounter = DMax(vstrFieldName, vstrTableName)
If IsNull(varCounter) Or IsEmpty(varCounter) Then
varCounter = 1
Else
varCounter = Val(varCounter) + 1
End If
varCriteria = vstrFieldName & " = Null"
' Iterate over all records in the table, throw out records with Nulls
dynTableSrc.FindFirst varCriteria
Do Until dynTableSrc.NoMatch
dynTableSrc.Edit
dynTableSrc(vstrFieldName) = varCounter
dynTableSrc.Update
varCounter = varCounter + 1
dynTableSrc.FindNext varCriteria
Loop
EliminateNulls = -1
EliminateNulls_Done: ' Jump here to clean up and exit
dynTableSrc.Close
db.Close
On Error GoTo 0
Exit Function
EliminateNulls_Err:
Select Case Err
' Handle specific errors here
Case Else
' Generic error handler here
Resume EliminateNulls_Done
End Select
End Function
Naming conventions never replace the judicious use of comments in your table definitions, macro code, or Access Basic routines. Naming conventions are an extension of, not a replacement for, good program-commenting techniques.
Formulating, learning, and applying a consistent naming style requires a significant initial investment of time and energy. However, you'll be amply rewarded when you return to your application a year later to do maintenance or when you share your code with others. Once you implement standardized names, you'll quickly grow to appreciate the initial effort you made.
If the entire Access community, including Microsoft, coded using one common naming style, we'd all find it easier to share information about Access. With this in mind, we submit these revised guidelines to the Access community.
This document accompanied the August 1994 issue of Smart Access Journal, published by Pinnacle Publishing, Inc. Earlier versions of these guidelines were published in the February and August 1993 issues of Smart Access.
This document copyright 1993-1994 by Stan Leszynski and Greg Reddick. It may be distributed freely as long as no profit is made from its publication or distribution, or from publications that include it, and the complete text is published or distributed without alteration of the content. All other rights reserved. Please send the authors a copy of any publication that includes this document.