CHAPTER 7 : File Layout
7.2 Division of files
The first level of layout design is to decide what to put in what file. There are two guiding principles that can be used to help make these decisions:
(a) Ease navigation The files should be divided so as to help the reader find his way about the system as easily as possible.
(b) Minimize scope Items should not, where possible, be available where they are not used.
There is also the notion of visual scope where an item is placed as close to its point of usage as possible. This aids (a) whilst following the aims of (b).
It may not always be practical to follow these guidelines to the letter - however their spirit should always be taken into consideration when dividing files and when laying out files internally.
7.2.1 Definition and Scope
Items may be defined in another file or in this one, and may or may not be available or used outside the file or subsystem where they are defined. This gives several possible different levels of real and effective scope:
The scope of items within the file can be minimized by ensuring that all items referenced by only one function are kept private or local within the same file or function.
How do you decide what functions (and other items) to group together in one code module? Note that a module is defined as a single design unit, which may or may not be contained in one code file. A subsystem is collection of one or more modules that perform a coherent set of functions.
Constantine describes a number of levels of cohesion (described as the 'glue' that holds a module together). Within a module, the same rules can be applied to items when deciding what is to be put into one file. From the worst to the best, these are:
(a) Coincidental The functions in the module have no particular relationship with one another.
(b) Logical The module contains functions which perform similar tasks, e.g. I/O functions.
(c) Temporal The module contains functions which are performed at the same time, e.g. Initialization functions.
(d) Procedural The functions in the module might be linked on a flowchart. e.g. Data read and data process functions.
(e) Communicational The functions in the module operate on common data. e.g. database access routines.
(f) Sequential The functions in the module perform a 'transformation' on some given data. The module may represent a part of a data flow diagram.
(g) Functional All functions in the module contribute directly towards performing one single function. e.g. Get keypress.
The last three levels are generally considered to be acceptable methods of cohesion.
Functions in a file
There is a philosophy of putting only one function in each file, in order to simplify file access and editing from the operating system. This, however, moves the function management problems out to file management. It also results in all functions using external scope.
The scope of many functions can be minimized by having one public function and multiple private functions in a single file. This leads quite well to functional grouping of code functions. Thus, for example, a keyboard I/O subsystem might have the GetKeyPress() function defined in a single file, along with all functions that it (but no external function) calls.
However, most of the private functions that GetKeyPress() calls may also be required by CheckKeyPress(), which would mean that the private functions would have to be external. In this type of situation, the scope of the lower level functions can be minimized by putting GetKeyPress() and CheckKeyPress() in the same file.
7.2.3 File templates
Any file can contain any type of C statement, but there are three classes of source code files which are commonly used:
Code files which contain executable source code
Data files which contain global data definitions
Header files which contain common replacement items
A standard layout can be used for each file type to help to ensure that a common layout is used for all similar files. This can be helped in practice by using template files for each file type to be used. These will typically be simple editable files containing just the framework of the main comment headers.
7.2.4 File length
How many lines should files contain? Too many, and they become unwieldy and awkward to edit. Too few, and they become proliferous, filling up directories and making items harder to find.
Data and header files are usually shorter, and decisions on splitting have to be applied more often to code files.
It is useful to establish a guideline limit for maximum file size. A fair limit is around 1000 lines or 20 pages or 20 functions. Half of this is also reasonable.