Programming Style

The issue of what constitutes good programming style is, of course, subjective, just as is the issue of what constitutes good writing style. Probably the best way to learn good programming style is to learn by example and to always keep the issue somewhere in the front of your mind while programming.

This is not the place to enter into a detailed discussion of programming style. However, in my opinion, the two most important maxims for good programming are:

Let us take the second point first. It is not possible to overestimate the importance of adding meaningful comments to your programs—at least any program with more than a few lines.

The problem is this: good programs are generally used many times during a reasonably long lifetime, which may be measured in months or even years. Inevitably, a programmer will want to return to his or her code to make changes (such as adding additional features) or to fix bugs. However, despite all efforts, programming languages are not as easy to read as spoken languages. It is just inevitable that a programmer will not understand (or perhaps not even recognize!) code that was written several months or years earlier, and must rely on carefully written comments to help reacquaint himself with the code. (This has happened to me more times that I would care to recall.)

Let me emphasize that commenting code is almost as much of an art as writing the code itself. I have often seen comments similar to the following:

' Set x equal to 5
x = 5

This comment is pretty useless, since the actual code is self-explanatory. It simply wastes time and space. (In a teaching tool, such as this book, you may find some comments that would otherwise be left out of a professionally written program.)

A good test of the quality of your comments is to read just the comments (not the code) to see if you get a good sense not only of what the program is designed to do, but also of the steps that are used to accomplish the program's goal. For example, here are the comments from a short BASIC program that appears in Appendix F:

' BASIC program to compute the average
' of a set of at most 100 numbers

' Ask for the number of numbers

' If Num is between 1 and 100 then proceed
   ' Loop to collect the numbers to average
      ' Ask for next number
      ' Add the number to the running sum
   ' Compute the average
   ' Display the average

Readability is also a subjective matter. What is readable to one person may not be readable to another. In fact, it is probably fair to say that what is readable to the author of a program is likely to be less readable to everyone else, at least to some degree. It is wise to keep this in mind when you start programming (that is, assuming you want others to be able to read your programs).

One of the greatest offenders to code readability is the infamous GOTO statement, of which many languages (including VBA) have some variety or other. It is not my intention to dwell upon the GOTO statement, but it will help illustrate the issue of good programming style.

The GOTO statement is very simple—it just redirects program execution to another location. For instance, the following BASIC code asks the user for a positive number. If the user enters a nonpositive number, the GOTO portion of the code redirects execution to the first line of the program (the label TryAgain). This causes the entire program to be executed again. In short, the program will repeat until the user enters a positive number:

TryAgain:
INPUT "Enter a positive number: ", x
IF x <= 0 THEN GOTO TryAgain

While the previous example may not be good programming style, it is at least readable. However, the following code is much more difficult to read:

TryAgain:
INPUT "Enter a number between 1 and 100: ", x
IF x > 100 THEN GOTO TooLarge
IF x <= 0 THEN GOTO TooSmall
PRINT "Your number is: ", x
GOTO Done
TooLarge:
PRINT "Your number is too large"
GOTO TryAgain
TooSmall:
PRINT "Your number is too small"
GOTO TryAgain
Done:
END

Because we need to jump around in the program in order to follow the possible flows of execution, this type of programming is sometimes referred to as spaghetti code. Imagine this style of programming in a program that was thousands of lines long! The following version is much more readable, although it is still not the best possible style:

TryAgain:
INPUT "Enter a number between 1 and 100: ", x
IF x > 100 THEN
  PRINT "Your number is too large"
  GOTO TryAgain
ELSEIF x <= 0 THEN
  PRINT "Your number is too small"
  GOTO TryAgain
END IF
PRINT "Your number is: ", x
END

The following code does the same job, but avoids the use of the GOTO statement altogether, and would no doubt be considered better programming style by most programmers:

DO
  INPUT "Enter a number between 1 and 100: ", x
  IF x > 100 THEN
    PRINT "Your number is too large"
  ELSEIF x <= 0 THEN
    PRINT "Your number is too small"
  END IF
LOOP UNTIL x >= 1 AND x <= 100
PRINT "Your number is: ", x
END

