Best Practices
## Learning Objectives
- Write maintainable Perl code
- Use strict and warnings
- Master debugging techniques
- Apply testing practices
- Follow conventions
## Essential Pragmas
### Always Use strict
```perl
use strict;
# Forces:
# - Variable declaration (my/our)
# - Package qualification for globals
# - Bareword protection
my $var = "test";
# $untyped = "error"; # Would error
```
### Always Use warnings
```perl
use warnings;
# Warns about:
# - Using undef values
# - Bareword filehandles
# - Keyword shadows
# - etc.
```
### Combined
```perl
use strict;
use warnings;
# Or combined
use strictures 2; # Equivalent to strict + warnings (CPAN)
```
### Version Requirement
```perl
use 5.014; # Minimum Perl version
use 5.010; # Enable features like given/when
```
## Variable Declaration
### Use my and our
```perl
use strict;
use warnings;
# Lexical (scoped) variables
my $local = "scoped";
# Package (global) variables
our $global = "package-wide";
# Always declare before use
```
### Initialize Variables
```perl
use strict;
use warnings;
my $count = 0; # Initialize to known value
my @items = (); # Empty array
my %data = {}; # Empty hash
# Avoid undef where possible
```
## Naming Conventions
### Variable Names
```perl
use strict;
use warnings;
# snake_case for variables and functions
my $first_name = "Alice";
sub calculate_total { }
# Descriptive names
my $user_count = 0;
my $is_valid = 1;
# Avoid single letters (except $_ or common loop vars)
my $i; # OK for simple loops
```
### Package Names
```perl
# Use capital letters for packages
package My::Module;
package Data::Processor;
# Version with $VERSION
our $VERSION = "1.00";
```
## Code Layout
### Indentation
```perl
use strict;
use warnings;
if ($condition) {
do_something();
if ($other) {
do_other();
}
}
```
### Line Length
```perl
# Keep lines around 80 characters
my $very_long_variable_name = some_function(
argument1 => $value,
argument2 => $other_value,
);
```
## Error Handling
### die for Fatal Errors
```perl
use strict;
use warnings;
open my $fh, "<", "file.txt" or die "Cannot open: $!";
```
### eval for Recoverable Errors
```perl
use strict;
use warnings;
eval {
risky_operation();
};
if ($@) {
warn "Error: $@";
# Handle gracefully
}
```
### autodie Pragma
```perl
use strict;
use warnings;
use autodie;
# Automatically dies on failure
open my $fh, "<", "file.txt"; # Dies if fails
```
## References
### Always Dereference Properly
```perl
use strict;
use warnings;
my $arr_ref = [1, 2, 3];
# Dereference properly
my @arr = @$arr_ref;
my $first = $arr_ref->[0];
my $hash_ref = { a => 1 };
my %hash = %$hash_ref;
my $val = $hash_ref->{a};
```
### Avoid Symbolic References
```perl
use strict;
use warnings;
my $var = "hello";
# Bad - symbolic reference (blocked by strict)
# print ${"var"}; # Error with strict
# Good - direct reference
print $var;
```
## Subroutines
### Named Parameters
```perl
use strict;
use warnings;
sub create_user {
my %args = @_;
my $name = $args{name} // "Anonymous";
my $age = $args{age} // 0;
# ...
}
create_user(name => "Alice", age => 30);
```
### Early Returns
```perl
sub process {
my ($data) = @_;
return unless defined $data;
return if $data eq "";
# Main processing
}
```
## File Handles
### Lexical Filehandles
```perl
use strict;
use warnings;
# Always use lexical filehandles
open my $fh, "<", "file.txt" or die "Cannot open: $!";
# ...
close $fh;
# With autodie
use autodie;
open my $fh, "<", "file.txt";
```
## Regular Expressions
### Use /x for Complex Patterns
```perl
use strict;
use warnings;
# Readable regex
if ($date =~ /
(\d{4}) # Year
- # Dash
(\d{2}) # Month
- # Dash
(\d{2}) # Day
/x) {
print "Year: $1\n";
}
```
### Compile Regexes
```perl
use strict;
use warnings;
my $pattern = qr/\d{3}-\d{4}/;
if ($text =~ $pattern) {
print "Match!\n";
}
```
## Testing
### Basic Testing
```perl
use strict;
use warnings;
sub add {
my ($a, $b) = @_;
return $a + $b;
}
# Test
my $result = add(2, 3);
die "Failed" unless $result == 5;
```
### Test::More
```perl
use strict;
use warnings;
use Test::More;
sub add {
my ($a, $b) = @_;
return $a + $b;
}
is(add(2, 3), 5, "add(2,3) returns 5");
is(add(0, 0), 0, "add(0,0) returns 0");
done_testing();
```
## Documentation
### POD Documentation
```perl
use strict;
use warnings;
=head1 NAME
My::Module - Brief description
=head1 SYNOPSIS
use My::Module;
my $obj = My::Module->new();
=head1 DESCRIPTION
Long description...
=cut
```
## Debugging
### print Debugging
```perl
use strict;
use warnings;
use Data::Dumper;
my @data = (1, 2, 3);
print Dumper(\@data);
warn "Debug: $variable";
```
### Smart::Comments
```perl
use strict;
use warnings;
use Smart::Comments;
my $result = process();
### Debug: $result
### Expected: 42
```
### Devel::NYTProf
```bash
# Performance profiling
perl -d:NYTProf script.pl
nytprofhtml
```
## Security
### Taint Checking
```perl
#!/usr/bin/perl -T
use strict;
use warnings;
# $ARGV[0] is tainted
my $input = $ARGV[0];
# Must untaint
if ($input =~ /^(\w+)$/) {
my $safe = $1; # Now safe
}
```
### Input Validation
```perl
use strict;
use warnings;
# Validate email
sub is_valid_email {
my ($email) = @_;
return $email =~ /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
}
# Validate number
sub is_valid_number {
my ($num) = @_;
return defined $num && $num =~ /^\d+$/;
}
```
## Performance
### Avoid Global Variables
```perl
use strict;
use warnings;
# Bad - global
our $Global_Counter = 0;
# Good - lexical
my $counter = 0;
```
### Efficient Data Structures
```perl
use strict;
use warnings;
# Use hashes for lookups
my %lookup = map { $_->{id} => $_ } @objects;
```
### Memoization
```perl
use strict;
use warnings;
use Memoize;
sub expensive {
my ($n) = @_;
# ...
}
memoize('expensive');
```
## Modern Perl
### Use Modern Features
```perl
use strict;
use warnings;
use 5.014;
# Given/when
given ($value) {
when (/^\d+$/) { say "Number" }
default { say "Other" }
}
# State variables
sub counter {
state $count = 0;
return ++$count;
}
```
### CPAN Modules
```perl
# Modern alternatives
use Path::Tiny qw(path); # Instead of File::Spec
use JSON qw(to_json from_json); # Instead of JSON::PP
use Try::Tiny; # Instead of eval/die
```
## Summary
- Always use `strict` and `warnings`
- Declare variables with `my` or `our`
- Use meaningful variable names
- Handle errors appropriately (die, eval, autodie)
- Use lexical filehandles
- Compile regexes when used multiple times
- Write tests with Test::More
- Document code with POD
- Validate all input
- Use modern Perl features when beneficial
- Use CPAN modules for common tasks
Comments
Comments powered by Giscus
To enable comments, add your Giscus embed code here.
Learn more about Giscus →