Messages in this thread | | | Date | Wed, 16 Jul 1997 23:36:39 -0400 | From | "Theodore Y. Ts'o" <> | Subject | Re: Take a deep breath... |
| |
From: Keith Rohrer <kwrohrer@uiuc.edu> Date: Wed, 16 Jul 1997 19:59:54 -0500 (CDT)
In "traditional" programming situations, I strongly hold to "*You* shall comment what you write, especially its interface." It's much easier for an author to write what he means by his code in natural language, while he still remembers what he was doing, than for that same programmer to go back and remember things later, or for a third party to have to figure things out from scratch.
In cases where the code being added to the main kernel distribution is "stable" or "perfect and complete the first time", it's sort of okay to let documentation slide; after all, "it works", and people who need to figure it out will learn more by figuring it out than by having it told to them. Likewise, when the chief programmers are viewed as some sort of gods, you don't want them writing the documentation so people don't blindly believe the inevitable bugs in it.
...
All you say is true, and I do encourage the other Kernel developers to comment their code, and most especially there interfaces more. (I think I do a pretty good job of documenting the kernel code I write, although I'm obviously a biased source; I've had other people tell me that they think my code is relatively understandable and well commented, so there's so basis for my belief....)
However, there's a flip side to this --- a distressing trend that I've been seeing --- which is that more and more programmers seem to be helpless without documentation. While it is a not a skill which most Computer Science departments teach (unfortunately!), it is extremely, extremely useful to be able to look at code that may not be particularly well documented, and figure out What's Going On.
I call this the ability, for lack of a better name, "being able to jump between different levels of abstractions". It's a skill like any other where you get better with practice. One of my first and earliest ways I practiced this skill was disasembling Microsoft Basic on my CP/M machine. Sure, I had a disassembler which gave me the 8080 instructions, and marked out functions; but then I had to figure out what functions did, and once I figured out low-level functions, I would name them and try to figure out higher-level functions; other times knowledge of basically what a higher-levle function did would be enough to figure out what the lower-level function did.
The basic trick is that once you figure out a particular function does, you make a mental model of what it appears to be doing at an abstract level, and then check your guess by seeing what functions call that particular function. Some people like to use fancy cross-referencing tools to look up this information. I personally simply use "grep func_name *.c". Sometimes, while looking at the callers to a particular function, I'll need to look at some other low-level functions which get called by the higher-level function. Then I try to figure out how the various low-level functions relate to one another.
This whole process is a lot harder to explain than it is to actually do, once you get the knack of it. For example, it took me perhaps 10 or 15 minutes to figure out the new dcache interface. However, I probably spent less than 15-20 seconds at a time reading any one particular file. When you're figuring out an interface, it's natural to jump around between many different files, using grep and emacs's search function to quickly locate relevant pieces of code. In fact, during the initial stages, if you spend more than a minute or two looking at a file, you're in danger of concentrating too much on a particular tree instead of trying to figure out the general configuration of the forest.
The reason why I call this "jumping between different levels of abstraction" is because as you jump from file to file, you need to adjust your thinking to an appropriate level of abstraction. At each level of abstraction, there are certain gaurantees made by the interface layers surrounding the abstraction layer (both above and below), and the abstraction layer will itself perform some abstract operation. While you're focusing on a particular abstraction layer, you won't care how a lower level function accomplishes its particular task --- only that it does do some abstract operation which is needed by the current abstraction level of interest. Of course, later, when you look at the lower level abstraction, you *will* care how it goes about its job.
Hence, a flexible mind is needed to be able to rapidly refocus as you jump around. In fact, a very good analogy to consider is how your eyes look at some particular new landscape. A typical human will let their eyes skip all around the their field of view, stopping at each prominent landmark for perhaps 3-5 seconds before moving on. At each landmark, the eye will focus at the correct distance for that landmark, even if it means letting other objects (at different focal distances) go out of focus for a little while. While your eyes are doing all of this, your brain automatically integrates all of the input so that you end up with a coherent mental model of what's out there.
I encourage budding kernel programmers to try to develop this skill. Not is it only useful for Linux development, but I think you will find it invaluable in your "Real World" jobs as well. First of all, often times in the "Real World" (as opposed to the idealized world of Computer Science Courses), code is often not well documented or commented. This is particularly true since many companies have these pesky deadlines which cause development staff to cut corners.
Also, even if the code is well documented, the ability to quickly and easily jump between different levels of abstraction will allow you to more quickly master a new API and start using it. If any of you programmers want to someday become computer architects, start developing this skill right away. Rest assured it will come in handy many, many times during your career.
- Ted
| |