Readability can also suffer at the hands of programmers who like to think that their code is especially clever or elegant but, in reality, just turns out to be hard to read and error-prone. This is especially easy to do when programming in the C language. For instance, as a very simple example, consider the following three lines in C:

x = x + 1;
x = x + i;
i = i - 1;

The first line adds 1 to x , the second line adds i to x , and the third line subtracts 1 from i. This code is certainly readable (if not terribly meaningful). However, it can also be written as:

x = ++x+i--;

This may be some programmer's idea of clever programming, but to me it is just obnoxious. This is why a sagacious programmer always favors readability over cleverness or elegance.

Another major issue that relates to readability is that of modular programming. In the early days of PC programming (in BASIC), most programs were written as a single code unit, sometimes with many hundreds or even thousands of lines of code. It is not easy to follow such a program, especially six months after it was written. Also, these programs tended to contain the same code segments over and over, which is a waste of time and space.

The following BASIC example will illustrate the point. Line numbers have been added for reference. (Don't worry too much about following each line of code. You can still follow the discussion in any case.)

10  ' Program to reverse the letters in your name

20  ' Do first name
30  INPUT "Enter your first name: ", name$
40  reverse$ = ""
                  50  FOR i = LEN(name$) TO 1 STEP -1
                  60     reverse$ = reverse$ + MID$(name$, i, 1)
                  70  NEXT i
80  PRINT "First name reversed: " + reverse$

90  ' Do middle name
100  INPUT "Enter your middle name: ", name$
110 reverse$ = ""
                  120 FOR i = LEN(name$) TO 1 STEP -1
                  130    reverse$ = reverse$ + MID$(name$, i, 1)
                  140 NEXT i
150 PRINT "Middle name reversed: " + reverse$

160  ' Do last name
170  INPUT "Enter your last name: ", name$
180 reverse$ = ""
                  190 FOR i = LEN(name$) TO 1 STEP -1
                  200    reverse$ = reverse$ + MID$(name$, i, 1)
                  210 NEXT i
220 PRINT "Last name reversed: " + reverse$

Now, observe that lines 40-70, 110-140, and 180-210 (in bold) are identical. This is a waste of space. A better approach would be to separate the code that does the reversing of a string name into a separate code module and call upon that module thrice, as in the following example:

' Program to reverse your name

DECLARE FUNCTION Reverse$ (name$)

' Do first name
INPUT "Enter your first name: ", name$
PRINT "First name reversed: " + Reverse$(name$)

' Do middle name
INPUT "Enter your middle name: ", name$
PRINT "Middle name reversed: " + Reverse$(name$)

' Do last name
INPUT "Enter your last name: ", name$
PRINT "Last name reversed: " + Reverse$(name$)

The separate code module to reverse a string is:

' Reverses a string
FUNCTION Reverse$ (aname$)
   Temp$ = ""
   FOR i = LEN(aname$) TO 1 STEP -1
      Temp$ = Temp$ + MID$(aname$, i, 1)
   NEXT i
   Reverse$ = Temp$
END FUNCTION

Of course, the saving in space is not great in this example, but you can imagine what would happen if we replace the reversing procedure by one that requires several hundred lines of code and if we want to perform this procedure a few hundred times in the main program. This modularization could save thousands of lines of code.

There is another very important advantage to modular programming. If we decide to write another program that requires reversing some strings, we can simply add our string-reversing code module to the new program, without having to write any new code. Indeed, professional programmers often compile custom code libraries containing useful code modules that can be slipped into new applications when necessary.

It is hard to overestimate the importance of modular programming. Fortunately, as we will see, VBA makes it easy to create modular programs.

Generally speaking, there are two main groups of code modules: functions and subroutines . The difference between them is that functions return a value whereas subroutines do not. (Of course, we may choose not to use the value returned from a function.) For instance, the Reverse function described in the previous example returns the reversed string. On the other hand, the following code module performs a service but does not return a value—it simply pauses a certain number of seconds (given by sec):

SUB delay (sec)
   ' Get the current time
   StartTime = TIMER
   ' Enter a do-nothing loop for sec seconds
   DO
   LOOP UNTIL TIMER - StartTime > sec
END SUB

Functions and subroutines are extremely common in modern coding. Together, they are referred to as procedures .