Infrastructure

Error Tracking

Maintain a personal error log. I do it in HTML with this template:
<hr>
<b>Date: </b>
date
<br><b>Symptom: </b>
the-symptom
<br><b>Cause: </b>
the-cause
<br><b>Fix: </b>
the-fix
<br><b>Lesson: </b>
the-lesson
It makes each entry like this:
Date: date
Symptom: the-symptom
Cause: the-cause
Fix: the-fix
Lesson: the-lesson

At some point, I'll go through and try to organize the problems. For example, I've noticed that I often introduce bugs when I reorganize part of a program with a semi-mechanical transformation, so I need to watch those more carefully. There are existing defect classification schemes; soon I'll adopt one. (Example: DEC's two-letter codes (UE=user error, RN=next release, etc.), Orthogonal Defect Classification, others.)

Directory Organization

There are two types of deliverables: libraries and applications. A library is a set of objects designed to work together. An application is a full program.

A library consists of several things: a set of (usually one or more) header files, a library for linking, and documentation. Libraries will be used by one or more applications, and should be developed as separate products. Libraries may depend on other libraries.

An application may consist of several things: an executable file, data files, and documentation.

This is the normal directory tree for a project:

    Name/
        data/
        doc/
        exports/
        lib/
            libr1/
                *.a
                *.h
                doc/
            libr2/
                :
        obj/
        src/
            Makefile
            part1/
                Makefile
                *.cc 
                *.h
                RCS/
            part2/
            :
data/
Data files for the library or application.
doc/
Documentation for this application or library.
exports/
A staging area for deliverables of this library or application.
obj/
Object files. A project is normally a number of relatively independent parts. (Each part might be a reasonable section for a programmer to work on.) Each part contains the object files. For each part, there is a corresponding library file created from its object files, and stored in the lib/ subdirectory. Parts do not build directly against each others' object files; rather, they link against the corresponding library file in lib/.
src/
Source files, for each part. There is a top-level makefile, and a subdirectory for each part. Each subdirectory will contain .h, .cc, and other source files. In addition, if using a source control like RCS, each subdirectory will have its own RCS subdirectory.
This structure may be tailored. If there is only one part, the files may be directly under the src/ and obj/ levels. If there is only one programmer, there may be a work/ subdirectory.

Individual programmers working on specific parts will copy/checkout the corresponding part to their own area, where they can mix source and object files as they wish.

Justification: This structure isolates the dependencies. It keeps it clear which things belong to which. It tries to reduce the number of situations where one part must grab a specific file out of another, whether for import, export, or general use. The separate object directory makes it easy to provide multiple object directories for different machines, or to let others build an object directory in their own area while the source is read-only.

Compiler

  • Compile with ALL error checking on (and fix what it complains about!). I can't believe all the people I've seen who haven't taken this step.
  • Integrate from the bottom up. For utility classes, I often provide a main routine full of tests. I surround it with "#ifdef DEBUG/#endif" so it won't be compiled that way by default. Compilers provide switches to let you define the macro when you compile it.

Copyright 1994-2010, William C. Wake - William.Wake@acm.org