Most people are more in favor of comments than they are in favor of writing comments. Most code doesn’t have enough comments, and the comments it has are often bad comments. Here are seven types of comments, listed from my favorite to my most disliked.
1. File Headers
I like to write file headers and I love to read file headers. These are multiline comments at the beginning of a program file. They contain information about the overall program or about elements that appear at multiple points throughout the program. File headers are an introduction to the program for other programmers and a refresher for the original programmer.
My file headers are fifty to one hundred lines long and include the following information:
- The names of the program, my organization, the person who requested the program (or provided the functional specs), and the person who originally wrote the program (me).
- The dates the program was started and first went into production.
- A description of the program’s purpose and function, and the service request that prompted program development.
- The Peoplesoft portal menu path, component name, page name, and run control table to run the program.
- The names and descriptions of any arrays used in the program.
- The names, aliases, operations (select, insert, update, delete), and descriptions of the database tables used in the program.
- The names, handles, record lengths, record types (fixed, vary), and operations (read, write, append) of any files used in the program.
- The names and descriptions of any user parameters used in the program.
- The names and descriptions of any flag variables used in the program.
- Special sections that vary from program to program. One program had a large number of similarly named variables. The variables used a consistent naming scheme that included abbreviations. I added a section to the file header with a glossary of those abbreviations.
- The maintenance history of the program, with each entry containing a date, programmer initials, description of bugs and changes, and a reference number (service request, error report, etc.).
Good practices make a lot of code self-explanatory.
- Descriptive variable names.
- Using substitution variables (constants) rather than literals.
- Consistent indenting to clarify program flow.
- Separating code into logical blocks with blank lines.
Some situations require more explanation. Comments are valuable here and should consist of simple but full sentences. If the situation is murky enough to need a comment, the comment should not be murky itself. Such situations include:
- Coding a complex business policy or calculation.
- Treating certain data differently from all the other data.
- Using an unusual algorithm to solve a problem.
An explanation should discuss why the program is doing what it does. It does no good and it may do harm to simply restate the code. For example:
! profits are revenues minus expenses
let #profits = #revenue - #expenses
Or, a few years later:
! profits are revenues minus expenses
let #profits = (1 - #tax_rate) * (#revenue - #expenses)
The first example shows how the comment adds absolutely no value. If we study it too long, we begin to wonder, was the proper variable name #revenue or #revenues? The second example shows that we’ve recognized the difference between pretax profits and post tax profits, we’ve decided to calculate post tax profits, and we’ve forgotten to update the comment. The comment was redundant, now it’s misleading.
Here are comments that provide a useful explanation. I am making the assumption (which I hope is not condescending) that not all programmers remember the definition of median, the floor function, and the remainder operator. I rarely use them myself. I’m also trying to save someone the trouble of tracking down the code that determines the value of #num_emp.
If I am over-explaining, just imagine this example featured whatever you find unintuitive: double declining balance amortization, economic order quantity procurement, chi squared statistics, bond yield to maturity calculations, Black-Scholes option pricing, etc.
! Median is a statistical term that refers to the value that has half the
! values in a collection above it and half below it. The only way to
! determine it is to sort the values and take the one in the middle. If
! there are an even number of values, there won't be a single value in the
! middle, so take the two values nearest the middle and average them.
! Sort the emp array by salary
! The #num_emp variable contains the number of entries in the array.
! The floor function returns the integer part of a number.
! The % operator returns the remainder of a division (#num_emp / 2).
let #middle_value = floor(#num_emp / 2)
if #num_emp % 2 = 0 ! even number
let #median_salary = (emp.salary(#middle_value)
+ emp.salary(#middle_value + 1)) / 2
else ! odd number
let #median_salary = emp.salary(#middle_value)
3. Procedure Headers
A procedure called “read_ps_job” that does nothing but read PS_JOB may not need a comment. If the selection criteria is particularly complex, there could be a comment there. More complex procedures deserve some description. We can discuss their purpose and methodology, any parameters passed to them or from them, and any assumptions they make about the context in which they’re used. Here’s an example of a procedure I wrote for a commonly used include file.
! This procedure obtains a value for one parameter from the run control
! table or an input statement, as appropriate. Call it as follows:
! do get_parameter('RUN_ID', 'Enter the pay run id: ', $run_id)
! do get_parameter('to_char(PAGE_NUM)', 'Enter page number: ', $page_num)
! move $page_num to #page_num
! The calling program must meet the following requirements:
! 1. Call procedure "stdapi-init" before calling this procedure.
! 2. Do not set a variable named "$run_control_table".
Some people use a line of stars (asterisks) or dashes, or a box of stars or dashes to highlight a comment or separate blocks of code. Like exclamation marks, they’re best used in moderation!!! I find it more helpful to use a text editor that I can configure to display comments in a different background color than the code, but I do like a line of asterisks before each procedure and a blank line after. Note that it is unnecessary to make a blank line a comment. We might choose to do it if the blank line is within a comment box or if we want our text editor to highlight it.
Some people initial and date every line of code they’ve changed. This practice often accompanies item six, below. I don’t like it. It’s not very informative and after a few years of bug fixes and enhancements, the code is cluttered. A better way to keep a history of the code is to get a source control system. Alternately, keep a copy of the program for each release level and use a file-difference utility.
6. Old Code
Keeping old code is even worse than keeping initials and dates. Imagine this code:
! where ERNCD = 'REG'
where ERNCD <> 'REG'
No matter how we try, we’ll read both lines of code. Now we have the memory that we’re selecting REG and the memory that we’re selecting every earning code except REG. It’s hard to hold on to the memory of which selection criterion is current and which is obsolete. If you think you can, now imagine several dozen pairs of code like that sprinkled through a program you don’t know.
Again, my advice is to get a source control system or a file-difference utility. If you belong to an organization that places low value on your productivity or your output, you can find either type of software for little or no money.
Now, look away and try to remember whether we are selecting or avoiding REG.
7. Not A Comment
When is a comment not a comment? A lot of programming languages support three scopes of comments,
- The remainder of the line (usually “//”)
- Part of a line (usually from “/*” to “*/”)
- Multiple lines (usually from “/*” on the first line to “*/” on the last line with no comment symbols on intervening lines)
SQR only supports the first scope; the remainder of the line. Instead of two characters that are not allowed together for any other purpose, SQR uses one character (!) that can appear in other contexts.
The exclamation mark can appear in string literals. To have SQR interpret it as natural language punctuation rather than the beginning of a comment, we have to have it twice (!!). This is the same convention as having two apostrophes in a string so SQR won’t interpret the apostrophe as a single quotation mark.
The exclamation mark can appear as part of the not-equals comparison operator (!=). In my first blog entry, on January 4, 2009, “Welcome to the Peoplesoft SQR Blog,” I wrote: “At that rate I think I’m good for at least six months before I begin blogging about the relative merits of <> versus != for not-equals comparisons. (And believe me, I do have an opinion on the subject.)”
My opinion is that I don’t like the latter. My text editor thinks != is the beginning of a comment and the SQR compiler agrees if it is at the first column of a line – but not if it is at the second or a later column.
!= 'A' This whole line is a comment, which triggers a compiler error
!= 'A' ! This is a valid version of "if $x != 'A'"
!= 5 ! This means “if x is not equal to five.”
!= 5 This is worst of all; it compiles without error to "if #x != 0"
I upgraded my website analytics on July 2, 2009 to get a better idea of which blog entries were most popular. The traffic dropped by 90% the next day! At first I thought all my readers were taking a three day weekend for America’s Independence Day, but the page hits stayed low for a week. (And that wouldn’t include the people who found me on Google Canada, Google India, and Google China.) Then I thought everyone (or 90% of everyone) had left for summer vacation. Then I was afraid that my latest blog entries were just too boring.
Welcome back everyone. Thank you for reading. You have no idea how much I missed you. Apparently, 2/3 of my readers use RSS pull down menus on their browsers to alert them to new entries on my blog. I’m flattered that you consider my website worthy of its own menu.