From Novice to Adept: Cleaning Up Bad Code

| 4 Comments

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.

4 Comments

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. :-)

Modern Perl: The Book

cover image for Modern Perl: the book

The best Perl Programmers read Modern Perl: The Book.

sponsored by the How to Make a Smoothie guide

Categories

Pages

About this Entry

This page contains a single entry by chromatic published on October 16, 2009 3:21 PM.

From Novice to Adept: Declarations and Scope was the previous entry in this blog.

From Novice to Adept: Embracing Idioms is the next entry in this blog.

Find recent content on the main index or look in the archives to find all content.


Powered by the Perl programming language

what is programming?