Jul/092
Upgrading to Catalyst 5.8
Over the last few days at $work I’ve been upgrading Catalyst from 5.7 to 5.8. This new version of catalyst, released in April, has been completely overhauled to use Moose for it’s OO system, among other enhancements and bug fixes.
I found that the Catalyst::Manual::CatalystAndMoose manual was a great starting point to using Moose with Catalyst. Also, Catalyst::Upgrading has specific points to consider when upgrading to 5.8. During the initial install of Catalyst 5.8 I was told that I had a few related modules installed, that while not Catalyst prerequisites, I should upgrade them as they were known to fail on the new Catalyst. I was lucky that I caught this message, as cpan did not pause to wait for me to read it and went on its marry way building, testing, and installing Catalyst.
Once installed I went ahead and also upgraded some related modules we use such as Catalyst::Plugin::Authentication, DBIx::Class, Catalyst::Plugin::Session, Catalyst::Authentication::Store::DBIx::Class, etc. This way I could test all these upgrades all at once instead of one at a time.
Next I modified all my custom plugins to use MRO::Compat instead of Class::C3 per the documentation in Class::C3::Adopt::NEXT. But, then I realized I might as well just rewrite all my plugins as Moose::Roles as its pretty easy to convert a plugin to a role and you end up with much cleaner code.
I started Apache up and things mostly worked. There were a few backwards incompatibilities that I wasn’t aware of, such as there were a few cases where developers had done this:
Instead of:
In our previous version of catalyst (5.7) using :Local, while not documented, worked just like :Private if the subroutine was named index. In 5.8 only :Private will cause a handler named index to be the default handler if the URL resolves to the controller only. This was an easy fix. There were a couple other small issues, but nothing major. I found and fixed a bug in Catalyst::Model::DBIC::Schema and added the support for the compute() method to Catalyst::Plugin::Cache. Both of these changes reduced the amount of changes I needed to make to my own code.
A couple hours in to it I was upgraded and everything was working. Of course I spent the next few days upgrading/enhancing/rewriting Catalyst bits that could be done much more elegantly, and with less code, using Moose.
On a side note, during the upgrade I found this great quote in Catalyst::Model::Adaptor:
Catalyst is glue, not a way of life!
Amen! Most people, myself included, start out by writing all their business logic in their Controllers because that is what MVC told them to do. Don’t do it! Catalyst is meant to be a GLUE – most of your application should be written in a way that it doesn’t give a flying crap how, or by whom, it is used. Put your business logic in modules that optionally expose themselves as Models (perhaps via Catalyst::Model::Adaptor) or just by adding a use statement in your controller that then uses that module. Your controllers should be little more than code to glue a data source with the view and provide some input validation.
I’ve been waiting a long time for this Moosification and its been a joy working with this new Catalyst. Next up to bat will be the Moosification of DBIx::Class! Think we’ll get it by Christmas? :)
Don’t forget to buy the new Catalyst Book! If purchasing from Amazon make sure you follow this link to ensure that the Enlightened Perl Organisation gets a cut of the sale.
Jul/093
XS Hits Newb; Bystanders Watch in Dismay
Last year I wrote GIS::Distance::Fast to provide some much needed speedups to the pure-perl GIS::Distance. This ::Fast version used Inline::C which isn’t all that optimal and was just a scapegoat for doing the right thing.
So, this evening I rolled up my sleeves and went to work. I first looked at a module I already knew to use XS, Cache::Memcached::Fast. That was overwelming.
Then I went on over and read through the perlxs and perlxstut docs. I was STILL floundering about not sure what to do. I then took a whack at using SWIG (Simplified Wrapper and Interface Generator). OhMyGodz I’m feeling overwhelmed now and still nothing works. I’m not going to even document my attempts up until this point.
I then found this document that goes in to more detail about using SWIG with Perl. The thing about this document that helped me so much is that in section 2, Perl Extension Building, it had the simplest example I had yet run in to, and it made sense! Its kinda funny that a SWIG document was what taught me how to write my own XS without using SWIG. :)
An XS distribution can contain as little as two files (well, beyond the usual Makefile.PL, etc). A single .pm file and a .xs file is enough. You can get more complex, if you want, of course. Once you’ve written your Module.xs file you can run it through xssubpp Module.xs > Module.c to see what the .c file looks like and to verify that your .xs file is correct.
Note that xssubpp may complain about you using types that aren’t in your typemap. This is because xssubpp doesn’t know how to find your system’s typemap file. You can specify a typemap file using the -typemap switch. The file is located somewhere in your perl lib path as ExtUtils/typemap.
So, let’s go for an example. Let’s make an XS module that convert hours to minutes. I structure all my code and files as if they would be distributed as a CPAN module. This has added benefits as you’ll see in a moment.
convert-hoursminutes/lib/Convert/HoursMins.pm:
use strict;
use warnings;
our $VERSION = 0.01;
use XSLoader;
XSLoader::load('Convert::HoursMins', $VERSION);
1;
convert-hoursminutes/HoursMins.xs:
#include "perl.h"
#include "XSUB.h"
double convert_hours_mins( double hours ) {
return hours * 60;
}
MODULE = Convert::HoursMins PACKAGE = Convert::HoursMins
PROTOTYPES: DISABLE
double
convert_hours_mins (hours)
double hours
convert-hoursmins/Makefile.PL
name 'Convert-HoursMins';
all_from 'lib/Convert/HoursMins.pm';
requires 'XSLoader';
WriteAll;
convert-hoursmins/t/00_basic.t
use warnings;
use Test::More tests => 2;
BEGIN{ use_ok('Convert::HoursMins'); }
is(
Convert::HoursMins::convert_hours_minutes(1.5),
90,
'1.5 hours is 90 minutes',
);
Now lets see if it worked:
make
make test
Bottom line for me is XS isn’t all that hard when your C code isn’t all that complex. SWIG is overkill for small stuff. But for large swaths of C code I bet SWIG saves lives. Also, XS is a little arcane, but its not too bad.
Jul/090
$(document).ready() Shortcut
When writing jquery you almost always put your code within a ready block:
// Code...
});
And I always forget the exact syntax. I just found that jQuery has a shortcut:
// Code...
});
Much better!
Jul/095
Authoring a CPAN Module
I’ve been authoring CPAN distribution since early 2003 with my first module being Geo::Distance. Since then I’ve authored several other distributions and do my best to keep my RT bug list small and fix FAILs. This process of authoring and maintaining modules on CPAN is in my top-10 list of all-time most educational experiences of my career.
I strongly encourage anyone that wants to become a better developer to take on the task and create a useful distribution for CPAN and/or work on an existing distro. There are plenty of projects out there (such as Moose, DBIx::Class, and Catalyst, to name a few) that need help and can use all the hands that they can get.
Now, if you would instead like to create your own distribution on CPAN, go for it! Its really quite easy and fun. But, it is VERY important that you think long and hard about what you want to release on CPAN. It may seem that every possible task that someone might want to accomplish in Perl is already available on CPAN – this is false. I regularly find myself needing tools that aren’t yet on CPAN. Don’t just write something for the sake of getting something on CPAN – develop something that is useful, of high quality, has a decent suite of automated tests, and doesn’t duplicate a module that is already on CPAN.
Once you developed a module or two, and you are ready to get it out the door, you’ll want to do a couple things. First, create a directory to hold your distribution. Assuming your module is named Acme::Yesterday:
cd Acme-Yesterday
vi Makefile.PL
You’ll want to install Module::Install first, before you go any further as it provides a much easier to configure build/test/install process than the old-school ExtUtils::MakeMaker.
Now, your Makefile.PL will look something like this:
all_from lib/Acme/Yesterday.pm
requires DateTime
test_requires Test::More 0.42
(Notice the first line DOES have a semicolon at the end, while the rest do not)
Next, create a directory to put your module(s):
mkdir lib/Acme
vi lib/Acme/Yesterday.pm
Now, your module will need some minimum requirements such as declaring the version of the distribution, the license type, and a name. Also, most CPAN modules follow a common convention for documentation using POD. Here is the most minimal of a module:
use strict;
use warnings;
our $VERSION = 0.01;
=head1 NAME
Acme::Yesterday - Make time() return the same hour,
second, and even minute as exactly 24 hours ago!
=head1 SYNOPSIS
use Acme::Yesterday;
=head1 DESCRIPTION
I'm an interesting introduction to this module.
=cut
use DateTime;
=head1 METHODS
=head2 some_method
some_method();
Description of some_method().
=cut
sub some_method { ... }
1;
=head1 AUTHOR
Your Name <your@email>
=head1 COPYRIGHT
This program is free software; you can redistribute it
and/or modify it under the same terms as Perl itself.
Alternatively you can use Module::Starter to create a shell of a module for you.
Now for automated tests. At a minimum you should write a test that verifies that your module can even be loaded. Here’s how to do that:
vi t/00_use.t
The content of 00_use.t should be something like:
use strict;
use warnings;
use Test::More tests => 1;
BEGIN{ use_ok('Acme::Yesterday'); }
You’ll need to make a couple more files:
echo '0.01 - First release.' > Changes
OK, now just sit back and let Module::Install do its work:
make dist
make disttest
Assuming your tests pass when you run `make disttest`, you’re set to put your module on CPAN. The above steps would have now created for you a Acme-Yesterday-0.01.tar.gz. This is the file that you need to upload to CPAN. In order to upload a distribution to CPAN you’ll need to get a pause account. Once your request has been approved you can login to pause, go to the upload page, and upload your tarball. Within an hour or two your new distribution will be availabe on CPAN.
Once you’ve done this you’ll want to clean up your distribution directory as running the various make steps leaves around some files you don’t need:
Good luck!
Jul/092
I’m in the Top 100!
So, I’ve been hearing about this CPAN Top 100 list but nobody seems to want to provide a link to it in their posts. Well, I dug that out and come to find that one of my very own modules is in the top 100… FAIL list. Woot! Anyways, I fixed it up and all should be well in an hour or two when everything gets mirrored out/re-indexed/etc by CPAN. There are 3 different top 100 lists on the site, all of them are interesting, so go take a look. It tickles me that Reaction is in the 100 Heavy list. Reaction is mst’s wrapper around Catalyst that is still in very early development. It looks promising.
Jul/090
Scientific Troubleshooting
Over the years I’ve naturally applied scientific principles to the way I program. There are two main principles that I think most good programmers ought to know.
Occam’s Razor (Wikipedia)
The idea behind Occam’s Razor, when applied to programming, is that when you are presented with a problem you should pick the simplest solution first and go try and prove it. We naturally formulate possible reasons (hypothesis) in our mind as soon as we are presented with a problem. Most junior programmers will pick either the first, or the easiest, hypothesus and go forward blindly. Neither of these is the simplest.
The easiest one is not a good choice because easy has a different meaning for every programmer in every different situation. Easy could mean that you are willing to sacrifice hours injecting print statements all over 20,000 lines of code. Easy could mean that you don’t understand the underlying system, so, rather than dig in a little and understand how things are working behind the scenes, you opt to stay safe and kick the tires hoping that something will present itself to you.
Picking the first hypothesis is an even worse choice because you’re not even attempting to prioritize the steps you are going to take to find a solution for your problem. Instead you are just blindly jumping in and will likely waste hours determining that your first hypothesis was not correct.
The bottom line is when you are presented with a problem it is important to consider several possible reasons for the problem, choose the simplest reason, and then go forward. More often than not the simplest solution is also the fastest one to confirm, which allows you to get through your initial list of hypothesis fairly quickly. At this point you will have identified the problem, or will have ruled out a bunch of stuff that will allow you to better test your larger hypothesis.
Scientific Method (Wikipedia)
The scientific method, when applied to programming, is a set of steps to take when troubleshooting an issue. In many cases following the scientific method is overkill, as abiding by Occam’s Razor is usually more than enough. For larger issue it helps to apply the scientific method which helps you structure your course of action in to various steps and can give you a visual map of all the steps you need to take to diagnose, and fix, your issue. The steps are:
- Purpose – State your issue.
- Research – Find out about the topic, if necessary.
- Hypothesis – Predict a reason for the issue.
- Experiment – Develop a procedure to test the Hypothesis.
- Analysis – Record the results of the experiment.
- Conclusion – Compare the hypothesis to the experiment’s conclusion.
It is important to come up with several hypothesis, ranging from very simple to very complex, and repeat steps 3 through 6 for each one. Also, remember Occam’s Razor when picking which Hypothesis to test first.
I find it works best for me when I get a pen and a pad of paper. Steps 1 and 2 will be documented on the first piece of paper. Then each hypothesis, steps 3 through 6, will get their own sheet of paper. Sometimes I can get everything to fit on one sheet, but I usually have to overflow on to a second piece of paper anyways, so its good to plan for that up front.
These techniques apply to any programming language such as Perl, JavaScript, HTML, CSS, SQL, etc, and have saved me, and can save you, countless hours and frustration.
Jul/090
The Perl is Dead, Long Live the Perl 5
Andy Lester recently wrote Promote Perl 6 by saying “Perl 5″. I think its a great idea, and as you may notice I’ve changed my blog in the few spots necessary to fit. Thanks for all the great work, Andy!
