Writing Robust Perl Code

Erwan Lemonnier

Swedish Premium Pension Authority (PPM)


$Revision: 1.12 $

Robust Code?

Robust Perl Code? 1/3

Robust Perl Code? 2/3

Robust Perl Code? 3/3

Killing myths

So... bug-proof your Perl code!

Issue number 1:

Education

Keep Code Simple

Use simple syntax

Comment regular expressions

the \x modifier:


    $a =~ /^\d        # start one digit
           _          # followed by an underscore
           [a-z]{10}  # and ten small case letters
           $          # and nothing more
          /x;

	

When you can't avoid magic

Protect advanced Perl code

Code Standard

Code Review

Open Source your Code

Personality

Issue number 2:

Assert the impossible

example:

    # by design, $a can only be 'foo' or 'bar'
    my $a = get_a();

    # but...
    if (!defined $a || ref $a ne '') {
        die "impossible!";
    } elsif ($a eq 'foo') {
        do_foo;
    } elsif ($a eq 'bar') {
        do_bar;
    } else {
        die "impossible!";
    }
	

Test, TeSt, tESt (TEST!)

Test, TeSt, tESt (TEST!)


    BEGIN {
        *CORE::GLOBAL::open = sub {
            return 0;
        };
    }

    my $in = open('file') || die "error: $!\n";

	

Issue number 3:

Be Paranoid

Database

Issue number 4:

Logging

Debug logs

    
    use Log::Dispatch;
    use Hook::Filter rules => 'filter_rules.conf', 
                     hook => ['Log::Dispatch::log',
                              'Log::Dispatch::log_to'];
	

Exceptions

Ok ok...

...bored?

Free the dogs! programming by contract!

Background

Contract programming 1/2

Contract programming 2/2

Class::Contract 1/2

Class::Contract 2/2

    package ClassName
    use Class::Contract;

    contract {
      attr 'data1' => HASH;
      
      method 'methodname';
        pre  { ... };
          failmsg 'Error message';

        post  { ... };
          failmsg 'Error message';

        impl { ... };
    };
	

Class::Agreement

	
    use Class::Agreement;	
		  
    precondition foo => sub {
        my ( $self, $value ) = @_;
        return ( $value >= 0 );
    };
    
    sub foo {
        my ( $self, $value ) = @_;
        ...
    }	  
	

Issues

We want something like

	
    use Sub::Contract;
    use Check::MyTypes;
    	
    contract('foo')
      ->in(\&is_foo_object, \&is_integer)
      ->out(\&is_string);
    
    sub foo {
        my ($self, $int) = @_;
        return "value is $int";
    }
	

More universal

Contract pool?


    use Sub::Contract::Pool;

    my $pool = get_contract_pool(); # singleton

    my @contracts = $pool->find(name_matches => "^My::Module::do_*$");
    map { $_->disable } @contracts;

	

Caching?

    use Sub::Contract;
    	
    contract('foo')
      ->in(\&is_foo_object, \&is_integer)
      ->out(\&is_string);
      ->memoize(size => 1000);
    
    sub foo {
        my ($self, $int) = @_;
        return "value is $int";
    }
	

Sub::Contract

Contract programming...

Questions?

Thank you!