Normalization

Introduction

Normalization is a term that we have borrowed from database theory, and which we define to mean absence of duplication of information. If information is duplicated, it must be updated in every place when modified---clearly a bad idea with respect to maintenance.

Duplication can occur unfortunately in several different ways, such as duplicated pieces of code, duplication of information between code and comments, between code and documentation, and so on. In the sections that follow, we'll explain how to avoid those pitfalls.

Normalization is enforced by the use of abstractions. Abstraction, in this context, means giving a meaningful name to a section of data definition or a section of code. The name should represent some useful entity that has meaning to the programmer.

Duplication of Code

Duplication of code occurs when the same piece of code, perhaps slightly modified, exists in several different places in the program. In other words, there is repetition of large chunks of code in the source. Such duplication should be avoided, for reasons of code size but more so for reasons of maintainability.

In contrast, for instance, a macro that creates a copy of a big chunk of code whenever instantiated may create a huge executable program, but that macro is no problem with respect to maintainability, as the body of the macro exists in only one place. Thus, there is no unnecessary, unmaintainable repetition.

However, overuse of cut and paste in the text editor can easily create duplicated code in the sense that we're warning against. Not only does this kind of repetition tend to fill up the screen, making it harder to see the structure of the program, but this kind of repetition also makes it necessary to find all the instances whenever some modification is necessary.

We solve this problem of repeated chunks of source code by liberal use of functional abstraction; i.e., whenever the same piece of code appears twice with no or only slight modification, we try to create a function that contains the code. The two occurrences are replaced by calls to the function, possibly with arguments accounting for the slight difference. Of course, it is not a good idea to create a function from an arbitrary sequence of instructions that happen to be similar. Rather, we try to identify pieces of code that have a specific purpose. We then assign a descriptive name to the piece of code in the form of a function.

Sometimes it is impossible to use functions to describe common pieces of code. In that case, we may use a macro. For instance, if the code contains a goto statement the target of which depends on the code instance, a function can't be used to capture the common parts of the code. The same goes if the parameter is a type. Usually, these two cases are the only times it is really necessary to use macros.

In fact, there are a few situations in which it is a serious mistake to use macros. In spite of ``traditional wisdom,'' the use of macros for speed should be avoided. For one thing, modern RISC processors have very little procedure call overhead, so using macros in that case in hopes of gaining speed really doesn't buy you anything. Moreover, there is a tendency among programmers to be mistaken about which parts of a program have performance problems. When you don't really know where the performance bottlenecks are, creating macros for unnecessary optimizations is a waste of time and makes debugging harder. Finally, macros tend to increase the size of the executable program (not really the same problem as the size of the source code).

Because of limited size cache memories, unnecessarily repetitious code can actually make the program slower. In such situations, increased use of functions would actually be advantageous to cut down on repetition in the source code and in the executable.

Duplication of Information Between Code and Comments

One might think that commenting the code is always a good thing, but there is also a risk with commenting the code: namely, that information is duplicated. Comments that paraphrase code should be avoided. In contrast, comments that explain passages that might need additional explanation are generally useful, as well as comments that identify the author and explain the purpose of a module. Here are some kinds of comments that should be avoided.

Comments that Document Function Headers (a bad idea)

ANSI C function headers contain the name of the function the number of arguments, the name and type of each argument, and the type of the return value of the function. There is no need for an additional comment explaining these things. Indeed, it is common that programs written where such additional comments are mandatory contain inconsistencies between the code and the comments. The explanation for such anomalies is simple: the maintainer is under pressure to get the code fixed and so modifies the program but not the comment.

Comments to Variable and Field Definitions (a bad idea)

The purpose of a variable or of a field in a structure should as much as possible be evident from their name. If additional information is necessary, a comment may be added, but then the comment should not repeat the name or the type of the variable, but instead give only the additional information. Rules that require a comment for each variable usually generate duplication of information and should thus be avoided.

Comments that Paraphrase Code (a bad idea)

Comments to pieces of code should provide additional information. Comments that only paraphrase code create maintenance nightmares. The classic example is:
  i++; /* increment i */
but there are many others. Indeed, even comments that provide additional information can be avoided by replacing them with a function that contains the code to be commented. The name of the function provides the additional information. For instance, instead of explaining that certain lines invert a matrix, one could create a function called invert_matrix that contains the code to be commented. This is an example of an abstraction that is not created for multiple use, but only for the purpose of giving it a name.