General Rules for Writing Code


A naming convention is the most important part of a coding standard, but it does not exist within a vacuum. Even the most thoroughly thought out standard will break down unless the architecture of the software follows a few simple rules. And of course, any standard is useless unless it fits the needs of the people involved and the problem at hand.


The Principle of Functional Cohesion

The Principle of Functional Cohesion shall be adhered to in all design, coding, inspection, and testing exercises. That principle is as follows:


A subroutine should perform one and only one purpose and contain only entities necessary for that purpose.

This principle should be applied at all levels of abstraction. That is, you can substitute the word "module" or "form" for "subroutine", and the advice will be just as practical.

Adherence to this principle has been shown to result in systems that are modular, modifiable, understandable, testable, flexible, and delightfully maintainable. The occasional performance costs of this approach should be viewed as a reasonable price to pay for the increased maintainability unless evidence overwhelming proves that only an in-line approach meets customer needs.

Top of Document.

If the customer can't read the code, rewrite it.

Each application is only valuable when it meets the needs of the customer. If the customer cannot tell what your program is doing, you do not know if you are meeting the customers needs.

Traditional programming approaches make the customer wait until the results are available to determine whether or not the program is doing the right thing. There are several disadvantages to this.

The primary disadvantage is that problems always are more expensive to solve when they are discovered late in the game. If your customer can read your code and identify any miscommunications early on, much wasted effort can be avoided. Have you ever had the experience of delivering an application to a customer only to find out that the customer wanted something different than what you had built. I know this has happened to me, and I have certainly seen it happen to others.

Secondly, if the customer can read the code, particularly in its early stage of development, exceptions can be identified by the customer and coded for. Many business applications are quite simple on the surface but can get quite complex when all of the exceptions are taken into account. Unless you are an expert in the problem domain, you will need the help of the customer in tracking down all of these exceptions. This is much easier when the customer can read the code.

Thirdly, if the customer can easily read and follow the code, you will be able to do the same. It is shocking the number of software professionals who need to study and decipher their own code just two weeks after they have written it. Six months later, the code often looks so strange to the people who have written it that they will even deny that they are the authors.

Top of Document.

Comments are for Whys not Whats

If the code needs comments to be understood, it should be re-written. Comments are still necessary, however, to explain why something is done one way instead of another.

Compilers do not care why you have chosen a particular method to solve a problem; humans do. When you are telling the compiler what you want to do, you should do that well enough and clearly enough so that the human can easily read and understand it. When you need to track information that is not used by the compiler, that's when you need a comment.

Replace any comment that explains what the program is doing with a subprogram call. While it is true this will slow down your program, the effects will be marginal unless the subprogram call is within a loop. Ignore any decrease in efficiency until your application is complete and you are fine-tuning to eliminate program slow-downs.

We'll take a look at a couple of examples that show how a lot of messy comments are replaced with subprogram calls.

Top of Document.

Pick a code organization plan and stick to it.

The location of a subroutine should be determined by the private information that it needs access to. This will happen almost as a matter of course if you adhere to the principle of functional cohesion.

In a language where the names of modules are significant, changing the location of a subroutine has exactly the same impact as changing the name of the object. Exercise the same degree of care, but always make sure that the name of a module accurately describes its contents.

Top of Document.

Favor Explicit over Implicit Constructs

Of course you should always have Option Explicit turned on, but that should just be the start of your use of explicit constructs.

For example, all variables should be of an explicit type if possible; so should parameters. The variant type should only be used when no other type can do the job.

Many languages provide you with the ability to set defaults. The most common is the ability to provide default parameter to subprograms. Defaults always seem like they save a lot of work, but do they really?

Top of Document.

Favor Named Notation over Positional Notation

Named notation is not only clearer than positional notation, it is considerably less prone to errors because of that clarity. Always use named notation when a subroutine has more than one parameter.

The major objection to named notation has been that it is more typing. This is an objection that should be dismissed as silly (Code is written once but read many times, Ichbiah). With the introduction of named notation in Visual Basic 4.0, the objection ceases to exist. The Object Browser actually makes it easier to use named than to use positional notation.

Top of Document.

Restrict Visibility.

Each object should always have its best possible name. Although it is almost always worth the effort to change an object name, every such change has a ripple effect. The broader the visibility of the object, the more work that must be done to make certain that the change does not cause errors.

Readers of your code should rarely have to ask the following questions. When these questions do come up, the answers should be quickly and easily determinable.

Where is the value of this object set?
How is the value of this object set?

If these questions are difficult to answer, the code may be easy to read but it will be difficult to understand completely. This is obviously more of a problem with variables than it is with constants.

Thus, global variables should be avoided entirely if possible and module-wide variables should be kept to a minimum. Careful use of parameters and local variables keeps all of the action right in front of you.

Constants are less of a problem because the value is only set once, but the scope of constants should be no broader than necessary. Do not forget that any global object persists throughout the life of the program, so that it continues to take up space even if nothing refers to it.

Top of Document.