Perl Styleguide¶
Preface¶
If you want to learn about what to do in Perl and what to avoid, just read Perl-Best-Practices from Damian Conway. That excellent book is not only fun to read, it will tell you much more about Perl-programming than this short guideline could ever hope for.
Many recommendations from that book have actually been implemented in a Perl-module !PerlCritic. Pretty soon, OpenSLX will use this module to check Perl-code that has been commit to the OpenSLX repository (and reject it if it exhibits problems above a certain severity).
Introduction¶
The following paragraphs contain the conventions that shall be applied to OpenSLX Perl-code.
As there are quite a lot of rules, they have been split into different topics. Each entry is marked with a severity level - ranging from '!' (low) to '!!!' (high), with the most important rules being listed at the top of each topic.
Note: currently, these conventions are open for discussion, so please do not hesitate to ask for explanation or send improvements or comments - preferably to openslx-devel@openslx.org.
So, there you go:
Formatting¶
- !!!: 4 space indents, no tabs in code (unless inside a string, of course)
- !!!: 80 characters width per line. It's okay to exceed it for long string constants (but for nothing else).
- !!!: Opening curly on the same line as the keyword it belongs to
- !!!: Closing curly vertically aligned with the opening keyword
- !!!: Space after comma or semi-colon, but not before
- !!!: One Space between special keyword and its arguments:
if (...) { ... } - !!!: Extra spaces in code delimiting curlies:
sort { $a <=> $b } @foo - !!!: No space between keyword and its arguments if the "looks like a function, therefor it is a function" rule applies:
print(join ',', @bars), notprint (join ',', @bars). - !!!: Long lines: indent according to parens (or
[],{}, etc), but always 4 spaces. Like this:
$someLongVarName->thatInvokesAnInsanelyLongMethodNameTakingALotOfParams( 'blurb', 1, sub { my ($attr) = @_; return lc($attr) eq $attr; }, 'more blurb' ); - !!!: Long lines: continuing lines are indented
- !!!: Long lines: Lines end before operator (especially
=&&||) - !!!: No "outdent"s, no half indents and no double indents
- !!!: No spaces around:
->(and only break lines before->as a last resort) - !!!: Spaces around:
=~!~*/%+-.<<>>comparison_ops&|^&&||?:assignment_ops=>andorxor - !!!: No space between
++/--and the variable - !!!: Semi-colon never appears on its own line
- !!: Opening curly for subs on the next line, i.e. write
sub foo { if ($bar) { print "bar\n"; } } - !!: Uncuddled else:
} else { - !!:
?and:begin lines in complex expressions (and get indented, since a long line is being broken) - !!: No extra spaces around or inside parens: foo, (bar, baz), quux
- !!: Extra spaces in arrayref constructor:
[ foo, bar ] - !!: Extra spaces in hashref constructor:
{ foo => bar } - !!: No parens unless needed for clarity
- !!: No double spaces except for vertical alignment and comments
- !!: Empty line between logical code chunks
- !!: No space between array/hash and index/key:
$foor0,$foo{bar} - !!: Complex regexes get
/x(and are nicely formatted and preferably get comments, too) - !: No double empty lines
- !: No quotes for simple literal hash keys
- !: Space around index/key if it is complex:
$foo{ $bar{baz}{bar} } - !: Subs after main code in scripts
- !: Semi-colon only left out for implicit return or in single-statement block
- !: in every sub, separate argument shifting and implementation by a single line (and do the same for the final return statement):
sub showMsgIf { my ($msg, $func, $arg) = @_; return if !$func->($arg); print $msg, "\n"; return 1; }
Names¶
- !!!: code in English (identifiers, methods and comments)
- !!!: Multi-word identifiers use (lower)camelCase (i.e.
$thisIsSomeVarand$self->callAMethod(); - !!!: Lowercase identifiers, but uppercase for constants
- !!!: Never use
$_unless it is required (i.e. in map and grep) - especially use explicit vars in loops:
foreach my $attr (@attributes) { ... } - !!!: No single-letter identifiers (
$a,$bor$i) except when sorting or as an index - !!!:
$iis a(n index) counter - !!!: Give variables meaningful names that communicate their meaning:
$keyand$valueare pretty useless - name them for what they are (like:$attrNameor$attrValif you must) - !!!: Data type not represented in variable name:
%fooand@foo, but not%foo_hashor@foo_array. However:- data type of referent in reference variable names:
$bla_hashis okay - data type ref in reference variable names:
$hashrefis okay
- data type of referent in reference variable names:
- !!!: Dummy variables can be called foo, bar or anything else (but you don't really need those, do you?)
- !!: No abbreviations (acronyms are okay, and so are VERY common abbreviations), NEVER
@ary
Perl-stuff¶
- !!!:
use strictanduse warnings. Loading of normal modules comes after loading these two. - !!!: No
eval STRINGunless absolutely required, useeval {}instead - !!!: Always
Class->method, nevermethod Class(this includesnew!) - !!!: No
grep EXPRandmap EXPR, always use a BLOCK:grep {} @fooandmap {} @bar - !!!: Use
=>(fat comma) in hashes, use,(comma) in all other places - !!!: Use lexical filehandles (
my $inFHinstead ofIN) - !!!:
use base 'BaseClass'instead ofuse [[BaseClass]]and setting@ISA - !!!: Localization of globals if they're to be changed (especially with
$/) - !!!: Use
{}as delimiter for regexes and tr:$var =~ s{^this}{that}igms;- alternatively use[](but please avoid//) - !!!: True and false are always implied. No
$foo 0when testing for truth. - !!!: Don't be afraid of postfix if/unless, use them for oneliners if the "other" statement is the important thing:
prefer
return unless $haveParam;over
unless ($haveParam) { return; }and
print "trying $distroModule" if $verbose;over
if ($verbose) { print "trying $distroModule"; }but prefer
open(my $configFH, '<', $configFile) or die "unable to open $configFile ($!)";over:
die "unable to open $configFile ($!)" unless open(my $configFH, '<', $configFile); - !!!: Never pair
unlesswith!, useifinstead. - !!: Explicit returns from subs
- !!: Logical order in comparisons:
$foo 4, but never4 == $foo - !!: Use here-documents for multi-line strings (if they exceed two lines), use
unshiftHereDoc()(fromOpenSLX::Utils) to unindent them. - !!: Single quotes when double-quote features not used
- !!: Sane variable scopes (declare vars as late as possible)
- !!: No globals when access from another package is not needed
- !!: Whatever tool is useful: no OO when it does not make sense
- !!: It's okay to import symbols
- !!: Prefer
&&||!overandornot, unless the lower precedence is required (as inopen($inFH, '<', $filename) or die "bummer - no $filename!" - !!: Guards (
return if ...) are nicer than deepelse-blocks - !!: Always check return values where they are important (if in doubt: do check!)
- !!: Declare variables on first use, not before (unless required)
- !!: List assignment for sub arguments if there are many (>2), not lots of shifts:
sub foo { my ($bar, $doh, $pir) = @_; ... }but this is ok:
sub show { my $msg = shift; ... } - !: Error checking is done using or. This means 'open or do { ... }' instead of 'unless (open) { ... }' when handling the error is more than a simple statement.
- !: 'our $VERSION', not 'use vars qw($VERSION);'
- !: Direct '@_' access is okay in very short subs
Comments¶
- !!!: Comments where code is unclear
- !!!: Comments usually explain the WHY, not the HOW
- !!: Block comments precede the code block they relate to
- !!: Comments that follow code on the same line have four spaces before and one after the '#' symbol (unless vertically aligned with other comments above/below). If those comments need more space, they continue on the next line, but are vertically aligned:
-------------------------------------------------------------------------------- 1 2 3 4 5 6 7 8 ... return if $vomittingHorse; # I know it is unlikely, but nevertheless we # should check for it! ...