The problem with documenting code is that if you do it too early, it's just another thing to keep updated along with the code. And if you wait until the end, then you have no time or inclination to add comments. An easy way is to document your code as you go.
Choose accurate, descriptive names for variables and functions
In this age of cut and paste and drop-down lists, you can take advantage of long names to make code self-explanatory. Grab a good thesaurus and use it as soon as you have some idea of what data the variables should hold. Granted, i, j, and k are excellent for index variables in short loops, but a specifically named loop index such as variable_name_idx makes it so much easier to figure out what's going on in a multipage procedure. And input_file_name is much better than ifname. (Is that a Boolean asking if the name exists or not?)
Use well-formed function names and skip stupid comments. If you have a C procedure called open_file() or close_file(), it better not need any documentation such as "This procedure opens a file." If it also does a lot of processing, then either move that capability or rename the function. The only time you'll want comments is for information that is beyond the scope of the procedure. Some folks refer to that as commenting on the intent of your code—the reason you're writing that block in the first place. Or, if you're expecting certain input values to be in a particular format or range, then document those expectations.
Write pseudocode and save it for documentation
Suppose you’re writing a process_data() function that will be very complex, perhaps checking file contents against valid values, updating a database, and sending notification to various users in various ways. Before coding, write some pseudocode to get your thoughts in order. It doesn't have to be verbose—just a list of function names with perhaps a one-line comment about what each will do. If a function is complex, then write some pseudocode for it, breaking it into well-named functions and a little bit of explanation for what will happen. The pseudocode and one-line explanation of the function can then be left in place as your documentation once you start coding.
While coding, if you run into any procedures that need further definition or should be broken into pieces, write the stub for the procedure immediately and a one-line explanation of what it is supposed to do (unless it is obvious from the procedure name). At the end, you'll have a complete program with documentation good enough for other developers to at least locate the place where they need to concentrate on updating or refining the code. For a pseudocode example, see Listing A.
Document the odd parts of your code
When it comes to documentation, some developers are inclined to say, “read the manual.” Others say you should document code if you have to look it up. But don't document the programming language, just your logic—and do so only if the language can't do it for you. If you have to look up parameters for some funky modem dialer or video driver, then documenting the parameter list and the place to find the manual is useful for the unfortunate soul who comes along two years later to fix some odd hardware problem. Of course, you may be that unfortunate programmer.
Sign your name
Leave your name on code that you write. Besides letting your coworkers know who wrote the code, you never know when you could pick up a consulting gig fixing some hack code that you wrote five years ago. That is usually the point when developers see the benefit of documenting their code.
Documenting code as you write may seem like a hassle, but it's worth the effort when you or coworkers have to modify an application written six months ago. Simply selecting variable names that make sense and turning pseudocode into documentation will save you time down the road.