Telephone +44(0)1524 64544
Email: info@shadowcat.co.uk

Show Us The Whole Code

A plea to those I'm helping debug

Fri Feb 5 20:15:00 2010

Digg! submit to reddit Delicious RSS Feed Readers

When I'm being asked for help troubleshooting perl code - both out in the community and for Shadowcat's professional services clients, one of the things I'm always doing is asking for more information. In fact, the most often heard cry on freenode's #perl channel is "show us the whole code".

Yet people always resist. "I already showed you the relevant parts", they say. Unfortunately, they're ignoring something fairly essential - they're showing us the parts they think are relevant. Which is fine, except that knowing which parts are relevant is a key skill in debugging, and the fact we've had much more practice at it is why we're being asked.

The thing is, the people concerned are usually trying to be helpful by not burdening us with code that doesn't matter to the problem. Unfortunately, that's just not how it works. So I say unto you:

If you're asking for help from me, please just show me all the code involved in the first place

Seriously. I can skim through half a dozen files to find the bits that matter way, way faster than I can go back and forth with you asking for those bits one at a time. I've spent much of the past decade reading perl code to work out what's going on, because I'm one of these strange people who likes to read the source before committing to using a piece of software.

But, ok, you're not convinced, so let me show you an example of something that's quite close to a problem I had to solve for a client a couple of years ago. Their Catalyst web application was refusing to start with compilation errors and they were starting to get frantic.

Here's the code they showed me:

12 sub foo1 {
13   my $bar = shift;
14   warn "In foo1\n";
15   warn $bar;
16   warn "Leaving foo1\n";
17 }

And here's the error message it produced:

Global symbol "$bar" requires explicit package name at f-ed.up.pl line 15.

Now, I think the first response all of us would have there is erm, that can't be right. Well, I can assure you that the client had misrepresented neither the code nor the error message.

I looked at it, and, eliminating that which was impossible, came to the only remaining conclusion, improbable though it was: The error was not in that piece of code.

Unfortunately, our client didn't find this as satisfactory a conclusion as I did, and we proceeded to have a debate about whether or not the error was somewhere else and whether it was worthwhile them showing me some more code (all this on an hours-based support contract) which I ended by giving up and asking for a shell onto the dev box.

Once I got on there, I cracked open the relevant file and after staring at it for a few minutes, spotted this:

12 sub foo1 {
13   my $bar = shift;
14   warn "In foo1\n";
15   warn $bar;
16   warn "Leaving foo1\n";
17 }
18 
19 sub foo2 {
20   my $fbar = shift;
21   warn "In foo2\n";
22   warn $bar;
23   warn "Leaving foo2\n";
24 }

Now, do we see the problem here?

Look again. It took me a while.

It's line 20 you need to be looking at.

And now you can explain why line 22 produces a strict error.

Wait? line 22?!

...

Precisely.

Now at this point, I made a lucky guess, went up to the top of the file, added a single '#' character, and the error did indeed come from line 22 with that change.

The reason is: At some distant point in the past of this module, somebody had decided they wanted a switch statement. So they'd loaded the horrific, dangerous source filter known as Switch.pm. Then, after that, they'd not needed the code that used it, so they'd =head1'ed it out as is often done in perl to temporarily get rid of a block of code.

And then, over time, that commented code was committed, still commented, and forgotten. The reuslting file looked roughly like this:

01 use strict;
02 use warnings;
03 
04 use Switch;
05 
06 =head1
07 switch ($foo) {
08   case 1 { print "yay\n" }
09 }
10 =cut
11 
12 sub foo1 {
13   my $bar = shift;
14   warn "In foo1\n";
15   warn $bar;
16   warn "Leaving foo1\n";
17 }
18 
19 sub foo2 {
20   my $fbar = shift;
21   warn "In foo2\n";
22   warn $bar;
23   warn "Leaving foo2\n";
24 }

The problem being that the #line directives Switch inserts are also within the POD and therefore ignored. So line number reporting from then on goes very, very wrong - see the original script and the same script with line numbers if you want to play for yourself.

And, of course, since I'd already heard that albeit not seen it in practice, if I'd seen the first half dozen lines of the file I'd've been able to solve the problem and get our client back on track immediately, instead of three quarters of an hour later.

So please, guys - for your own sanity as well as ours - when somebody who's trying to help you asks for more information, provided you can give them that information, please accept there's probably a reason for it. And please, please.

Show Us The Whole Code.

Thank you.

-- mst, out