Writing Maintainable Perl
David M. Bradford
Who am I?
David Bradford
@tinypig
tinypig.com
Who am I?
● Web Engineer at OmniTI
– Full stack tech consulting
– Remote database management and consulting
– Large Scale / Mission Critical
– We're Hiring!
– omniti.com
Why This Talk?
● Is Perl a "write-only" language?
Why This Talk?
● Is Perl a "write-only" language? No!
Why This Talk?
● Is Perl a "write-only" language? No!
● ...but it can be.
Why This Talk?
● Is Perl a "write-only" language? No!
● ...but it can be.
● It's our responsibility to keep code:
Why This Talk?
● Is Perl a "write-only" language? No!
● ...but it can be.
● It's our responsibility to keep code:
– Easy to read
Why This Talk?
● Is Perl a "write-only" language? No!
● ...but it can be.
● It's our responsibility to keep code:
– Easy to read, so it will be:
Why This Talk?
● Is Perl a "write-only" language? No!
● ...but it can be.
● It's our responsibility to keep code:
– Easy to read, so it will be:
– Easy to maintain
My Function, “listify”
sub listify {
my ($aref,$cc) = @_;
if( ref $aref eq 'ARRAY' && $cc > 0 ) {
my $j;
for(my $i=0; $i<=$#$aref; $i+=$cc) {
push @$j, [@$aref[$i..$i+$cc-1]];
}
$#{$j->[$#{$j}]}=$#$aref%$cc;
@$aref = @$j;
return 1;
}
return;
}
Purpose of listify
Take a list, for example:
List # 1, with 10 items
one two three four five six seven eight nine ten
Give me several lists back, each containing no more than N items,
for example, 4:
List #1 with 4 items: one two three four
List #2 with 4 items: five six seven eight
List #3 with 2 items: nine ten
Prepare to call listify
listify( @list, 4 );
Result:
@array = (
[ 'one', 'two', 'three', 'four' ],
[ 'five', 'six', 'seven', 'eight' ],
[ 'nine', 'ten' ],
);
my @list = qw( one two three four five six seven eight nine ten );
Call to listify
my @list = qw( one two three four five six seven eight nine ten );
Result:
@array = (
[ 'one', 'two', 'three', 'four' ],
[ 'five', 'six', 'seven', 'eight' ],
[ 'nine', 'ten' ],
);
listify( @list, 4 );
Result of listify
my @list = qw( one two three four five six seven eight nine ten );
listify( @list, 4 );
Result:
@array = (
[ 'one', 'two', 'three', 'four' ],
[ 'five', 'six', 'seven', 'eight' ],
[ 'nine', 'ten' ],
);
Declare function listify
sub listify {
my ($aref,$cc) = @_;
if( ref $aref eq 'ARRAY' && $cc > 0 ) {
my $j;
for(my $i=0; $i<=$#$aref; $i+=$cc) {
push @$j, [@$aref[$i..$i+$cc-1]];
}
$#{$j->[$#{$j}]}=$#$aref%$cc;
@$aref = @$j;
return 1;
}
return;
}
sub listify {
}
Get Parameters
sub listify {
my ($aref,$cc) = @_;
if( ref $aref eq 'ARRAY' && $cc > 0 ) {
my $j;
for(my $i=0; $i<=$#$aref; $i+=$cc) {
push @$j, [@$aref[$i..$i+$cc-1]];
}
$#{$j->[$#{$j}]}=$#$aref%$cc;
@$aref = @$j;
return 1;
}
return;
}
my ($aref,$cc) = @_;
Validate Parameters
sub listify {
my ($aref,$cc) = @_;
if( ref $aref eq 'ARRAY' && $cc > 0 ) {
my $j;
for(my $i=0; $i<=$#$aref; $i+=$cc) {
push @$j, [@$aref[$i..$i+$cc-1]];
}
$#{$j->[$#{$j}]}=$#$aref%$cc;
@$aref = @$j;
return 1;
}
return;
}
if( ref $aref eq 'ARRAY' && $cc > 0 ) {
}
return;
Declare Return Variable
sub listify {
my ($aref,$cc) = @_;
if( ref $aref eq 'ARRAY' && $cc > 0 ) {
my $j;
for(my $i=0; $i<=$#$aref; $i+=$cc) {
push @$j, [@$aref[$i..$i+$cc-1]];
}
$#{$j->[$#{$j}]}=$#$aref%$cc;
@$aref = @$j;
return 1;
}
return;
}
my $j;
Loop Through Input Array
sub listify {
my ($aref,$cc) = @_;
if( ref $aref eq 'ARRAY' && $cc > 0 ) {
my $j;
for(my $i=0; $i<=$#$aref; $i+=$cc) {
push @$j, [@$aref[$i..$i+$cc-1]];
}
$#{$j->[$#{$j}]}=$#$aref%$cc;
@$aref = @$j;
return 1;
}
return;
}
for(my $i=0; $i<=$#$aref; $i+=$cc) {
}
Add List to Output Variable
sub listify {
my ($aref,$cc) = @_;
if( ref $aref eq 'ARRAY' && $cc > 0 ) {
my $j;
for(my $i=0; $i<=$#$aref; $i+=$cc) {
push @$j, [@$aref[$i..$i+$cc-1]];
}
$#{$j->[$#{$j}]}=$#$aref%$cc;
@$aref = @$j;
return 1;
}
return;
}
push @$j, [@$aref[$i..$i+$cc-1]];
???
sub listify {
my ($aref,$cc) = @_;
if( ref $aref eq 'ARRAY' && $cc > 0 ) {
my $j;
for(my $i=0; $i<=$#$aref; $i+=$cc) {
push @$j, [@$aref[$i..$i+$cc-1]];
}
$#{$j->[$#{$j}]}=$#$aref%$cc;
@$aref = @$j;
return 1;
}
return;
}
$#{$j->[$#{$j}]}=$#$aref%$cc;
Update Input Array In Place
sub listify {
my ($aref,$cc) = @_;
if( ref $aref eq 'ARRAY' && $cc > 0 ) {
my $j;
for(my $i=0; $i<=$#$aref; $i+=$cc) {
push @$j, [@$aref[$i..$i+$cc-1]];
}
$#{$j->[$#{$j}]}=$#$aref%$cc;
@$aref = @$j;
return 1;
}
return;
}
@$aref = @$j;
Return 1 to Indicate Success
sub listify {
my ($aref,$cc) = @_;
if( ref $aref eq 'ARRAY' && $cc > 0 ) {
my $j;
for(my $i=0; $i<=$#$aref; $i+=$cc) {
push @$j, [@$aref[$i..$i+$cc-1]];
}
$#{$j->[$#{$j}]}=$#$aref%$cc;
@$aref = @$j;
return 1;
}
return;
}
return 1;
Clever (but not easy to read) Line
$#{$j->[$#{$j}]}=$#$aref%$cc;
Purpose of Clever Line
The purpose of the line is to truncate the final array to the number of remaining
elements so we don't end up with this:
@array = (
[ 'one', 'two', 'three', 'four' ],
[ 'five', 'six', 'seven', 'eight' ],
[ 'nine', 'ten', undef, undef ],
);
Improvement #1: Whitespace
Improvement #2: Refactor
$#{ $j->[ -1 ] } = $#$aref % $cc;
$#{ $j->[ $#{$j} ] } = $#$aref % $cc;
Improvement #3: Naming
$#{ $result_array[ -1 ] } = $#$in_aref % $elements_per_array;
Improvement #4: Multiple Lines
$final_aref = $result_array[ -1 ];
$#$final_aref = $#$in_aref % $elements_per_array;
Improvement #5: Split Another Line
my $final_aref = $result_array[ -1 ];
my $elements_in_final = $#$in_aref % $elements_per_array;
$#$final_aref = $elements_in_final;
Improvement #6: More Whitespace
my $final_aref = $result_array[ -1 ];
my $elements_in_final = $#$in_aref % $elements_per_array;
$#$final_aref = $elements_in_final;
Improvement #7: A comment!
my $final_aref = $result_array[ -1 ];
my $elements_in_final = $#$in_aref % $elements_per_array;
# Truncate final array
$#$final_aref = $elements_in_final;
Easier to Read Now?
Original:
$#{$j->[$#{$j}]}=$#$aref%$cc;
Revised:
my $final_aref = $result_array[ -1 ];
my $elements_in_final = $#$in_aref % $elements_per_array;
# Truncate final array
$#$final_aref = $elements_in_final;
Apply Principles to Entire Function
sub listify {
my ( $in_aref, $elements_per_array ) = @_;
return if (
ref $in_aref ne 'ARRAY' or
$elements_per_array <= 0
);
my @result_array;
for( my $i = 0; $i <= $#$in_aref; $i += $elements_per_array ) {
push @result_array, [
@$in_aref[ $i..$i + $elements_per_array - 1 ]
];
}
# Continued on next slide
Apply Principles to Entire Function
# Continued from previous slide
my $final_aref = $result_array[ -1 ];
my $elements_in_final = $#$in_aref % $elements_per_array;
# Truncate final array
$#$final_aref = $elements_in_final;
@$in_aref = @result_array;
}
Helpful Modules
Perl::Critic
based on the book “Perl Best Practices” by Damian
Conway
Perl::Tidy
increase readability of code
perlcritic Result
$ perlcritic -1 listify.pl
Code not contained in explicit package at line 1, column 1. Violates
encapsulation. (Severity: 4)
Code before strictures are enabled at line 1, column 1. See page
429 of PBP. (Severity: 5)
Subroutine "listify" does not end with "return" at line 1, column 1.
See page 197 of PBP. (Severity: 4)
Code before warnings are enabled at line 1, column 1. See page 431 of
PBP. (Severity: 4)
No package-scoped "$VERSION" variable found at line 1, column 1. See
page 404 of PBP. (Severity: 2)
C-style "for" loop used at line 10, column 7. See page 100 of PBP.
(Severity: 2)
Double-sigil dereference at line 10, column 26. See page 228 of PBP.
(Severity: 2)
(more double-sigil warnings follow)
Critical Fixes
Code not contained in explicit package at line 1, column 1. Violates
encapsulation. (Severity: 4)
Code before strictures are enabled at line 1, column 1. See page 429
of PBP. (Severity: 5)
Code before warnings are enabled at line 1, column 1. See page 431
of PBP. (Severity: 4)
sub listify {
my ( $in_aref, $elements_per_array ) = @_;
# --- cut ---
#!/usr/bin/perl
use strict;
use warnings;
Explicit Return
Subroutine "listify" does not end with "return" at line 2,
column 1. See page 197 of PBP. (Severity: 4)
# Truncate final array
$#$final_aref = $elements_in_final;
@$in_aref = @result_array;
}
return;
$VERSION
No package-scoped "$VERSION" variable found at line 1,
column 1. See page 404 of PBP. (Severity: 2)
#!/usr/bin/perl
use strict;
use warnings;
sub listify {
my ( $in_aref, $elements_per_array ) = @_;
# --- cut ---
our $VERSION = '1.19';
C-style "for" Loop
C-style "for" loop used at line 11, column 7. See page 100
of PBP. (Severity: 2)
C-style "for" Loop
C-style "for" loop used at line 11, column 7. See page 100
of PBP. (Severity: 2)
● “What?” No C-style “for” loops
C-style "for" Loop
C-style "for" loop used at line 11, column 7. See page 100
of PBP. (Severity: 2)
● “What?” No C-style “for” loops
● “Why?” More difficult to read and maintain
C-style "for" Loop
C-style "for" loop used at line 11, column 7. See page 100
of PBP. (Severity: 2)
● “What?” No C-style “for” loops
● “Why?” More difficult to read and maintain
● “I disagree.” That's OK. Modify Perl::Critic settings!
C-style "for" Loop
C-style "for" loop used at line 11, column 7. See page 100
of PBP. (Severity: 2)
● “What?” No C-style “for” loops
● “Why?” More difficult to read and maintain
● “I disagree.” That's OK. Modify Perl::Critic settings!
But today, I'm going to fix all the defaults
Change to “while” loop
C-style "for" loop used at line 11, column 7. See page 100 of
PBP. (Severity: 2)
Old:
for( my $i = 0; $i <= $#$in_aref; $i += $elements_per_array ) {
# (loop contents)
}
New:
my $i = 0;
while($i <= $#$in_aref) {
# (loop contents)
$i += $elements_per_array;
}
Double-sigil dereference
● Caused by
– @$my_array_reference
● Fixed with
– @{ $my_array_reference }
JAPH: The Do-Not Example
sub q{ord($_[0])}sub qq{chr($_[0])}(@q=(j,q,q,,q,s,,u,o,[$;=@q,$"=sub{for(@q){
s/(.)/&qq(&q($1)-1)/e}},$_=q,*534`!./4(%2`0%2{`(!#+%2,,tr;{;,;,s/(.)/&q($1)>95?
&qq(&q($1)-64):&qq(&q($ 1)+64)/eg,% q=(q,qq,,sub{eval$ _[0]},q,q,,1)])),&{$ "},
$q{qq}->(qq.$;->[$q=$q{q}]${$;}[++$q]$;->[$[]${$;}[-1+$)-$ )+$#q]$;->[$#q-$q].)
JAPH: The Do-Not Example
sub q{ord($_[0])}sub qq{chr($_[0])}(@q=(j,q,q,,q,s,,u,o,[$;=@q,$"=sub{for(@q){
s/(.)/&qq(&q($1)-1)/e}},$_=q,*534`!./4(%2`0%2{`(!#+%2,,tr;{;,;,s/(.)/&q($1)>95?
&qq(&q($1)-64):&qq(&q($ 1)+64)/eg,% q=(q,qq,,sub{eval$ _[0]},q,q,,1)])),&{$ "},
$q{qq}->(qq.$;->[$q=$q{q}]${$;}[++$q]$;->[$[]${$;}[-1+$)-$ )+$#q]$;->[$#q-$q].)
● Ugly variables $" $; $ " and even $_, @_
JAPH: The Do-Not Example
sub q{ord($_[0])}sub qq{chr($_[0])}(@q=(j,q,q,,q,s,,u,o,[$;=@q,$"=sub{for(@q){
s/(.)/&qq(&q($1)-1)/e}},$_=q,*534`!./4(%2`0%2{`(!#+%2,,tr;{;,;,s/(.)/&q($1)>95?
&qq(&q($1)-64):&qq(&q($ 1)+64)/eg,% q=(q,qq,,sub{eval$ _[0]},q,q,,1)])),&{$ "},
$q{qq}->(qq.$;->[$q=$q{q}]${$;}[++$q]$;->[$[]${$;}[-1+$)-$ )+$#q]$;->[$#q-$q].)
● Ugly variables $" $; $ " and even $_, @_
– use English;
JAPH: The Do-Not Example
sub q{ord($_[0])}sub qq{chr($_[0])}(@q=(j,q,q,,q,s,,u,o,[$;=@q,$"=sub{for(@q){
s/(.)/&qq(&q($1)-1)/e}},$_=q,*534`!./4(%2`0%2{`(!#+%2,,tr;{;,;,s/(.)/&q($1)>95?
&qq(&q($1)-64):&qq(&q($ 1)+64)/eg,% q=(q,qq,,sub{eval$ _[0]},q,q,,1)])),&{$ "},
$q{qq}->(qq.$;->[$q=$q{q}]${$;}[++$q]$;->[$[]${$;}[-1+$)-$ )+$#q]$;->[$#q-$q].)
● Ugly variables $" $; $ " and even $_, @_
– use English;
● 74% non-alpha/space
JAPH: The Do-Not Example
sub q{ord($_[0])}sub qq{chr($_[0])}(@q=(j,q,q,,q,s,,u,o,[$;=@q,$"=sub{for(@q){
s/(.)/&qq(&q($1)-1)/e}},$_=q,*534`!./4(%2`0%2{`(!#+%2,,tr;{;,;,s/(.)/&q($1)>95?
&qq(&q($1)-64):&qq(&q($ 1)+64)/eg,% q=(q,qq,,sub{eval$ _[0]},q,q,,1)])),&{$ "},
$q{qq}->(qq.$;->[$q=$q{q}]${$;}[++$q]$;->[$[]${$;}[-1+$)-$ )+$#q]$;->[$#q-$q].)
● Ugly variables $" $; $ " and even $_, @_
– use English;
● 74% non-alpha/space
– More non-alpha characters, more difficult to read
Other Considerations
● Conformity can be good
Other Considerations
● Conformity can be good
● How to implement good change?
Other Considerations
● Conformity can be good
● How to implement good change?
● The “next guy” might be YOU.
Other Considerations
● Conformity can be good
● How to implement good change?
● The “next guy” might be YOU.
● Comment to preempt disputes or misunderstandings
Best Book on this Topic
Perl Best Practices by Damian Conway
Questions?
Thank You!
David Bradford
@tinypig
tinypig.com
Web Engineer at OmniTI
omniti.com/presents

Writing Maintainable Perl

  • 1.
  • 2.
    Who am I? DavidBradford @tinypig tinypig.com
  • 3.
    Who am I? ●Web Engineer at OmniTI – Full stack tech consulting – Remote database management and consulting – Large Scale / Mission Critical – We're Hiring! – omniti.com
  • 4.
    Why This Talk? ●Is Perl a "write-only" language?
  • 5.
    Why This Talk? ●Is Perl a "write-only" language? No!
  • 6.
    Why This Talk? ●Is Perl a "write-only" language? No! ● ...but it can be.
  • 7.
    Why This Talk? ●Is Perl a "write-only" language? No! ● ...but it can be. ● It's our responsibility to keep code:
  • 8.
    Why This Talk? ●Is Perl a "write-only" language? No! ● ...but it can be. ● It's our responsibility to keep code: – Easy to read
  • 9.
    Why This Talk? ●Is Perl a "write-only" language? No! ● ...but it can be. ● It's our responsibility to keep code: – Easy to read, so it will be:
  • 10.
    Why This Talk? ●Is Perl a "write-only" language? No! ● ...but it can be. ● It's our responsibility to keep code: – Easy to read, so it will be: – Easy to maintain
  • 11.
    My Function, “listify” sublistify { my ($aref,$cc) = @_; if( ref $aref eq 'ARRAY' && $cc > 0 ) { my $j; for(my $i=0; $i<=$#$aref; $i+=$cc) { push @$j, [@$aref[$i..$i+$cc-1]]; } $#{$j->[$#{$j}]}=$#$aref%$cc; @$aref = @$j; return 1; } return; }
  • 12.
    Purpose of listify Takea list, for example: List # 1, with 10 items one two three four five six seven eight nine ten Give me several lists back, each containing no more than N items, for example, 4: List #1 with 4 items: one two three four List #2 with 4 items: five six seven eight List #3 with 2 items: nine ten
  • 13.
    Prepare to calllistify listify( @list, 4 ); Result: @array = ( [ 'one', 'two', 'three', 'four' ], [ 'five', 'six', 'seven', 'eight' ], [ 'nine', 'ten' ], ); my @list = qw( one two three four five six seven eight nine ten );
  • 14.
    Call to listify my@list = qw( one two three four five six seven eight nine ten ); Result: @array = ( [ 'one', 'two', 'three', 'four' ], [ 'five', 'six', 'seven', 'eight' ], [ 'nine', 'ten' ], ); listify( @list, 4 );
  • 15.
    Result of listify my@list = qw( one two three four five six seven eight nine ten ); listify( @list, 4 ); Result: @array = ( [ 'one', 'two', 'three', 'four' ], [ 'five', 'six', 'seven', 'eight' ], [ 'nine', 'ten' ], );
  • 16.
    Declare function listify sublistify { my ($aref,$cc) = @_; if( ref $aref eq 'ARRAY' && $cc > 0 ) { my $j; for(my $i=0; $i<=$#$aref; $i+=$cc) { push @$j, [@$aref[$i..$i+$cc-1]]; } $#{$j->[$#{$j}]}=$#$aref%$cc; @$aref = @$j; return 1; } return; } sub listify { }
  • 17.
    Get Parameters sub listify{ my ($aref,$cc) = @_; if( ref $aref eq 'ARRAY' && $cc > 0 ) { my $j; for(my $i=0; $i<=$#$aref; $i+=$cc) { push @$j, [@$aref[$i..$i+$cc-1]]; } $#{$j->[$#{$j}]}=$#$aref%$cc; @$aref = @$j; return 1; } return; } my ($aref,$cc) = @_;
  • 18.
    Validate Parameters sub listify{ my ($aref,$cc) = @_; if( ref $aref eq 'ARRAY' && $cc > 0 ) { my $j; for(my $i=0; $i<=$#$aref; $i+=$cc) { push @$j, [@$aref[$i..$i+$cc-1]]; } $#{$j->[$#{$j}]}=$#$aref%$cc; @$aref = @$j; return 1; } return; } if( ref $aref eq 'ARRAY' && $cc > 0 ) { } return;
  • 19.
    Declare Return Variable sublistify { my ($aref,$cc) = @_; if( ref $aref eq 'ARRAY' && $cc > 0 ) { my $j; for(my $i=0; $i<=$#$aref; $i+=$cc) { push @$j, [@$aref[$i..$i+$cc-1]]; } $#{$j->[$#{$j}]}=$#$aref%$cc; @$aref = @$j; return 1; } return; } my $j;
  • 20.
    Loop Through InputArray sub listify { my ($aref,$cc) = @_; if( ref $aref eq 'ARRAY' && $cc > 0 ) { my $j; for(my $i=0; $i<=$#$aref; $i+=$cc) { push @$j, [@$aref[$i..$i+$cc-1]]; } $#{$j->[$#{$j}]}=$#$aref%$cc; @$aref = @$j; return 1; } return; } for(my $i=0; $i<=$#$aref; $i+=$cc) { }
  • 21.
    Add List toOutput Variable sub listify { my ($aref,$cc) = @_; if( ref $aref eq 'ARRAY' && $cc > 0 ) { my $j; for(my $i=0; $i<=$#$aref; $i+=$cc) { push @$j, [@$aref[$i..$i+$cc-1]]; } $#{$j->[$#{$j}]}=$#$aref%$cc; @$aref = @$j; return 1; } return; } push @$j, [@$aref[$i..$i+$cc-1]];
  • 22.
    ??? sub listify { my($aref,$cc) = @_; if( ref $aref eq 'ARRAY' && $cc > 0 ) { my $j; for(my $i=0; $i<=$#$aref; $i+=$cc) { push @$j, [@$aref[$i..$i+$cc-1]]; } $#{$j->[$#{$j}]}=$#$aref%$cc; @$aref = @$j; return 1; } return; } $#{$j->[$#{$j}]}=$#$aref%$cc;
  • 23.
    Update Input ArrayIn Place sub listify { my ($aref,$cc) = @_; if( ref $aref eq 'ARRAY' && $cc > 0 ) { my $j; for(my $i=0; $i<=$#$aref; $i+=$cc) { push @$j, [@$aref[$i..$i+$cc-1]]; } $#{$j->[$#{$j}]}=$#$aref%$cc; @$aref = @$j; return 1; } return; } @$aref = @$j;
  • 24.
    Return 1 toIndicate Success sub listify { my ($aref,$cc) = @_; if( ref $aref eq 'ARRAY' && $cc > 0 ) { my $j; for(my $i=0; $i<=$#$aref; $i+=$cc) { push @$j, [@$aref[$i..$i+$cc-1]]; } $#{$j->[$#{$j}]}=$#$aref%$cc; @$aref = @$j; return 1; } return; } return 1;
  • 25.
    Clever (but noteasy to read) Line $#{$j->[$#{$j}]}=$#$aref%$cc;
  • 26.
    Purpose of CleverLine The purpose of the line is to truncate the final array to the number of remaining elements so we don't end up with this: @array = ( [ 'one', 'two', 'three', 'four' ], [ 'five', 'six', 'seven', 'eight' ], [ 'nine', 'ten', undef, undef ], );
  • 27.
  • 28.
    Improvement #2: Refactor $#{$j->[ -1 ] } = $#$aref % $cc; $#{ $j->[ $#{$j} ] } = $#$aref % $cc;
  • 29.
    Improvement #3: Naming $#{$result_array[ -1 ] } = $#$in_aref % $elements_per_array;
  • 30.
    Improvement #4: MultipleLines $final_aref = $result_array[ -1 ]; $#$final_aref = $#$in_aref % $elements_per_array;
  • 31.
    Improvement #5: SplitAnother Line my $final_aref = $result_array[ -1 ]; my $elements_in_final = $#$in_aref % $elements_per_array; $#$final_aref = $elements_in_final;
  • 32.
    Improvement #6: MoreWhitespace my $final_aref = $result_array[ -1 ]; my $elements_in_final = $#$in_aref % $elements_per_array; $#$final_aref = $elements_in_final;
  • 33.
    Improvement #7: Acomment! my $final_aref = $result_array[ -1 ]; my $elements_in_final = $#$in_aref % $elements_per_array; # Truncate final array $#$final_aref = $elements_in_final;
  • 34.
    Easier to ReadNow? Original: $#{$j->[$#{$j}]}=$#$aref%$cc; Revised: my $final_aref = $result_array[ -1 ]; my $elements_in_final = $#$in_aref % $elements_per_array; # Truncate final array $#$final_aref = $elements_in_final;
  • 35.
    Apply Principles toEntire Function sub listify { my ( $in_aref, $elements_per_array ) = @_; return if ( ref $in_aref ne 'ARRAY' or $elements_per_array <= 0 ); my @result_array; for( my $i = 0; $i <= $#$in_aref; $i += $elements_per_array ) { push @result_array, [ @$in_aref[ $i..$i + $elements_per_array - 1 ] ]; } # Continued on next slide
  • 36.
    Apply Principles toEntire Function # Continued from previous slide my $final_aref = $result_array[ -1 ]; my $elements_in_final = $#$in_aref % $elements_per_array; # Truncate final array $#$final_aref = $elements_in_final; @$in_aref = @result_array; }
  • 37.
    Helpful Modules Perl::Critic based onthe book “Perl Best Practices” by Damian Conway Perl::Tidy increase readability of code
  • 38.
    perlcritic Result $ perlcritic-1 listify.pl Code not contained in explicit package at line 1, column 1. Violates encapsulation. (Severity: 4) Code before strictures are enabled at line 1, column 1. See page 429 of PBP. (Severity: 5) Subroutine "listify" does not end with "return" at line 1, column 1. See page 197 of PBP. (Severity: 4) Code before warnings are enabled at line 1, column 1. See page 431 of PBP. (Severity: 4) No package-scoped "$VERSION" variable found at line 1, column 1. See page 404 of PBP. (Severity: 2) C-style "for" loop used at line 10, column 7. See page 100 of PBP. (Severity: 2) Double-sigil dereference at line 10, column 26. See page 228 of PBP. (Severity: 2) (more double-sigil warnings follow)
  • 39.
    Critical Fixes Code notcontained in explicit package at line 1, column 1. Violates encapsulation. (Severity: 4) Code before strictures are enabled at line 1, column 1. See page 429 of PBP. (Severity: 5) Code before warnings are enabled at line 1, column 1. See page 431 of PBP. (Severity: 4) sub listify { my ( $in_aref, $elements_per_array ) = @_; # --- cut --- #!/usr/bin/perl use strict; use warnings;
  • 40.
    Explicit Return Subroutine "listify"does not end with "return" at line 2, column 1. See page 197 of PBP. (Severity: 4) # Truncate final array $#$final_aref = $elements_in_final; @$in_aref = @result_array; } return;
  • 41.
    $VERSION No package-scoped "$VERSION"variable found at line 1, column 1. See page 404 of PBP. (Severity: 2) #!/usr/bin/perl use strict; use warnings; sub listify { my ( $in_aref, $elements_per_array ) = @_; # --- cut --- our $VERSION = '1.19';
  • 42.
    C-style "for" Loop C-style"for" loop used at line 11, column 7. See page 100 of PBP. (Severity: 2)
  • 43.
    C-style "for" Loop C-style"for" loop used at line 11, column 7. See page 100 of PBP. (Severity: 2) ● “What?” No C-style “for” loops
  • 44.
    C-style "for" Loop C-style"for" loop used at line 11, column 7. See page 100 of PBP. (Severity: 2) ● “What?” No C-style “for” loops ● “Why?” More difficult to read and maintain
  • 45.
    C-style "for" Loop C-style"for" loop used at line 11, column 7. See page 100 of PBP. (Severity: 2) ● “What?” No C-style “for” loops ● “Why?” More difficult to read and maintain ● “I disagree.” That's OK. Modify Perl::Critic settings!
  • 46.
    C-style "for" Loop C-style"for" loop used at line 11, column 7. See page 100 of PBP. (Severity: 2) ● “What?” No C-style “for” loops ● “Why?” More difficult to read and maintain ● “I disagree.” That's OK. Modify Perl::Critic settings! But today, I'm going to fix all the defaults
  • 47.
    Change to “while”loop C-style "for" loop used at line 11, column 7. See page 100 of PBP. (Severity: 2) Old: for( my $i = 0; $i <= $#$in_aref; $i += $elements_per_array ) { # (loop contents) } New: my $i = 0; while($i <= $#$in_aref) { # (loop contents) $i += $elements_per_array; }
  • 48.
    Double-sigil dereference ● Causedby – @$my_array_reference ● Fixed with – @{ $my_array_reference }
  • 49.
    JAPH: The Do-NotExample sub q{ord($_[0])}sub qq{chr($_[0])}(@q=(j,q,q,,q,s,,u,o,[$;=@q,$"=sub{for(@q){ s/(.)/&qq(&q($1)-1)/e}},$_=q,*534`!./4(%2`0%2{`(!#+%2,,tr;{;,;,s/(.)/&q($1)>95? &qq(&q($1)-64):&qq(&q($ 1)+64)/eg,% q=(q,qq,,sub{eval$ _[0]},q,q,,1)])),&{$ "}, $q{qq}->(qq.$;->[$q=$q{q}]${$;}[++$q]$;->[$[]${$;}[-1+$)-$ )+$#q]$;->[$#q-$q].)
  • 50.
    JAPH: The Do-NotExample sub q{ord($_[0])}sub qq{chr($_[0])}(@q=(j,q,q,,q,s,,u,o,[$;=@q,$"=sub{for(@q){ s/(.)/&qq(&q($1)-1)/e}},$_=q,*534`!./4(%2`0%2{`(!#+%2,,tr;{;,;,s/(.)/&q($1)>95? &qq(&q($1)-64):&qq(&q($ 1)+64)/eg,% q=(q,qq,,sub{eval$ _[0]},q,q,,1)])),&{$ "}, $q{qq}->(qq.$;->[$q=$q{q}]${$;}[++$q]$;->[$[]${$;}[-1+$)-$ )+$#q]$;->[$#q-$q].) ● Ugly variables $" $; $ " and even $_, @_
  • 51.
    JAPH: The Do-NotExample sub q{ord($_[0])}sub qq{chr($_[0])}(@q=(j,q,q,,q,s,,u,o,[$;=@q,$"=sub{for(@q){ s/(.)/&qq(&q($1)-1)/e}},$_=q,*534`!./4(%2`0%2{`(!#+%2,,tr;{;,;,s/(.)/&q($1)>95? &qq(&q($1)-64):&qq(&q($ 1)+64)/eg,% q=(q,qq,,sub{eval$ _[0]},q,q,,1)])),&{$ "}, $q{qq}->(qq.$;->[$q=$q{q}]${$;}[++$q]$;->[$[]${$;}[-1+$)-$ )+$#q]$;->[$#q-$q].) ● Ugly variables $" $; $ " and even $_, @_ – use English;
  • 52.
    JAPH: The Do-NotExample sub q{ord($_[0])}sub qq{chr($_[0])}(@q=(j,q,q,,q,s,,u,o,[$;=@q,$"=sub{for(@q){ s/(.)/&qq(&q($1)-1)/e}},$_=q,*534`!./4(%2`0%2{`(!#+%2,,tr;{;,;,s/(.)/&q($1)>95? &qq(&q($1)-64):&qq(&q($ 1)+64)/eg,% q=(q,qq,,sub{eval$ _[0]},q,q,,1)])),&{$ "}, $q{qq}->(qq.$;->[$q=$q{q}]${$;}[++$q]$;->[$[]${$;}[-1+$)-$ )+$#q]$;->[$#q-$q].) ● Ugly variables $" $; $ " and even $_, @_ – use English; ● 74% non-alpha/space
  • 53.
    JAPH: The Do-NotExample sub q{ord($_[0])}sub qq{chr($_[0])}(@q=(j,q,q,,q,s,,u,o,[$;=@q,$"=sub{for(@q){ s/(.)/&qq(&q($1)-1)/e}},$_=q,*534`!./4(%2`0%2{`(!#+%2,,tr;{;,;,s/(.)/&q($1)>95? &qq(&q($1)-64):&qq(&q($ 1)+64)/eg,% q=(q,qq,,sub{eval$ _[0]},q,q,,1)])),&{$ "}, $q{qq}->(qq.$;->[$q=$q{q}]${$;}[++$q]$;->[$[]${$;}[-1+$)-$ )+$#q]$;->[$#q-$q].) ● Ugly variables $" $; $ " and even $_, @_ – use English; ● 74% non-alpha/space – More non-alpha characters, more difficult to read
  • 54.
  • 55.
    Other Considerations ● Conformitycan be good ● How to implement good change?
  • 56.
    Other Considerations ● Conformitycan be good ● How to implement good change? ● The “next guy” might be YOU.
  • 57.
    Other Considerations ● Conformitycan be good ● How to implement good change? ● The “next guy” might be YOU. ● Comment to preempt disputes or misunderstandings
  • 58.
    Best Book onthis Topic Perl Best Practices by Damian Conway
  • 59.
  • 60.
    Thank You! David Bradford @tinypig tinypig.com WebEngineer at OmniTI omniti.com/presents

Editor's Notes

  • #43 C-style &amp;quot;for&amp;quot; loop used at line 11, column 7. See page 100 of PBP. (Severity: 2) “What?” Damian recommends against using C-style “for” loops” “Why?” His main argument is that C-style “for” loops are more difficult to read and therefore more difficult to maintain “I disagree.” That&amp;apos;s OK and in fact Perl::Critic allows for a lot of customizations to alter or remove those policies you don&amp;apos;t agree with BUT, I&amp;apos;m going to fix all the default suggestions for the purpose of this presentation
  • #44 C-style &amp;quot;for&amp;quot; loop used at line 11, column 7. See page 100 of PBP. (Severity: 2) “What?” Damian recommends against using C-style “for” loops” “Why?” His main argument is that C-style “for” loops are more difficult to read and therefore more difficult to maintain “I disagree.” That&amp;apos;s OK and in fact Perl::Critic allows for a lot of customizations to alter or remove those policies you don&amp;apos;t agree with BUT, I&amp;apos;m going to fix all the default suggestions for the purpose of this presentation
  • #45 C-style &amp;quot;for&amp;quot; loop used at line 11, column 7. See page 100 of PBP. (Severity: 2) “What?” Damian recommends against using C-style “for” loops” “Why?” His main argument is that C-style “for” loops are more difficult to read and therefore more difficult to maintain “I disagree.” That&amp;apos;s OK and in fact Perl::Critic allows for a lot of customizations to alter or remove those policies you don&amp;apos;t agree with BUT, I&amp;apos;m going to fix all the default suggestions for the purpose of this presentation
  • #46 C-style &amp;quot;for&amp;quot; loop used at line 11, column 7. See page 100 of PBP. (Severity: 2) “What?” Damian recommends against using C-style “for” loops” “Why?” His main argument is that C-style “for” loops are more difficult to read and therefore more difficult to maintain “I disagree.” That&amp;apos;s OK and in fact Perl::Critic allows for a lot of customizations to alter or remove those policies you don&amp;apos;t agree with BUT, I&amp;apos;m going to fix all the default suggestions for the purpose of this presentation
  • #47 C-style &amp;quot;for&amp;quot; loop used at line 11, column 7. See page 100 of PBP. (Severity: 2) “What?” Damian recommends against using C-style “for” loops” “Why?” His main argument is that C-style “for” loops are more difficult to read and therefore more difficult to maintain “I disagree.” That&amp;apos;s OK and in fact Perl::Critic allows for a lot of customizations to alter or remove those policies you don&amp;apos;t agree with BUT, I&amp;apos;m going to fix all the default suggestions for the purpose of this presentation
  • #50 $&amp;quot;, $;, $ &amp;quot; (ignored space - crazy! Whitespace thus used to my advantage) even $_, @_ use English; My obfuscated code is 74% non-alpha/space, and that isn&amp;apos;t considering the abuse of alpha conventions like q qq s tr etc The higher percentage of non-alpha characters, the more difficult to read
  • #51 $&amp;quot;, $;, $ &amp;quot; (ignored space - crazy! Whitespace thus used to my advantage) even $_, @_ use English; My obfuscated code is 74% non-alpha/space, and that isn&amp;apos;t considering the abuse of alpha conventions like q qq s tr etc The higher percentage of non-alpha characters, the more difficult to read
  • #52 $&amp;quot;, $;, $ &amp;quot; (ignored space - crazy! Whitespace thus used to my advantage) even $_, @_ use English; My obfuscated code is 74% non-alpha/space, and that isn&amp;apos;t considering the abuse of alpha conventions like q qq s tr etc The higher percentage of non-alpha characters, the more difficult to read
  • #53 $&amp;quot;, $;, $ &amp;quot; (ignored space - crazy! Whitespace thus used to my advantage) even $_, @_ use English; My obfuscated code is 74% non-alpha/space, and that isn&amp;apos;t considering the abuse of alpha conventions like q qq s tr etc The higher percentage of non-alpha characters, the more difficult to read
  • #54 $&amp;quot;, $;, $ &amp;quot; (ignored space - crazy! Whitespace thus used to my advantage) even $_, @_ use English; My obfuscated code is 74% non-alpha/space, and that isn&amp;apos;t considering the abuse of alpha conventions like q qq s tr etc The higher percentage of non-alpha characters, the more difficult to read
  • #55 Conformity can be good: code like everyone else has in the apps you inherit or join. Unless it&amp;apos;s horrible, then start a consistent style. Then how to implement good change? One idea: implement across the entire code base, a little at a time. For example, get &amp;quot;use strict&amp;quot; working everywhere first. Make it easy on the &amp;quot;next guy&amp;quot;. The next guy might be YOU. Comment to pre-empt disputes or misunderstandings that will break production.
  • #56 Conformity can be good: code like everyone else has in the apps you inherit or join. Unless it&amp;apos;s horrible, then start a consistent style. Then how to implement good change? One idea: implement across the entire code base, a little at a time. For example, get &amp;quot;use strict&amp;quot; working everywhere first. Make it easy on the &amp;quot;next guy&amp;quot;. The next guy might be YOU. Comment to pre-empt disputes or misunderstandings that will break production.
  • #57 Conformity can be good: code like everyone else has in the apps you inherit or join. Unless it&amp;apos;s horrible, then start a consistent style. Then how to implement good change? One idea: implement across the entire code base, a little at a time. For example, get &amp;quot;use strict&amp;quot; working everywhere first. Make it easy on the &amp;quot;next guy&amp;quot;. The next guy might be YOU. Comment to pre-empt disputes or misunderstandings that will break production.
  • #58 Conformity can be good: code like everyone else has in the apps you inherit or join. Unless it&amp;apos;s horrible, then start a consistent style. Then how to implement good change? One idea: implement across the entire code base, a little at a time. For example, get &amp;quot;use strict&amp;quot; working everywhere first. Make it easy on the &amp;quot;next guy&amp;quot;. The next guy might be YOU. Comment to pre-empt disputes or misunderstandings that will break production.