I clean my office every couple of months. Despite a decent filing system for paperwork, a day-of-the-month accordion folder for bills and appointments, and every good intent to organize papers and books out of piles, stuff piles up on my desk until I start to lose things. Right now, if I want to take notes on a manuscript (or outline a book in pen), I have to clear off a section my desk.
Tidiness is important to working effectively. It's easier to do good things if you're not working around random debris.
As this is with my desk, so it is with code.
I can't give you a magic incantation to turning thousands of lines of spaghetti code into a well-formatted program that's easy to read, easy to understand, easy to maintain, and easy to extend, but I can explain a couple of Perl 5 tools which will help.
Perl::Tidy
The Perl::Tidy module improves the formatting of messy Perl code. There are myriad options available, but by default it's pretty good -- so good, in fact, that my ~/.perltidyrc file contains only two lines:
-ci=4
-bl
You can run the included perltidy
program from the command-line:
$ perltidy my_messy_code.pl
... or you can add a macro or plugin to your editor to tidy code for you. Padre has a plugin called Padre::Plugin::PerlTidy. I have two Vim macros:
map ,pt <ESC>:%! perltidy<CR>
map ,ptv <ESC>:'<,'>! perltidy<CR>
If I type ,pt
, Vim will run perltidy
on the entire
file. If I select a region and type ,ptv
, Vim will run
perltidy
on the selection.
This is my first line of defense against poorly-formatted code. Better formatting often helps clarify logic and logic errors.
B::Deparse
Sometimes it's more important to see how Perl interprets code than to suss it out for yourself, especially given complex expressions. The core module B::Deparse takes a program that Perl 5 has already parsed and turns it back into source code.
You can run it from the command line:
$ perl -MO=Deparse some_bad_program.pl
... or on a specific subroutine within a file:
$ perl -MO=Deparse,a_real_mess some_bad_program.pl
... or within a Perl 5 program itself:
use B::Deparse;
my $bdp = B::Deparse->new();
my $code = $bdp->coderef2text( \&some_awful_function );
Email::Send->new({
mailer => 'SMTP',
mailer_args => [ Host => 'my.example.com' ]
})->send(<<'END_MESSAGE');
From: a_kind_person@my.example.com
To: mortified_perl_programmer@your.example.com
Subject: Here's What Your Code Really Does
$code
END_MESSAGE
Of course, you might not want to mail deparsed code to people instead of talking to them first -- but you can if you must.
Perl::Critic
After you can read the code in a proper format and understand complex expressions well enough to consider rewriting them, the Perl::Critic toolset can help you identify and avoid well-understood problems in code -- both stylistic and substantial.
The perlcritic
utility runs from the command line and can
identify the most egregious potential errors in a program or module:
$ perlcritic MyAwfulModule.pm my_nifty_program.pl
There are many command-line options. I like --top
which finds
the 20 worst violations. Severity levels range from 5
(the
default) to 1
(the pickiest); select your preferred range with
-n
. You can customize P::C policies for your project or
organization and you can add other policies as you wish.
P::C policies tend to explain themselves. That is, Perl::Critic::Policy::BuiltinFunctions::ProhibitUniversalCan has a brief discussion of why the policy exists and what to do instead. If you take the time to explore various policy violations for a codebase and consider the arguments, you'll learn a lot about writing effective Perl 5 code.
If you want to enforce site policies, the Test::Perl::Critic module is useful. The criticism pragma is another approach worth considering. Gabor Szabo also pointed out the Padre Perl::Critic plugin.
All three of these utilities have options and suggestions and nuances ripe for discovery, but all three of them can provide you an immediate benefit without requiring arduous or tedious customization.
If you want to write better Perl 5 code, start here.
I've always been a big fan of perltidy. However, I haven't been using perlcritic as of late and so ran it on a program of mine. Turns out I had a few "Two-argument "open"" warnings, never fixed because I didn't know how to do a three-argument open when using pipes. Finally figured it out, fixed it, and perlcritic is happy again. :) Thanks for the article.
Great comparison with cleaning up your desk!
Thanks for mentioning the Padre plugin. The working link on search.cpan.org would look like this: Padre::Plugin::PerlTidy and there is also Padre::Plugin::PerlCritic though both need a lot more work.
I have the following for my Perl Tidy:
nnoremap ,pt :%!perltidy -q<cr> " only works in 'normal' mode
vnoremap ,pt :!perltidy -q<cr> " only works in 'visual' mode
With that, I can use the same key binding for both normal and visual mode.
I'm using for set equalprg=perltidy\ -st as a autocmd for Perl files. So I can use = to format my code, like always. :-)