introduction to writing readable and maintainable perl
DESCRIPTION
An introduction to writing readable Perl code, for people who write Perl that other people may want to read. Covers the most important lessons from Perl Best Practices, and ends by showing how to use Perl::Critic to test that you are meeting the standards set out.Given at FOSDEM 2011TRANSCRIPT
Introduction to writing readable and maintainable Perl
Or
Perl Best Practices: The Best Bits
Or
Perl is more readable than Java!
Or
Your code is bad and you should feel bad
Who Am I?
Working for a small company
~5 years of code582 modulesLots of legacy codeAll Perl
Alex Balhatchet
Super Nerd since 1985Perl Hacker since 2002Londoner since 2004Paid Perl Hacker since 2006
Who are you guys?
Perl Oldies?Perl Newbies?Curious non-Perl types?
I'm here to convince you that Perl can be readable!
my @files = @ARGV;
foreach my $file (@files) { open(my $fh, '<', $file);
while (my $line = readline($fh)) { print $line; }
close($fh);}
Summary
PragmasCPANBest Perl Best PracticesLegacy CodePerl::Critic & Perl::TidyQuestions
Pragmas
Always use strict
use strict makes your code safer
requires that all variables are declared with "my", "our", etc.- stops you from making typos in variable namesstops you from using symbolic (string) references- stops you from writing terrible terrible codedoes not allow non-subroutine barewords- stops you making typos in subroutine calls
...and use warnings
use warnings ensures that odd things do not silently try to "do what you mean."
print(undef) - uninitialized value in print() 1 + "bananas" - non-numeric value in addition %hash = (1, 2, 3); - odd number of elements in hash
Other Useful Pragmas
# make open() and others die on erroruse autodie;
# enable say(), given(), state, etc.use feature ':5.10'; # enable all of themuse feature 'say'; # enable one at a time
# make warnings throw exceptionsuse warnings FATAL => 'all';
CPAN
The CPAN
The CPAN is by far the best thing about Perl.
http://search.cpan.org
90,000 modules! Using CPAN modules means your code gets maintained, bug-fixed and optimized for you!
Picking CPAN Modules
With 90,000 modules it can be difficult to pick the right one...
Which is the right one for the job?
Picking CPAN Modules
Use the CPAN Testers reports, rt bug tracker, and Reviews. Every Distribution will have these!http://search.cpan.org/dist/Data-Dumper/
CPAN Testers: PASS (561) FAIL (8) UNKNOWN (4) Rating: (9 Reviews)
Picking CPAN Modules
The Task::Kensho CPAN module is a documentation-and-dependencies-only distribution which can be used as a recommended modules list.Some highlights are...App::cpanminus, Test::Most, Try::Tiny, Devel::NYTProf, Perl::Critic, DateTime, Config::General, and App::Ack It's a great starting point!
Best Perl Best Practices
Code in paragraphs
Code which is written in paragraphs is much more readable.
# get ready...read_commandline_arguments(); init(); # actual work here...do_stuff();
# output...format_output();output_stuff();
Throw Exceptions
Modern programming wisdom gives us many reasons Exceptions win out over error codes.
Impossible to ignoreFunctions don't have to try to return two valuesSeparate exceptional from non-exceptional cases
Throw Exceptions
Perl implements Exceptions with strings and die(). die "Exception!"; You can use eval() to catch them, but the Try::Tiny module gives us Java-style try/catch keywords which are much nicer. try { stuff();}catch { # exception is in a lexically scoped $_ variable}
Use builtins
Builtins in Perl are sensible and readable, especially when your editor has decent syntax highlighting.
Perl is excellent at string manipulation and dealing with lists. Use it to its full potential.
Perl's builtins have well defined names and behaviours, learn to love them.
Use builtins
while (my $line = readline($fh)) { # ...} warn "warning! something's weird";
while (my $line = <$fh>) { # ...}
print STDERR "is this a warning? who knows?!";
Use builtins
if (defined $value){ # stuff...}
my @files = glob("*.txt");
if ($value){ # stuff...}
my @files = <*.txt>;
Use honorary builtins
There are a number of "honorary builtins" which are exported by core modules.
use Scalar::Util qw(looks_like_number openhandle);
use List::Util qw(first max min shuffle sum);
use List::MoreUtils qw(any all none uniq apply);
Avoid overly confusing idioms and cleverness
Perl lets you write code however you want.
TIMTOWTDI - There is more than one way to do it.
A big part of writing readable Perl is about admitting that some of the ways to do it suck!
Avoid overly confusing idioms and cleverness
What does this do?
my $result = [ $result1 => $result2 ] ->[ $result2 <= $result1 ];
Avoid overly confusing idioms and cleverness
Maybe it's more obvious like this... use List::Util qw(min); my $result = min($result1, $result2);
Legacy Code
Be consistent with existing code
This is an important rule, because it often contradicts all the others I've mentioned:
When dealing with an existing code base, be consistent.
Perl::Critic & Perl::Tidy
Be consistent with existing code
If you change the existing code...
Make sure there are testsMake sure there are good testsChange the whole file so that consistency is maintainedCommit your changes to your VCS as a whole, without any other changes!
Perl::Critic
Perl::Critic, and its binary friend perlcritic, is a tool which will tell you what is wrong with your Perl code. % perlcritic my_script.pl
Perl::Critic
#!/usr/bin/perl
use feature 'say';
open(IN, $0);while (<IN>) { chomp; for (split //, $_) { $letters{$_}++; }}
foreach (sort keys %letters) { say "$_\t$letters{$_}";}
close(IN);
How many mistakes can you spot?
Perl::Critic
% perlcritic --verbose 11 bad_perl.pl
Bareword file handle opened at line 3, near 'open(IN, $0);'. InputOutput::ProhibitBarewordFileHandles (Severity: 5) Using bareword symbols to refer to file handles is particularly evil because they are global, and you have no idea if that symbol already points to some other file handle. You can mitigate some of that risk by......
Contains the full Perl Best Practices text!!
Perl::Tidy
Perl::Tidy, and perltidy, is a tool for automatically tidying up Perl code to make it more readable.
It can...
convert tabs into spacesrestrict lines to 80 charactersautomatically line up "=>" characters in hashes and ","'s in listsadd semi-colons where they belongun-cuddle elses
The perltidyrc file listed in Perl Best Practices can be found here:
http://www.perlmonks.org/?node_id=485885
Questions etc.
Questions?
Contact Me
http://kaoru.slackwise.net/
@kaokun on Twitter
My Code
http://search.cpan.org/~kaoru/
https://github.com/kaoru/
Slides
http://www.slideshare.net/kaokun