http://qs1969.pair.com?node_id=221498

Just a short "thought for the day".

Yesterday, I found that I had a subroutine that I couldn't figure out how to name and I was forced to add comments to explain it. For the most part, I believe that well chosen names can eliminate much of the need comments, thus leaving comments only for those "you'll never figure it out on your own" moments. For example, with the following line, you can probably guess what is going on.

if ( tokens_are_the_same($token, $CONFIG{stack}[0]) ) {

If I had made the mistake of trying to do the entire comparison on the spot, it would have been terribly clumsy and confusing. To avoid such things, I often take confusing code and move it into its own function, even if it's not reused.

# if we have an expense account and the amount is too large if (4223 == $acct and $amount >= 100) {

Even the above simple example can do without a comment, when properly handled. We move the test into its own function and dispense with documentation that frequently wouldn't be updated anyway.

if ( excessive_expense_account($acct,$amount) ) {

One of the side benefits is that maintenance programmers are considerably less likely to change the sense of the test without changing the function name. If we just left the explanation as a comment, it may not have been changed.

This all leads to something interesting. If you can't figure out a good name for your function, what do you do? I sometimes struggle with this and I'll sit back in my chair and I'll restate what the function does. Usually the name of the function will just magically occur at that point. Yesterday, it didn't. I had a function that, not matter how many times I tried, I just couldn't figure out what to call it. It shouldn't be too hard from the following snippet to figure out which function I am talking about.

while ( my $token = $parser->get_token ) { if ( tokens_are_the_same($token, $CONFIG{stack}[0]) ) { $parser->unget_token( $token ); my ($html_chunk,$matched) = stack_match_or_current( $parse +r ); $html .= $html_chunk; $REPLACEMENTS{$file} += $matched; } else { $html .= $token->as_is; } }

What the heck does &stack_match_or_current do? To figure it out, you need to read the comments that I was adding to the top of that function. Further, this function was returning two values: some HTML and a value for the number of matches. It's rather clumsy and the poor maintenance programmer isn't going to figure it out very quickly. But here's what I have noticed, time and time again: if you can't figure out a good function name, look for a design problem. It's akin to a school teacher telling a student "if you can't write it down, you don't know what it means". In this case, I didn't know what my design problem was, but I knew it was probably there since I couldn't figure out the name of the function. My first two runs of the code exposed it.

By the time I had fixed the problem, the &stack_match_or_current function was merely returning a boolean value: does my stack match my current parser position or not? Once you get into the code, it makes perfect sense and it fixed my design issue. With the correct design, a good name of the function was obvious, &stack_matched, and the code was much cleaner.

while ( my $token = $parser->get_token ) { if( stack_matched($parser) ) { $html .= $CONFIG{replace}; $REPLACEMENTS{$file}++; } else { $html .= $token->as_is; } }

Cheers,
Ovid

New address of my CGI Course.
Silence is Evil (feel free to copy and distribute widely - note copyright text)