package Coding::Conventions; =head1 General Coding Coventions id3 coding conventions such as they are (take with a reasonable pinch of salt and a sprinkle of cayene pepper and perhaps a twist of lime): scalars ie $var passed to and from subs a plain scalars if they are short ie a file name or similar or as a ref \$var if the are long ie file content arrays always passed to and from subs as references ie \@stuff or [ @stuff ] note that these are the same. you deref them like @stuff = @$stuff_ref or $bit_of_stuff = $stuff_ref->[1] - second array element hashes as for arrays \%hash. deref %hash = %$hash_ref or @keys = keys %$hash_ref or @values = values %$hash_ref or $value = $hash_ref->{key} if you pass a list to a sub ie foo(@files) you can't ever add a new arg without buggering everything that uses foo() - pass refs then you can do foo( \@files, $some_stuff_i_forgot, $more_forgotten_stuff ) without breaking the existing coed base. on the note of passing stuff to subs if you do this sub foo { my $arg = shift; you often will scratch your head if you add an arg like and forget to change the shift to @_ sub foo { my ( $arg1, $arg2 ) = shift; # :o) this bug is quite common as $arg2 is always undef. as $arg2 is often a new option it may not be obvious or caught in the current test suite. as a result i prefer to use this form (even for single args) sub foo { my ( $arg ) = @_; as it avoids the problem above and is a bit faster to boot. constants in UPPERCASE except Win32 camel hump constants in native form. vars all lower case. that way you never forget of have trivial syntax issues. perl is case sensitive remember. subs all lower case as well modules in usual form like Some::NewModule::Config under_score separated sylables and you will never have to think was that $filename or $file_name??? $password $passwrd $passwd $pass - when you start dropping random vowels and consonants..... use sensible var names that self document the code as a guide aim for < 15 chars for var/sub names. use more of less as appropriate. the aim is simply to self document the function/var. sub get_var_from_db_munge_and_return_as_ref { descriptive but a bit over the top. go with what feels about right. minimal globals ie $q = CGI object, $action plus constants. have good reason to add any others. efficiency like not having untainting code everywhere is a reason but of course you already subbed that didn't you... pass values to and from subs as a general rule and don't modify values en passant - ie if i do foo(\$var) i expect $var to still be the same. if i wanted to change it i would be explicit $var = munge(\$var) if it *might* ever change make it a constant. it will. never, ever hard code file paths - they often change never, ever allow a user to pass a full file path. always do my $BASE_DIR = '/widget/stuff'; my $PATH_RE = qr![^A-Za-z0-9_\.: -/]!; # remove all but these chars my $user_path = $q->param('user_path'); my $user_path = sterilize_path( $user_path ); sub sterilize_path { my ( $path ) = @_ ; return '' unless $path; # kill null byte hacks $path =~ tr/\0//d; # remove backslashes which can be use to hide ../ as \.\./ which # has the same literal meaning but does not match in the following RE $path =~ s!\\+!/!g; # now remove instances of ../../../ and various sneaky variants $path =~ s!\.\.*/!!g; # get rid of every char that is not on the allowed list $path =~ s!$PATH_RE!!g; return $path; } if you have to let them pass a full url then use this sub. it has had extensive hack attacks and is now (pretty) secure sub ilya_proof_path { my ( $path ) = @_ ; return '' unless $path; my ($type, $domain, $q_string ); ( $path, $q_string ) = split '\?', $path; $q_string =~ tr/\0//d if $q_string; 1 while $path =~ s/%([0-9a-fA-F]{2})/chr hex $1/ge; $path =~ s!\\+!/!g; $path =~ s![^\w :\./#-]!!g; $path =~ s!\.\.*/!!g; $path =~ s/^\s+//g; $path =~ s/ +/ /g; $type = $1 if $path =~ s!^(\w+):/+!!; $domain = $1 if $type and $type =~ m/(?:https?|ftps?)/ and $path =~ s!^([\w\.-]+)/!!; # tolerate win32 drive letters as a pseudo domain $domain = $1 if $type and $type =~ m/file/ and $path =~ s!^([A-Z]:)/!!; return $path, $type, $domain, $q_string ; } localise vars as much as possible with my max sub length ~ 1 editor page ie 35 lines as a guide. do it twice and sub it. if it made your head hurt the first time sub it. if it makes sense to be a sub... sub it. if you are really pleased with how clever that code is document it while you remember how (if) it works. you will probably be debugging it ;-) don't bother to do # this sub does a search and replace on word docs (no shit) # but you can probably guess that from the name duh... sub word_search_and_replace { instead do # word_search_and_replace( FULL_FILE_PATH, REF_TO_HASH_OF_TOKENS ) # tokens hash has FIND part as key REPLACE part as value # return ref to modified file content # this code is almost self documenting through good var names sub word_search_and_replace { my ( $full_file_path, $tokens_ref ) = @_; # [blah] return \$content; } strict (my declare vars with my) and warnings always. ensure initialized vars. if optional args to subs use $option ||= '' to set $option to null string if it was not passed. note don't send $option == 0 as 0 '' and () - empty array/hash are all false in perl. remember defined and exists if you need to deal with valid input of 0 or '' use diagnostics to explain warnings if they are not obvious - all diagnostics does is deliver the FM for each warning which save you having to RTFM document while you remember. good var and sub names save a lot of documentation. if it is long use pod, if short use inline # use qq!! here docs < to fix the line endings when your code chokes on *nix. typical error is bad interpreter for no good reason. NEVER TRUST USER INPUT NEVER TRUST USER INPUT NEVER TRUST USER INPUT consider the edge cases - file does not exist, no vital arg passed, etc deal with the edge cases, preferably without bothering the user unless you have to tell them something. use CGI::Carp 'fatalsToBrowser' in debugging but kill it in production as it give out too much potentially usefull info to a hacker. remember people will try to hack your code. don't let them. mess with their heads a bit if you wan't - redirect blatant hacks to security sites for instance or give the user a dump of their ip details, browser, etc and tell them you are watching. do this for your own amusement but don't let the paying customers see it. no more than low level profanity in comments and var names please. if you have personal tookit code that is well tested but does not satisfy the spec (other than strict and warnings) by all means drop it in unchanged - working tested code is better than new untested code that satifies some arbitrary guidelines. pop a note to that effect in the comments and you won't even get chewed out in the code review ;-) Well maybe. Management reserves all rights to complain about anything at any time for any reason. They also reserve their right to change their opinion for totally incomprehensible and irrational reasons. You know how it is..... You do read Dilbert don't you. BTW why aren't we doing this in Java, I heard Perl was dead (just kidding!) Oh and fax me through a copy on green paper. Better send me an email in triplicate while you are at it. our perl is invariably #!/usr/bin/perl on *nix. X:/Perl/bin/perl.exe on Win32 where X: is any convenient drive with space. Usually not C: =cu