Deprecation is citizenship

Last year I attended the Programming the web with Dancer master class at YAPC::NA, taught by the awesome folks Sawyer X and Mickey. It was then I learned that a new way to access get/post/route parameters was being baked and the potential pitfalls of what had been the current practice.

At the time, I was busy evangelizing the use of…

Dancer2 Named Route Parameters

If you're familiar with Dancer2 (my favorite Perl web framework to date), you know how amazingly easy it is to develop self-describing routes for your web application.

Let's say you have a Dancer2 app that allows your users to manage their phone numbers in a 1:X relationship. You might want to expose a route like...

post '/user/:user_id/phone_numbers/new' => sub {
    my $user_id = param 'user_id';
    # Do some stuff
};

... to add a new number to their profile. Let's also assume you have a route upstream that prohibits users from accessing routes associated with other users:

any '/user/*/**' => sub {
    my ($user_id) = splat;
    send_error(403) unless $user_id == session('user_id');
    pass;
};

Looks good, right?

If you have read all the documentation associated with Dancer2 (of course you did), you might have noticed params can take an optional argument to limit the source of the parameters. In other words, you can get parameters defined by the route, the query string (GET), or the content body (POST) in isolation.

What source does param use then? Well, it defaults to the behavior of params without arguments, which is to say that parameters from all three sources are munged together into a hash using the parameter name as a key.

What this means is that parameters from one source may be overwritten (not collected together in an array) by another source. Specifically, POST arguments overwrite all parameters of the same name, and named route parameters overwrite GET query string parameters of the same name.

So, back to our example!

any '/user/*/**' => sub {
    my ($user_id) = splat;
    send_error(403) unless $user_id == session('user_id');
    pass;
};

post '/user/:user_id/phone_numbers/new' => sub {
    my $user_id = param 'user_id';
    # Do some stuff
};

In this well-intended code, what is not accounted for is whether a POST argument might be received of the name user_id. Sure, we might not write such a conflict into our application but a less well-intentioned visitor might.

Documented behavior or not, this behavior is not how my brain works. So to accommodate my own laziness, I posted Dancer2::Plugin::ParamKeywords to facilitate more explicit parameter gathering and munging. So now the above example can be rewritten as...

any '/user/*/**' => sub {
    my ($user_id) = splat;
    send_error(403) unless $user_id == session('user_id');
    pass;
};

post '/user/:user_id/phone_numbers/new' => sub {
    # New keyword, route_param
    my $user_id = route_param 'user_id';
    # Do some stuff
};

... which will do what you would expect it to.

Stay tuned for a new parameters keyword that will eliminate the ambiguity described in this blog post in a future Dancer2 release. Also, thanks to XSAWYERX and MICKEY for an excellent YAPC::NA master class on Dancer2!

Why I donated to the Perl QA Hackathon

It's great when organizations with (marketing? public relations? good will?) budgets authorize financial backing of events like the Perl QA Hackathon. Donations to these kinds of efforts are one of the many ways to contribute to the Perl ecosystem. But did you know you can donate to the Hackathon personally?

This year, I decided that I wanted to make a donation to the Perl QA Hackathon (albeit modest). For those of you who have some spare change burning a hole in your wallet, maybe some of the reasons I decided to donate will resonate with you.

My relationship with Perl is personal. I use the Swiss Army chainsaw because I choose to. The fact that I am employed by a company that wants to leverage this choice is almost happenstance. Said another way, if my employer decided to stop developing in Perl, I would seek a new employer.

I use Perl because I enjoy it. This enjoyment is strictly due to the efforts of a lot of really bright and talented CPAN and Perl core developers who make "getting things done" progressively easier. They iterate relentlessly over the scaffolding of giants such that yesterday's mountains become molehills. And when I read through this year's proposed ambitions, I said "Yes, I want that, too!"

I won't even pretend I have the wherewithal to contribute programmatically or even strategically to the efforts described in this year's proposed projects. But I want the benefits that would come when any of those proposed efforts succeed, and those benefits will continue to fuel my enjoyment of Perl and facilitate my livelihood. So in lieu of being able to make my life easier with my own hands, investing a miniscule fraction of my lifetime Perl earnings to make earning with Perl even easier/more enjoyable/etc. seems like a great idea.

Also, Ron Savage served as a role model and made a private donation. It's always easier when someone else gets the ball rolling. :)

eMortgage Logic is Hiring!

eMortgage Logic, an Assurant Company, is looking for Senior Perl Web Application Developers. Our offices are located in North Richland Hills (Dallas-Fort Worth Metroplex) AND we are open to remote positions for the right candidate.

