On function headers
Last week I wrote about good practices in writing comment headers for source code files. Several readers wrote asking for my thoughts on headers for functions.
I recommend reading code. Lots of code. You’ll always learn something. Sometimes you’ll be delighted and inspired to follow the example set by a careful developer. Other times you’ll recoil in shock and horror – which is also a motivation to avoid those poor practices.
The first goal in creating a function header is to provide the casual reader with all of the information he needs to use the code. A secondary goal is to document what is going on in the function, including any weirdness that has to be accounted for.
Looking at some functions in Linux, here’s a clock setup routine for the AT91:
There’s no header, and no comments at all. Naming conventions are pretty good, though, which helps. But every function needs a header! In this case, what the heck is the return value? You’d have to dig through the header file to understand what those constants are, assuming they are constants.
Here’s a single Linux header that applies to 13 functions. One function declaration is included to give a sense of the problems:
The header comments are nice and descriptive of the problem being addressed. But none of the functions are described – what does simulate_bbl do? None of the passed parameters are described, which is an enormous no-no. Don’t make the reader work to understand how the function ties in to the rest of the code. And I don’t care for using a leading asterisk on each line; it makes it that much harder to maintain the comments.
Sadly, Linux is peppered with poorly-documented functions.
Sometimes, as in FreeRTOS, the function header precedes the prototype and is absent in the function itself. I feel this is a mistake. The prototypes are there to ensure type compatibility and are usually glossed over by people reading the code. If you’re trying to understand a function, the documentation should be part of that code, not at the beginning of the file, or in an include file.
Here’s an example of what I like to see:
A narrative is short but complete. The goes-intas and goes-outas are described. The header uses the /* and */ comment notation with no leading characters on each line, making maintenance easier. Comments use proper sentence structure, spelling and are grammatically correct. I’d prefer a blank line before “Returns:” just to separate it from the inputs. A craftsman wants his code – and comments! - to work, but also to look nice.
That example was from a module where the author is identified in the file header, with the creation date. However, I prefer to identify the author and date in each function, since over time more functions will likely be added by other people. Putting the author’s name with the code does two things: It provides a link so others know where to go if more information is needed. And just as important, it’s an imprimatur, a stamp of the author’s approval. A craftsman will work hard to do a very careful job on any code where he effectively signs his name.
Function headers should include:
- A description of the function, including any odd things that must be accounted for. (E.g., in the previous example the quirky A/D is described).
- Author’s name
- A description of all passed parameters and the function’s return value
- The date of first release
- The developer’s name, date and a description of each revision
- Information about the code review
The code review information might be maintained in an external document, depending on a company’s procedures.
Some argue that the revision information properly belongs in the version control system. I agree that it should be there, but feel a decent argument can be made for including it in the header, as most people reading the code need to see it there and won’t care to call up the VCS.
Err on the side of wordiness rather than brevity in the description. A casual reader should be able to learn pretty much all he needs to know from these comments. No, it doesn’t need to be a blow-by-blow description of every DMA register setting, but under no circumstances should someone have to go to the code to figure out how to use the function.
Grammar, spelling and sentence structure are important. A description that reads the way some of the citizens in Baltimore talk will be perceived as an idiot. It’s easy to get these right when writing emails and documents since the tools autocorrect or at least identify errors. Why is it that editors, which are always C-aware, don’t parse out comments and signal at least the spelling errors? Even better, an editor could identify variables, types and the like which are declared in the source and header files and exempt those from spell-checks.
In my opinion, IDEs are still primitive affairs that poorly serve developers.
Take as much pride in your documentation as you do in your code. It’s just as important.
Jack G. Ganssle is a lecturer and consultant on embedded development issues. He conducts seminars on embedded systems and helps companies with their embedded challenges, and works as an expert witness on embedded issues. Contact him at firstname.lastname@example.org. His website is www.ganssle.com.