We’ve all been there: Deep in the bow­els of a pro­gram, try­ing to fig­ure out why some­thing’s not work­ing right. 

Maybe a vari­able isn’t get­ting the right val­ue. Maybe a func­tion or method isn’t get­ting called or has the wrong argu­ments. Maybe we don’t even know if a line of code is being reached.

So what do we do? We lit­ter our code with print state­ments or log­ging. Got val­ue.” Calling foo with x.” Reached line 42.”

And then we have to make sure to clean it all out, lest these infor­mal clues make their way to pro­duc­tion and the eyes of users.

There’s a better way

What if I told you that you could freeze time in the mid­dle of your pro­gram and exam­ine all these details while they hap­pen, or even before they hap­pen? That you could be alert­ed when vari­ables or expres­sions changed and imme­di­ate­ly dive in to see the cause? That you could even run explorato­ry test code and play what if” sce­nar­ios?

All of this is pos­si­ble with a debug­ger, and Perl has one built-​in. Run your pro­gram with perl -d, and after a slight delay you’re pre­sent­ed with a new com­mand line prompt:

% perl -d hello.pl

Loading DB routines from perl5db.pl version 1.57
Editor support available.

Enter h or 'h h' for help, or 'man perldebug' for more help.

main::(hello.pl:7):	say 'Hello world!';

Before you go any fur­ther, you might want to know how to exit the debug­ger. Just type q and then press Enter and you’ll be back at your nor­mal com­mand line.

Perl also comes with a good (if incom­plete) tuto­r­i­al on using the debug­ger, and I sug­gest you work through that to famil­iar­ize your­self. It will tell you how to get help, list and view vari­ables and lines of code, set break­points, and step through line by line.

And then there’s the full man­u­al, where you can learn how to do things like get­ting a stack back­trace of all calls lead­ing up to the cur­rent line.

My favorite debugging trick

By far my favorite thing to do with the debug­ger is to run it against test scripts using the prove com­mand. This takes advan­tage of proves abil­i­ty to run an arbi­trary inter­preter through its test har­ness. Run it like this:

% prove --verbose --lib --exec 'perl -Ilib -d' t/foo.t

…and you’ll be able to step through the test script at t/foo.t, load­ing any nec­es­sary mod­ules from the lib direc­to­ry, get­ting ver­bose test out­put along the way.

This is extreme­ly help­ful when paired with mod­ules like Test::Mojo, which can load Mojolicious web appli­ca­tion class­es and then exer­cise them using its own user agent. (You can do sim­i­lar things with oth­er PSGI appli­ca­tions using Plack::Test.)

A caveat

If you’re debug­ging and test­ing your appli­ca­tions strict­ly through net­work requests to anoth­er process, such as through Test::WWW::Mechanize, run­ning the debug­ger will only show you the client-​side of things and not allow you to step through exe­cu­tion of the serv­er side. This is espe­cial­ly preva­lent among lega­cy apps not using the PSGI pro­to­col. If you’re using Apache mod_​perl have a look at Apache::DB, which enables you to run the Apache httpd web serv­er with the inter­ac­tive debugger.

So what’s your superpower?

A debug­ger is a com­mon fea­ture in many lan­guages and devel­op­ment envi­ron­ments, and Perl has had one for decades. Yet I’m con­stant­ly sur­prised that more devel­op­ers don’t know about or don’t use this pow­er­ful tool that can cut through the add prints/​run/​stop/​add more prints/​run” cycle.

How can you inte­grate the Perl debug­ger into your pro­gram­ming work­flow? Leave me a mes­sage in the com­ments and let me know.

One thought on “The Perl debugger can be your superpower

Comments are closed.