We want your experiences and talent to influence our architecture and our team. We’ve got a wide variety of projects to keep work interesting and fun, ranging from the epitome of legacy apps to self-contained services running on the latest and greatest of Modern Perl. Having an appreciation for the evolution of the Perl web development community will be your greatest asset in modernizing and growing our stack together with us.

If any of the below practices or technologies make you excited, apply at http://jobs.assurant.com/dallas/information-technology/jobid7063768-lead-software-engineer-jobs and come aboard – let’s have fun! :)

  • Agile / Scrum / Kanban
  • Moops / DBIC / Dancer2 / Mojolicious
  • PostgreSQL 9.4 / Sybase
  • Apache 2 + mod_perl / nginx
  • Sencha Ext JS / Node.js
  • git + Stash / JIRA / Confluence
  • Memcached / ActiveMQ
  • Jenkins / Docker
  • RHEL / VMware
  • ELK / Nagios / Cacti

P.S. Like contributing to CPAN? We support open source!

Fun with overload

Spoiler alert: If you are participating in the DFW.pm February thought exercise, this post is about my solution :)

DFW.pm challenged its members with the following exercise:

Pivot a multi-row/multi-column table, 4X4 in size for example, containing name-value pairs. Code should account for larger table sizes with any number of name-value pairs. Numbering the pairs is optional but encouraged for readability. An example would be as follows:

THE SOURCE TABLE
1. name | tommy | 5. pet   | fish    
2. lang | Perl  | 6. kids  | four   
3. eyes | blue  | 7. food  | pizza 
4. lbs  | n/a   | 8. hello | world 

PIVOTED RESULT TABLE
1. name | tommy | 2. lang  | perl   
3. eyes | blue  | 4. lbs   | n/a    
5. pet  | fish  | 6. kids  | four   
7. food | pizza | 8. hello | world

If you happened to read my previous post, you'll know that I'm not one to seek the most terse solution to a problem. In fact, for this exercise I was most interested in specifications left unspoken:

  1. What happens when the data set is larger than the dimensions of the table?
  2. What if the key value pairs were objects instead?

It turns out (as usual) there are a plethora of modules dating back to the relatively far past to handle tabular data. There are an equally impressive number of modules to handle pagination. While I could (maybe should) have used any number of these solutions in conjunction with one another to write a script to solve the challenge, I had a very specific contract in mind for the way objects would be treated when the table was rendered; And thus, I decided to add yet another data-table-paginator-whatsit to an already crowded namespace.

The result of this effort is Data::PaginatedTable, and here is the script that uses this new fangled module to solve the DFW.pm exercise.

#!/usr/bin/env perl
use 5.18.2;
use Modern::Perl;
use Data::PaginatedTable;
use Moops;

class Tabifier {
    use overload '""' => 'tabify';
    has 'key'   => ( is => 'ro', isa => Str, required => true );
    has 'value' => ( is => 'ro', isa => Str, required => true );

    method tabify {
        "\t" . $self->key . "\t" . $self->value;
    }
}

my $key_value_pairs = [
    [qw( name tommy )], [qw( lang Perl )],
    [qw( eyes blue )],  [qw( lbs  n/a )],
    [qw( pet  fish )],  [qw( kids four )],
    [qw( food pizza )], [qw( hello world )],
];

my @data =
  map { Tabifier->new( key => $_->[0], value => $_->[1] ) } @$key_value_pairs;

my $pt = Data::PaginatedTable->new(
    {
        data           => \@data,
        columns        => 2,
        rows           => 4,
        string_mode    => 'preformatted',
        fill_direction => 'vertical'
    }
);

say $pt;

#        name    tommy   pet     fish
#        lang    Perl    kids    four
#        eyes    blue    food    pizza
#        lbs     n/a     hello   world
#

$pt->fill_direction('horizontal');
say $pt;

#        name    tommy   lang    Perl
#        eyes    blue    lbs     n/a
#        pet     fish    kids    four
#        food    pizza   hello   world

I used overload to have the string context of a Data::PaginatedTable instance return the current page of the table, with each of the table's elements also stringified. As the script demonstrates above, table content objects may also employ string overload to dispatch a rendering method that is appropriate to themselves. This pattern can be applied to nested objects (turtles all the way down!), thereby making each object in the hierarchy responsible for its own display logic and creating a nice separation of concerns.

Using overload let's you extend Perl DWIMmery convenience to your own classes. If you've never seen what all it can do for you, have a look!