The Perl Conference in Riga

Short version: I'll be there.

Long version: people have been asking me why I've not been as visible in the Perl community as I used to be (including at least one person asking if I was still involved in Perl). Well, that's a long story.

Renaming modules from the command line

As we continue to build Tau Station, the free-to-play narrative sci-fi MMORPG (what a mouthful!), we find our code base is getting larger and larger. As with any large codebase, we've found ourselves sometimes mired in technical debt and need a way out.

One simple hack I wrote has saved so much grief with this process. I can run this from the command line:

bin/dev/rename-module.pl Veure::Old::Module::Name Veure::New::Module::Name

And it automatically renames the module for me, updates all references to it, creating directories as needed, renaming test classes built for it, and uses git.

Atomic Updates with DBIx::Class

As we're building Tau Station, a narrative sci-fi MMORPG written in Perl, we've encountered any of a number of challenges, not the least of which is that this is a very "write-heavy" application. Further, because it's a universe where people interact, there's often no clear isolation between what you can change and what I can change. Thus, there's a lot of writing to the database and often to the same data!

By now you've probably heard of the Object-Relational Impedance Mismatch, which is just a fancy way of saying "collections of objects and databases aren't the same thing."

One problem which is particularly difficult is handling "syndicate credits". Syndicates ("guilds" in other MMORPGs) can tax their members and every time a member gets credits deposited in their bank account, a certain percentage goes to the syndicate. So let's say two syndicate members each earn 100 credits at the same time, paying 10% tax to their syndicates. It can look like this:

  • Process #1: Read how many credits a given syndicate has.
  • Process #2: Read how many credits a syndicate has.
  • Process #1: Set syndicate credits = credits + 10
  • Process #2: Set syndicate credits = credits + 10

Logically, the syndicate should end up with an extra 20 credits. But if you do a naïve:

$syndicate->update({ credits => $credits + $tax });

... you can easily wind up with 10 credits because the "Process #2" read the total credits before "Process #1" wrote them out. Fortunately, there's an easy fix to this.

Enforcing Simple Standards with One Module

It's fair to say that at our consulting company, we work with many clients who use Perl heavily. The "preamble" of their Perl code is either an ad-hoc mixture of features, or stock boilerplate like this which gets cut-n-pasted all over the place:

use strict;
use warnings;
use v5.24;
use feature "signatures";
no warnings 'experimental::signatures';
use utf8::all;
use Carp;

Both of those approaches are dead wrong. The "ad hoc" pragma list means it's hard to be sure what features are or are not available. The "standard boilerplate" approach means cutting-n-pasting and then hating yourself when you have to change that standard boilerplate.

Modern::Perl is a nice middle ground for avoiding this, but it may not be the features you want. For example, our free-to-play narrative browser game, Tau Station, doesn't use the C3 MRO because we don't use multiple inheritance (note: we enforce C3 on our DBIx::Class classes, of course).

Instead, we have our custom boilerplate, wrapped up in Veure::Module.

Improving Perl debugger variable output

TL;DR: Drop my .perldb file in your home directory for a much nicer debugger experience.

The kindest thing I can say about the built-in Perl debugger is that it doesn't drink even though it's old enough to. Using it is painful but there are many things you can do to make it nicer. Heck, I even had syntax highlighting working once.

One of my major pet peeves with the debugger has been how it dumps variable data. Have you ever used it and typed "x $dbic_object" or "r" to return from a method and gotten hundreds of lines of near useless output spewing across the screen? To make matters worse, it takes a long time to dump all of that, making the slow debugger even slower than normal. It's very frustrating. Here's how to fix it.

When running the debugger, Perl loads a script named perl5db.pl and internally, when it needs to dump some variables to the terminal, it runs some code which looks like this (edited for clarity):

# If main::dumpValue isn't here, get it.
do 'dumpvar.pl' || die $@
    unless defined &main::dumpValue;

# must detect sigpipe failures  - not catching
# then will cause the debugger to die.
eval { main::dumpValue(@vars); };

# The die doesn't need to include the $@, because
# it will automatically get propagated for us.
if ($@) {
    die unless $@ =~ /dumpvar print failed/;
}

If you read that carefully, you'll realize that if there's a dumpValue() function in main::, that's what the debugger will use to dump out your variables. The old dumpvar.pl code was written back when 5.001 was still around and fortunately shoves things in the dumpvar package, but we still have dumpValue() littering main::.

However, we can make life much easier with this. By creating your own .perldb file in your home directory (I have a fully documented example here), you can add this to it:

# use a different package in case you need to
# define other helper functions here
package My::Debugger;

use Data::Printer sort_keys => 1, colored => 1;

# this is usually set by dumpvars.pl (called from the debugger). But if it's
# already defined, the debugger uses our version
sub ::dumpValue {
    my ( $value, $maxdepth ) = @_;
    p $value;
}

With that, you'll get nice, clean Data::Printer output (or whatever you want to put in there).

About Ovid

user-pic Freelance Perl/Testing/Agile consultant and trainer. See http://www.allaroundtheworld.fr/ for our services. If you have a problem with Perl, we will solve it for you. And don't forget to buy my book! http://www.amazon.com/Beginning-Perl-Curtis-Poe/dp/1118013840/