in reply to Meaning of Maintanability and Functionality in Coding Perl

If I were to answer this in a few words, I'd say:

Consistency

Pick a style, and adhere to it when possible.

Self Documentation

One should write code such that it appears to do what it actually does. This also means that one should write code such that bad code appears to be bad. Joel of "Joel on Software" has an interesting write-up called Making Wrong Code Look Wrong touching this subject. He's talking about Hungarian Notation which you may not want to use, but the underlying idea is very important.

Document Assumptions

Almost all of the comments I've seen in my lifetime were completely useless, and what should be documented wasn't. The most important thing to document are the assumptions you (the programmer) made. For example, "$var must not be undef.", "This algorithm is only ideal for lists no bigger than XXX elements.", "The module may not be thread-safe." and "Uses features specific to Win32." are all valuable comments which document assumptions. These bits of information are not apparent from reading the code, therefore they must be documented.

On a less general note, I have a beef with documentation that fails to properly the causes and methods of failure of a unit. Very little is usually said about how a function might fail. I feel it's very important to document the state of relevant variables, structures and objects on failure.

Update: I incorrectly used the word "comment" where I meant "document". Fixed.

  • Comment on Re: Meaning of Maintanability and Functionality in Coding Perl

Replies are listed 'Best First'.
Re^2: Meaning of Maintanability and Functionality in Coding Perl
by Anonymous Monk on Oct 18, 2005 at 18:26 UTC
    The most important thing to comment are the assumptions you (the programmer) made. For example, "$var must not be undef.", "This algorithm is only ideal for lists no bigger than XXX elements.", "The module may not be thread-safe." and "Uses features specific to Win32."
    I understand that you were merely making stuff up off the cuff, but I think those are bad examples. Any assumptions should really be coded as assertions and the comments should explain why the check is there.
    #sub foo() which sets $var can never fail for such and such reason defined($var) or die "\$var must not be undef.\n" #I'm too lazy to make it work properly for all lists (@list > $XXX) or warn "This algorithm is only ideal for lists no". " bigger than $XXX elements." #cross platform compatibility is comming in version 9.0 ($^O eq 'MSWin32') or die "Platform not supported"
    ...etc.

      My mistake was in my word selection. I said "The most important thing to comment" when I meant to say "The most important thing to document" (like in the paragraph header). Those words are obviously not interchangeable. It is possible to document something with means other than comments. For example, the use of assertions are an excellent mean of documentation. I didn't mention the use of assertions specifically because I considered it an implementation detail and I was speaking at the conceptual level.

      Looking at assertions further, I don't think they are always the best choice. For example,
      ($^O eq 'MSWin32') or die "Platform not supported";
      could be replaced with
      ($^O eq 'MSWin32') or warn "Platform not supported";
      depending on whether the unit is known to use features specific to Win32 (die), or whether the possibly of running the unit on another platform was simply not considered (warn). This would be consistent with Perl's spirit of flexibility and permissivity. It's not always necessary to know that something won't work; it's often sufficient to know when it might not work.

      Any assumptions should really be coded as assertions and the comments should explain why the check is there. Really? What should the code do if, once promoted to production and deployed, the underlying assumptions are found to be wrong? What should those assertions *do* if they fail?

      It depends a lot upon the implications of the assertion failure, and it's often not an easy problem.

      What should I do if I catch a "POWER OUTAGE" signal on a machine with no UPS? It can't logically happen; so how should I code to handle it? Anything follows logically from a contradiction, so logically, any response I choose is wrong.

      What about just an I/O error from the disk? Should I write a message to the logfile (on disk) complaining that the disk is broken? Should I spam the user with repeated console messages? How do I continue after such a failure?

      It's bad if a program aborts when it doesn't need to. It's also bad if a program continues when it shouldn't. If you've got an situation that you didn't code for (can't legally happen), you don't know what to do.

      For example, why did you choose to die() in one case, and warn() in another? Why not carp() or croack() instead?

      The documentation for the *function* should tell the caller what the correct inputs and outputs are, and what error handling, if any, there is.

      That way, if I call your spiffy new function with data that I haven't vetted, I'll *know* what the error handling for the routine is, and whether or not it is suitable, without having to wade through the ugly implementation details of your code. Reading code should be a thing of last resort; documentation designed for humans should be the first avenue of attack, and only when code is broken should it have to be investigated manually.

      If you can't explain what your function does in plain English, then you need a simpler function (or English language lessons). Or both.

      -- AC