Node:How to Code, Next:, Previous:How to Implement, Up:Top



How to Code

Modularity

Be aware of the two levels of modularity

A program consists of different libraries, and a library consists of different object files (built from different source files). The following is not only true for the relationship between libraries, but also for the relationship between the different sources of a library, as well as the different sources of a program.

Make independent modules

If every module can be understood without reading the source of the other modules, people will understand the whole program better. If every module can be tested without relying on other modules, your code can get more stable. And, if every module can be debugged without digging through all the other code, you will be able to fix bugs much faster than otherwise.

Avoid circular dependencies in your modules. Avoid dependencies on too many other modules in a single module. Avoid modules that are tied together too strong.

Be clean in the headers

For C, the header files are the faces of your modules. If you put something in a header, you have to expect that people rely on it. Don't put implementation specific stuff in a header. Don't define structures in your header - define the structure in the main source, and simply put a type definition in the header, to make your structures opaque.

As every source file is a `low-level module', every source file must have it's own header if it exports symbols that other source files of the same `high-level module' (library or application) uses. Don't write a `big' header file in which you define all symbols that are shared among your library or application, as that would make the internal dependency structure of your modules very unclear.

And, of course, protect all headers against multiple including.

Be clean with what you include

The #include preprocessor directives are a way of documenting dependencies. Don't include what you don't need. Explicitly include every header you directly depend on, even if it's implicitly included in another header.

Be careful to use #include<...> for system headers and headers that are external to your project and #include "..." for your own headers.

In header files, only include other headers when the code in this header needs the other header. Foreign headers you include in the header of your library have to be present on every system where your library should be used.

In source files, include all headers the source depends on, even those already included in the source's own header. This documents clearly what your source depends on.

Use the right order for includes

If your project has a global configuration file (like autoconf's config.h), this must be included in every source file, and it must be included as the very first line of your code after comments, so that all other header files can react on the defines. config.h may only include #define's. Nobody expects code in such a file. Don't include config.h in a header file, unless you want to force all projects that use your header to have a config.h, too.

Next should be your source's own header file (where this source exports its external symbols). By putting no other includes before this, you implicitly check whether your header file is self-contained, i.e. if it contains all #include's it needs to compile.

Then, include all needed header files that are external to your project, with the most usual ones first. Last, include the needed header files of the other modules of your project.

Never put any code before the #include's. Nobody searches them somewhere else as at the very top of your source or header file.

Don't put code in header files

Nobody expects real code in files that end in .h.

Provide test code

When you write a module, you will write code to test it. That code is a part of the module. Put it in it's own file, document it, and make it a program that others can use to test if the module behaves correctly on their system. GNU Automake provides a very good means for running automatic tests when a program is built with make check.

Symbol names

Define and use a module prefix

Choose a prefix for a module, and use that prefix for all symbols in that module. If the module prefix is foo, then all public symbols of that module should start with foo_, and all private symbols with _foo_.

Name functions after the structure they operate on

If the module foo defines a structure bar, name the structure tag _foo_bar, define the structure tag in the main source, and define a type foo_bar in the header. Name all the functions operating on this structure beginning with foo_bar_. For example, name a function that frees the memory of the structure, foo_bar_free.

Make your private global symbols static

Well, that's the reason why we have static symbols anyway, isn't it?