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?

Alex Balhatchet             Working for a small company

   Super Nerd since 1985       ~5 years of code
   Perl Hacker since 2002      582 modules
   Londoner since 2004         Lots of legacy code
   Paid Perl Hacker since      All Perl
   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
 Pragmas
 CPAN
 Best Perl Best Practices
 Legacy Code
 Perl::Critic & Perl::Tidy
 Questions
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 names
   stops you from using symbolic (string) references
   - stops you from writing terrible terrible code
   does 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 error
use autodie;

# enable say(), given(), state, etc.
use feature ':5.10'; # enable all of them
use feature 'say';                # enable one at a time

# make warnings throw exceptions
use 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 ignore
  Functions don't have to try to return two values
  Separate 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   while (my $line = <$fh>) {
($fh)) {                       # ...
   # ...                     }
}


warn "warning! something's   print STDERR "is this a warning? who
weird";                      knows?!";
Use builtins

if (defined $value){   if ($value){
    # stuff...             # stuff...
}                      }



my @files = glob("*.   my @files = <*.txt>;
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 tests
   Make sure there are good tests
   Change the whole file so that consistency is maintained
   Commit 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;                 foreach (sort keys %letters) {
  for (split //, $_) {      say "$_t$letters{$_}";
     $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 spaces
    restrict lines to 80 characters
    automatically line up "=>" characters in hashes and ","'s in lists
    add semi-colons where they belong
    un-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

Introduction to writing readable and maintainable Perl

  • 1.
    Introduction to writingreadable 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
  • 2.
    Who Am I? AlexBalhatchet Working for a small company Super Nerd since 1985 ~5 years of code Perl Hacker since 2002 582 modules Londoner since 2004 Lots of legacy code Paid Perl Hacker since All Perl 2006
  • 3.
    Who are youguys? Perl Oldies? Perl Newbies? Curious non-Perl types?
  • 4.
    I'm here toconvince 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); }
  • 5.
    Summary Pragmas CPAN Best Perl Best Practices Legacy Code Perl::Critic & Perl::Tidy Questions
  • 6.
  • 7.
    Always use strict use strictmakes your code safer requires that all variables are declared with "my", "our", etc. - stops you from making typos in variable names stops you from using symbolic (string) references - stops you from writing terrible terrible code does not allow non-subroutine barewords - stops you making typos in subroutine calls
  • 8.
    ...and use warnings use warningsensures 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
  • 9.
    Other Useful Pragmas #make open() and others die on error use autodie; # enable say(), given(), state, etc. use feature ':5.10'; # enable all of them use feature 'say'; # enable one at a time # make warnings throw exceptions use warnings FATAL => 'all';
  • 10.
  • 11.
    The CPAN The CPANis 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!
  • 12.
    Picking CPAN Modules With90,000 modules it can be difficult to pick the right one... Which is the right one for the job?
  • 13.
    Picking CPAN Modules Usethe 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)
  • 14.
    Picking CPAN Modules TheTask::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!
  • 15.
    Best Perl BestPractices
  • 16.
    Code in paragraphs Codewhich is written in paragraphs is much more readable. # get ready... read_commandline_arguments(); init(); # actual work here... do_stuff(); # output... format_output(); output_stuff();
  • 17.
    Throw Exceptions Modern programmingwisdom gives us many reasons Exceptions win out over error codes. Impossible to ignore Functions don't have to try to return two values Separate exceptional from non-exceptional cases
  • 18.
    Throw Exceptions Perl implementsExceptions 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 }
  • 19.
    Use builtins Builtins inPerl 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.
  • 20.
    Use builtins while (my$line = readline while (my $line = <$fh>) { ($fh)) { # ... # ... } } warn "warning! something's print STDERR "is this a warning? who weird"; knows?!";
  • 21.
    Use builtins if (defined$value){ if ($value){ # stuff... # stuff... } } my @files = glob("*. my @files = <*.txt>; txt");
  • 22.
    Use honorary builtins Thereare 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);
  • 23.
    Avoid overly confusingidioms 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!
  • 24.
    Avoid overly confusingidioms and cleverness What does this do? my $result = [ $result1 => $result2 ] ->[ $result2 <= $result1 ];
  • 25.
    Avoid overly confusingidioms and cleverness Maybe it's more obvious like this...   use List::Util qw(min); my $result = min($result1, $result2);
  • 26.
  • 27.
    Be consistent withexisting 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.
  • 28.
  • 29.
    Be consistent withexisting code If you change the existing code... Make sure there are tests Make sure there are good tests Change the whole file so that consistency is maintained Commit your changes to your VCS as a whole, without any other changes!
  • 30.
    Perl::Critic Perl::Critic, and itsbinary friend perlcritic, is a tool which will tell you what is wrong with your Perl code. % perlcritic my_script.pl
  • 31.
    Perl::Critic #!/usr/bin/perl use feature 'say'; open(IN,$0); while (<IN>) { chomp; foreach (sort keys %letters) { for (split //, $_) { say "$_t$letters{$_}"; $letters{$_}++; } } } close(IN); How many mistakes can you spot?
  • 32.
    Perl::Critic % perlcritic --verbose11 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!!
  • 33.
    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 spaces restrict lines to 80 characters automatically line up "=>" characters in hashes and ","'s in lists add semi-colons where they belong un-cuddle elses The perltidyrc file listed in Perl Best Practices can be found here: http://www.perlmonks.org/?node_id=485885
  • 34.
  • 35.
  • 36.
    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