codenode

"A designer achieves perfection when nothing is left to remove." —Saint-Exupéry

Code best practices

without comments


Perl Best Practices

I have been programming for just over tens years (professionally and personally). That does not compare to some people who have been programming 20 or even 30 years, but I feel that I have had enough experience to accumulate the following code best practices. Most of these best practices address questions of code design, style or organization rather than data structures or algorithms. In that sense, they are meta-code practices, independent of a particular programming language. I am inspired by the excellent book Perl Best Practices.

Below, in no particular order, are various meta-code considerations and that I have encountered while programming and the best practice that I have adopted for each.

If you die, tell me why

If a program exits other than zero (successfully, without errors), it should always print or log why it exited non-zero.

Although I’m pretty good about adhering to this philosophy, a user once reported that he couldn’t figure out why one program was exiting 1. I had to look at the code to figure it out.

The overarching philosophy here is that generally users don’t care when everything works ok (that’s what they want and expect), but they certainly care when things don’t work ok, when there’s a problem/error. Even worse is when something doesn’t work and the user doesn’t realize this until later. If a problem occurs that the user isn’t aware of, they may continue doing other things and those things could either not work either or seem to work but worsen the original problem.

Communicate like a human to humans

Consider these 2 lines:

Time range 2007-12-18 11:48:27 to 2007-12-18 11:48:27
Time range: all events occurred at 2007-12-18 11:48:27

They “say” the same thing, but the second line actually says what we humans come to realize after studying the first line. The second line communicates the point in a human-friendly way; this has two benefits: one, it’s quicker and easier to read, and two, it reduces possible misreads.

Overall, I’m of the opinion that computers aren’t human-friendly enough, especially since they’re supposed to make our work and/or lives easier, faster or whatever. Another good example that we’ve implemented is this output:

Cannot connect to MySQL because the Perl DBI module is not installed or not found. Run 'perl -MDBI' to see the directories that Perl searches for DBI. If DBI is not installed, try:
Debian/Ubuntu apt-get install libdbi-perl
RHEL/CentOS yum install perl-DBI
OpenSolaris pgk install pkg:/SUNWpmdbi

That error message clearly states the problem and tells you what to do that will probably solve the problem.

(These examples came from ideas proposed by Baron.)

Pass pure values

When passing values to functions/subroutines, etc., pass only “raw” values, that is, values without any meta-characters like quotes. The rational is simple: meta-characters are not part of the value itself.

For example, if we’re passing the name of a database and that database is called sales, pass a value containing just sales, not "sales" or 'sales' or `sales`, etc. Let the called subroutine quote or alter values as it needs.

Users are impatient

User’s are impatient. Always tell them what’s happening after N seconds of inactivity/waiting. I’m sure someone has done studies to determine how long before a user become impatient or beings to wonder what a program is doing. I would guess this value to be about 30 seconds. Slow programs are already frustrating enough, but worst is slow silent programs. It’s very satisfying when then program says after some time, “Here’s what I’m doing”. If it’s doing something important, perhaps the user will keep waiting because they know what they’re waiting for. Furthermore, if a program can’t say why it’s waiting, then it’s a poor program because it not only leaves the user in the dark, but its in the dark about its own internal operation, too.

Don’t mix tenses

Consider the variable name iters_done. “Done” implies the past tense. So if iters_done equals 1, then that means one iteration has been done. Ok simple enough, but that also means that the code is currently doing (present tense) the second iteration. A better variable name is iter (for “iteration”) which implies the present tense. So iter equals 1 during the first iteration, 2 during the second iteration, etc. Thus there is no mix of tenses.

Furthermore, iters can be more expressive in the case where you want to do something only for a particular iteration, let’s say iteration 1. Then you would code: if ( iter == 1 ) ... This is very clear that the conditional code only happens during iteration 1. Otherwise, you would have to code something like: if ( iters_done == 0 ) ... which makes it less clear that the conditional code happens during iteration 1 because the if checks if the var equals zero.

Make debugging easy

Debugging is already a pain, and when you get to the point that you need to use a debugger you certainly don’t want any further complications. Certain code styles are easier to debug, for example:

if ( ... ) {
   return "something";
else {
   return "another thing";
}

In that case the return in the if-else block create multiple points of return from the subroutine. It would be easier if they assigned their return values to a variable and there was one point of return at which you could set a breakpoint to examine the return value.

Don’t mow the lawn if the grass is short
(Avoid blind calls)

A blind call is a call to a subroutine without checking if the proper conditions exist that will allow the subroutine to work. For example, if sub meow() only works if option --cat was given on the command line, then calling meow() without first checking if --cat was given is a blind call, and these should be avoided.

The primary advantage to avoiding blinds calls is that it reduces uses function calls. Normally a function call isn’t expensive, unless the function is poorly written and it does a lot of work before realizing that it can’t complete.

The second advantage applies to the general performance philosophy that “the fastest way to do something is to not do it”. Or, more colloquially, you don’t mow your lawn when the grass is short and doesn’t need mowing. Doing so doesn’t hurt anything, but it doesn’t help anything either and only wastes your time.

Let the horse speak

The idiom “from the horse’s mouth” means information from the source responsible and authoritative for that information. For code this means that messages should be printed/logged/etc. from their true points of origin. Mostly this applies to messages announcing that the code has entered a subroutine. It is better to do,

sub foo {
   debug("Entered foo sub");
}

than,

debug("Calling foo sub");
foo();

Let messages about foo() come from inside foo() itself. Not doing this run the risk of inaccurate messages. For example, what if other code is put between the debug message and the sub call in the second example and that code somehow causes foo() to not be called (e.g. the other code returns early, dies, throws an exception, etc.). Then we’ll get a false-positive message saying foo() was entered when really it was not.

The inverse is true: don’t announce that the code has left foo() until the code has actually left foo(). That is, the message that says that foo() has been left should be outside of foo().

Express positive actions

Related to my post on double negatives, variables, arguments, options, etc. should express the action or result that will happen when their value is true.

For example, consider the variable “check_input” verses “disable_input_check”. Check_input expresses a positive action, something to be done, whereas “disable_input_check” expresses what not to do. The difference between the two given a true or false value is:

VALUE    check_input             disable_input_check
=====    =====================   =====================
TRUE     check the input         don't check the input
FALSE    don't check the input   check the input

 
The actions of check_input align more naturally with its value: the action happens when the value is true, and it does not happen when the value is false.

Written by Daniel Nichter

December 12th, 2010 at 2:56 pm

Posted in

Leave a Reply

Your email address will not be published. Required fields are marked *

*

4,058 Spam Comments Blocked so far by Spam Free Wordpress

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>