Module and Subroutine Layout


The Natural Language Naming Convention

  1. General Layout
    1. Subroutine Declaration
    2. Local Declarations
    3. Error Handler Enabler
    4. Body
    5. Exit Handler
    6. Error Handler
    7. End Statement
  2. White Space
  3. Declarations
  4. Indentation
  5. Line Continuation
  6. Nesting Control Structures
  7. Line Length
  8. Subroutine Length

General Layout

Even in a small project, it is convenient to find each entity used by your program quickly and easily. The most critical factor in being able to find things is consistency. You don't need to be a programmer or a database designer to appreciate this -- just put your keys and wallet in a different place each night. The bigger the project, the more important that consistency is.

The are several distinct sections to each Visual Basic module: Subroutine declaration, local declarations, error trap enabler, body, exit handler, error handler, and end. Each section serves a distinct purpose and is separated from the other sections by exactly one blank line.

Top of Document

Subroutine Declaration

The subroutine or procedure declaration should explicitly identify whether the routine is private or public, explicitly specify the types of any required parameters, and function subroutines should explicitly specify the return type.

Top of Document

Local Declarations

All declarations of local variables used in the subroutine shall be between the subroutine declaration and the error handler enabler. Declarations shall be one indentation level from the left edge.

Only one variable shall be declared per line.

All declarations shall be grouped by variable type. Do not use untyped variables.

Top of Document

Error Trap Enabler

A line of code in the format "On Error GoTo LabelXXX" will follow the declarations and proceed the first executable statement in the subroutine enabling error trapping and specifying the location (following the exit handler) of procedures that will handle the error.

Top of Document

Body

The Body of the code contains the code that performs the action described by the name of the subroutine. The body is where the work gets done. Where this standard makes references like "the main body of the program should fit comfortably on a single screen", this is the section that is under discussion.

Top of Document

Exit Handler

The exit handler follows the body. It should contain any necessary clean-up code and end with an exit statement. All exits from the program must be through the exit handler. The exit handler is typically where objects will typically be set to Nothing.

In error free execution, the program will flow directly into the error handler. If an error condition is encountered, the error handler should direct the program flow to the exit handler after the error has been handled.

Top of Document

Error Handler

The error handler follows the exit handler and proceeds the end statement. The error handler shall contain code to resolve all of errors OR explicitly propagate those errors to the calling routine. The error handler shall return control to an appropriate place in the body or to the exit handler after an error response has been selected.

Top of Document

End Statement

End Sub, End Function - don't erase them. VB writes these lines automatically when the subroutine is declared.

Top of Document

White Space

Use white space liberally to increase readability and understandability. Primarily, this means use blank lines to set off control structures and subroutine sections. The VB formatter will automatically provide consistent spacing among the terms of an expression.

Specifically, there should always be blank lines before and after the subroutine sections named here, before and after branching structures, and before any line that contains comment text and nothing else.

Consider blank lines to set off statements or sets of statements that are bound tightly together. Consider blank lines before elseifs, elses, and cases.

Top of Document

Declarations

Group all declarations together in the local declarations section of the program unit in which they are required. Put them directly after the procedure declaration and before the start of error handling.

Never put more than one declaration on a single line. List declarations alphabetically: first by variable type and secondly by variable name. When a procedure require many variables (generally a sign that some other design problem exists), separate declarations for each of the types used into their respective group.

Example

Sub Sample_Sub_Declaration ()

Dim Current_Database As Database
Dim This_Recordset As Recordset

On Error GoTo Sample_Sub_Declaration_Handler

Top of Document

Indentation

Use indentation to indicate control structures, set off error handling and exit code, and to indicate the beginning and end of clearly discrete structures. Four spaces shall constitute a standard tab stop.

Only labels, the beginning and the end of the subroutine, and the statement that initializes error handling shall extend to the left margin. Note that in a program that follows the standard layout format, each line that extends to the left margin marks the start of a subprogram section as listed above.

The following are all specific instances where additional indenting should be employed:

  1. All commands shall be indented one level from any control structure that selects them. (If...Then...Else, Select Case, and all loops)
  2. Each Case should be indented one level from the Select Case structure itself.
  3. All lines between an AddNew or Edit and the corresponding Update.
  4. All lines between an Echo False and Echo True.
  5. All lines between a SetWarnings False and SetWarnings True.
  6. All lines between a With and an End With.
  7. All continued lines must be indented at least two levels. Additional indentation is encouraged when it enhances readability and program flow.

