posted 07-02-99 03:08 AM ET
tfs99: That Wizard of Oz reference! What can I say? It's so apropos.MtG: I wish I didn't have to agree with you, but yes, we used to have a course here called EPM 1 (Engineering Principles and Methods) in which we taught Turbo Pascal 6 graphics (all our budget could afford for many years) in first semester to a class half of whom had never been near a computer before (so the first week was teaching them the DOS command line).
After the basic training, they were instructed to organise themselves in teams of four, and each team was asked to choose a graphics software project froma list of about thirty.
By mid-semester, they were really in the swing of designing, implementing and testing their programs, and by end of semester when they were assessed, most of them had product that stood up well to the software industry's standards.
So the students made us happy, and the professionals are a sad, sad case.
Sure, we pushed the students hard for quality of design, but many of them were able to innovate solutions that I'd never thought of, so doesn't this suggest that the industry is driven by all the wrong goals?
Incidentally, here is the best way I know how to code. It's fast, it's accurate, it's bug-resistant.
The brief points are these, in order of importance.
1. Document.
2. Analyse.
3. Validate data.
4. Design and code top-down.
5. Reuse code.
Expanded, the points become:
1. Write the documentation first. That's the most important point, and it applies _all_ the way through the process. This means document every thing you intend to do, before you do it. This is the _only_ way to ensure that (1) the documentation is accurate, and (2) the program is correct.
So that you, the programmers, know what you want to do next, use block comments to record to your fullest knowledge, in clear language, what the following code is intended to do, before you type a jot of code. (How easily one otherwise gets distracted and forgets!)
2. Analyse the problem with mathematical precision, that is with an eagle eye for structure and pattern. Once you see a pattern, study it! Generalise it, reuse it wherever applicable. Document your analysis every step of the way. Lots of simple but accurate diagrams, please.
3. Validate data! After the first round of analysis, we must have a clear picture of the outermost organisation of the intended program, the data structures that will be employed, and what operations they will use. If not, analyse more until you do.
Now that you've described your data, you know what it means, and what values it can have. And now that you've structured your program, you know where the data is entering and leaving each logical block or module. *So every time it does, check it for validity.*
"What?", I hear the traditional Sloppy Joe programmer asking, "our slick code cannot tolerate such an overhead". On the contrary, of course it can. Since you've structured your design wisely (you have, haven't you?), most of the processing of the data has occurred in between the entry and exit points of the module, so a little validity checking won't hurt you at all.
Besides, if you really desperately want faster code, then it's high time you investigated better algorithms. (And documented them thoroughly, before using them.)
The great advantage of these thorough checks is that the code self-tests. The moment something goes wrong, your software raises its own hand and says "Here is the bug! And this is what's wrong!", and traces the problem for you.
Sounds magical, but it works.
Data entry and departure also includes memory allocation and deallocation. Don't ever assume that memory has been successfully allocated - always check it! And never forget to free memory when you no longer need it.
How do you remember to do these checks everywhere? The same way you remember anything - by systematically documenting them before you code.
Some C functions must be forbidden in code that's intended to be stable: for example, the functions that access memory without checking for overruns. Their behavior is not well-controlled, so program-wise they are intrinsically evil. (Like Erratic Lal and the Impossible Planet Busters from Nowhere.)
4. Design and code top-down. This should be called "outside-in" design. We're designing from the most general outer shell of the program, inwards to the specific calls to pre-existing compiler and library functions.
This is the iterative process. Document your most general intentions, but in clear, precise language. Pseudo-code is OK here, but make sure your _motivation_ for each design choice is recorded completely. Write this in block comments.
Then, and only then, start coding. Code under the comment, and code only what you said you would. If you change your mind ("Oh! I can see a better way of doing this!"), then change the documentation first.
Use clear and obvious names for the functions and data, even if they're a bit longer than your lazy fingers feel comfortable with. Unpronounceable and mysterious handles are fine in newsgroups and forums; but in code, sloppiness wins you the Blue Screen Of Death.
Now that your documentation and coding of the outer layer of the software onion are written, consistent, accurate, and look quite neat, you can repeat the process on each of the functions.
5. Reuse code. In most projects, one sees patterns recurring. This is a hint that there's structure here. You should find what it is (nail the concept!), and make it into a function or module, or data type or class (if you're using Object Oriented programming).
Now that you have objectified it, use it. Use it everywhere the concept applies. Use it and only it, and use it consistently, so that your program behaves in reasonable ways.
Finally, remember: your reputation's at stake, so only the best will do. Emphasise Quality and Thoroughness in Documentation, Analysis, Design, Code and Testing at every stage.
Example: a strategy game has 7 players. Key concept: player. A player is conceptually distinct from the book-keeping mechanism underlying the game, and can only communicate with the game through a clean interface that is the same for every player. Therefore, the AI player obeys the same rules as the human player, and has access to the same information, by the same means.
If an AI player has advantages, those advantages are all within the rules, and are thoroughly documented, and the AI cannot cheat.