Laying Out Software
30 July 2018, early morning
I wrote this in 2007, when my life was all C and C++. I was working on migrating something that morphed from a small focused C program to a larger messy C++ program. I don’t remember why I didn’t publish it at the time. I’m sure I had more I wanted to say. Or maybe this advice is bad and with my forgetting all the C++ I used to know I no longer remember why.
—
I should write some posts about cleaning up old and poorly written programs. As software develops over time it sometimes ends up a huge unmanageable mess. It takes concerted effort to keep source code neat and organized. Furthermore, spending the time to think about how you organize your software will save you time in the long run. So, my first piece of advice for you budding software developers — i’m looking at you here Shima — is that source files should be as small as possible, and no smaller.
If you are working in C++ (or a similar object-oriented language), header files should be used to declare classes, and source files should be used for their definitions. Inline function should go in their own file as well. You should be able to look at a file and know what its contents are. Languages like C++ are fairly easy to work with because the structure of your code in the file system generally mirrors the structure of the program as discrete objects.
When working with a procedural languages like C, it is sometimes harder to see where things should be delineated. It is easy to fall into the habit of having one mother-of-all header files that contains all your declarations, and one source file with all your functions. This is stupid. Code should be organized such that unrelated functions, typedefs, structures, etc, are kept apart. Digging through a 3000 line source file looking for a function definition will make you crazy. You shouldn’t need a fancy IDE to manage your software projects.
Regardless of the programming language you are using, related functionality should be grouped and declared in their own header files, with definitions of functions in their own source files. Dividing your source code neatly in this fashion allows code that requires this functionality to (ideally) #include
just the definitions it needs, and no more. You should be able to look at the #include
directives in source file and header files and understand the dependencies of the code contained within; you should be able to see the relationships between the functions in your program. If you are lazy about the file structure of your source this becomes difficult. Don’t be lazy.