Top of Document

Use of Line Continuation

The introduction of the line continuation character removes many of the inconveniences associated with long identifiers. Used properly, line continuation characters can enhance readability and understandabilty. They are absolutely essential for print control.

The primary potential concern with line continuation is making certain that continued lines can easily be distinguished from new lines. Thus, continued lines will always be indented at least two levels, and properly formatted continued lines will show a marked tendency towards right justification.

In Formal Parameter Declarations

Use line continuation characters so that only one formal parameter appears on each line. If the subroutine or function has more that one formal parameter, the first line continuation character shall be placed after the left parentheses so that no formal parameter is declared on the same line as the subprogram itself.

In Procedure and Function Calls

Whenever named notation is used , each parameter assignment shall be on a new line and indented at least two levels.

In Assignment Statements

Use line continuation when the length of any assignment statement forces critical information off the right of the screen in the default window width. Place the line continuation character before the assignment operator ("=" or ":=") and indent the continued line at least two levels. If the right-hand side of the statement still runs off the screen, use the other line continuation rules to break it up.

When Constructing Long Strings

Use line continuation characters to place each distinct element of a string in construction on a different line. The third and each subsequent line should be aligned with the second line of the string construction statement so that it is apparent that a single string is under construction.

In SQL Statements

Use line continuation characters to place each distinct clause of the SQL statement on a different line. The third and each subsequent line should be aligned with the second line of the SQL statement so that it is apparent a single SQL statement is under construction.

In Mathematical Operations

Use line continuation characters to place each distinct element of a mathematical operation on a different line. The third and each subsequent line should be aligned with the second line of the mathematical unless the specific operation on that line applies to more than one of the preceding lines. For example, if you are representing (a + b)/ c, align line three (/c) so that it is centered under the two preceding lines so that it is apparent that the total is being divided by c rather than just the preceding line. Use parentheses liberally where they enhance the clarity we are looking for.

It is clearly recognized that even the most carefully constructed formatting may be incapable of clearly representing complex operations. In many cases, you will have to settle for a best try and hope that it evolves into something you can understand at a glance. The more complex or obtuse a mathematical operation is, the more important it is to use whatever tools are available for clarification.

Top of Document

Nesting Control Structures

Limit nesting of control structures. In no case should nesting go more than three levels deep. Even two levels of nesting is a primary indicator of a violation of the principle of function cohesion.

Break out inner details into private subroutines or functions to reduce nesting when necessary.

Top of Document

Line Length

The primary determinant of line length is how easily readable the code is on the screen. A reader of the code should not need to scroll horizontally to read the code.

Since the goal of this guideline is obviously to increase the readability of the code, balance it carefully against the other factors that affect this virtue. For example, use line continuation characters rather than cryptic identifiers to stay within a certain line length.

Top of Document

Subroutine Length

The Principle of Functional Cohesion shall be the primary determinant of subroutine size.

If you the body of the subroutine covers more than one screen, take a hard look at your program. Given the high-level nature of Visual Basic, it's extremely likely that you that you are trying to make a single routine accomplish several different tasks.

Breaking each task out into separate subroutines encourages reuse and simplifies each portion of the job. When combined with a readable naming convention, calls to these new subroutines will double as documentation.

Note

Reuse and maintainability, not reliability, are the top reasons for keeping your routines as small as possible. Counter-intuitively, there are even a few studies that suggest that the most reliable average routine size is 200 lines!

If you do not break out each functionally cohesive routine, you will miss many opportunities for reuse. The smaller and simpler each subroutine is, the broader the opportunity for reuse.

In-lined code is simply not reusable. In-lining should be done only when absolutely necessary for performance reasons. Loops that iterate many times are the most likely candidates for in-lined code.

Small routines can make it easier and faster to track down bugs, particularly if you use something similar to our development error handlers. It should take less time to find the error in a routine that has ten lines of code than it does to find the error in a 250-line routine. You can find a needle in a haystack if the haystack only contains ten pieces of hay.

Top of Document