Cold Hard Code

My thoughts on the iPad.

By J. Shirley on April 3, 2010 12:47 PM |
Comments welcome

I've been a dedicated Mac user for about 2 years. I purchased a MacBook Pro 3 years ago, and used it just for traveling. The turning point for me was struggling for about 20 minutes to connect to an Airport WiFi network, and while I was sitting there 3 different people with Macs sat down and immediately loaded webpages. That made me envious.

The other part is that I saw how quickly the Apple laptops wake up (and sleep). That also made me envious. I've happily trusted Apple to make a device that I want to use to accomplish the task they built the device for. This is an important distinguishing factor, because trying to use an Apple device for a use not intended is very frustrating. This is why I still use Linux servers, and can't imagine ever switching.

With this all in mind, when I looked at the iPad there was a moment of confusion. What is this device? What are the competitors? The UMPC segment isn't there, and the iPad is different than tablets. I honestly don't think there are competitors on the market now (JooJoo doesn't count), but there certainly will be (the HP tablet, etc).

The iPad is the natural evolution of the iPod. The very first generation iPod hit the market with an MSRP of $399. Not very far off of the $499 for the iPad, released 9 years later.

The iPad is pushing the limits of current technology, much like the iPod did back then (for those people questioning this statement, I dare you to look at iPod competitors back then.)

With technology at the point it is now, the current crop of personal media devices is going to be the future. Apple did not do this abruptly, they have been slowly removing and testing the waters. The AppleTV was the first device for media consumption, and it largely failed. The iMac and Mini were full computer that was largely non-servicable by the end-user. The MacBook Air was the closest shot, a closed device without a lot of ports. This was the perfect litmus test to see if people in general were willing to start giving up on things they didn't use.

This is where we are at. We have purpose-built devices that excel at what they're built at doing. In the case of the iPad, it's exactly that: a pad. Much like a pad of paper, this is the new generation. It isn't a computing device, nor should it ever attempt to be one. It will fail at that, just as much as the current "Tablets" fail at being competitors to the iPad.

You don't want background tasks on this. It's a single-task type of device. Push notifications and perhaps event loops are important, but on the iPad (or any other Pad device) you should be focusing on a single task. This is the expectation the device has of its user.

The technology is to be able to quickly flip between tasks. This is where Apple has a leg up on competitors and I am not sure if the competitors are going to truly understand that the quick-task switching is the killer feature. One which Apple does well with, but I still think they could do better.

So after sitting with my iPad for a couple days, both using it as a productivity enhancer and just a media consumption device, I still think they have a hit. it's exactly what it should be. It isn't perfect, but none of the first generation of devices are. I'll be buying the next generation when it comes out, and be very happy.

Pros:

  1. Vivid screen. Very impressive, readable and perfect.
  2. Orientation Lock is fantastic.
  3. It works exactly as you would expect.

Cons

  1. It's heavy. I'll build up forearm strength simply reading in bed (a pro?)
  2. There is disparity between applications on which way is down. The case should resolve this. Certain applications have fixed orientation (usually games) and that "Down" direction may be counter to what is natural to you, and it doesn't rotate. As an example, Harbor Master's "Down" is contrary to the case.
  3. Apps are expensive. More screen real estate does not automatically make something worth more. The app itself needs to be more. There isn't the "14 Day Free Trial" editions on the iPad, and because of that it precludes me from buying a lot of applications I'd like.
  4. The App Store. It has too many limitations. No free trials, the iPad/iPhone split isn't clean enough.

Now, each and every one of those cons is temporary and I'm certain will be resolved within the next couple of years. I'll be on my 3rd iPad and probably my 5th iPhone by then, and enjoying every one.

Comments welcome

An early project migration, from MogileFS to MongoDB.

By J. Shirley on March 24, 2010 7:36 AM |
Comments welcome

As vaguely announced, a few days ago we launched a new project called CodePeek.  While we have our own reasons for this particular project, it was really just a very quickly done project that, by default, was built using the tools that we had available to us and experience with.  One of those tools we picked simply because of familiarity was MogileFS.

MogileFS has always been my default choice whenever I needed to store a lot of data somewhere, without any relational context to that data.  It handles replication, and for the most part just works.  For things like pastes, with the support for images and other media types, it was a reasonable choice.

Except it is just a bit fragile and lacks certain features that we really wanted to have available to us.  I don't want this to be interpreted as being critical of MogileFS because I think it's good software.  However, I do think that it is software that requires more attention than what we wanted to give it and also is not an exact fit for our purposes.

This discussion was happening while we are also exploring various document-based storage engines (commonly referred to as "NoSQL").  This movement has produced CouchDB and, of course, MongoDB (as well as many others).  For us, MongoDB looked like the obvious solution because it supports replication, has an incredibly easy API and was very fast in our tests.

After about an hour of hacking and debugging last night, I had everything working.  I spent 20 minutes this morning writing a migration script and everything has just simply worked.

With a total investment of about 2 hours — including setup, "apt-get install mongodb" wasn't much trouble — we have replicated MongoDB storage (across 2 Linodes), and new storage code.  I'm pretty impressed with the agility in which we can move to replace a storage backend, and believe it is a testament to the quality inherently available when using superior tools, like Moose, Catalyst and DBIx::Class.

Comments welcome

Designing Codepeek: The Logo.

By gphat on March 20, 2010 6:10 AM |
Comments welcome

Much of my work to date with Cold Hard Code has been for relatively large applications.  These big, complex applications can quickly overwhelm so a lot of time is spent keeping things simple.  Our most recent project, Codepeek, gave me a chance to make something less intense.

The logo came together very fast.  Hoefler & Frere-Jone's Tungsten is CHC's corporate font so it's use was predetermined.  I had it in my head to create something playful, classy and more pop than my usual work.

From jump I knew that I wanted to set the text on an arc. After a few attempts I finally found what I wanted with a negative leading. This gave it a presence that reminded me of an announcer crowing to the crowd: Codepeek has arrived!

The two-tone effect is intentional, providing some clarification for the words.  The name is inspired by the concept of "peeking at code".  My original idea was "peekcode" but the k and c felt like a linguistic train wreck that refused to roll off the tongue.  Codepeek worked much better but was backward from my original concept.  Placing "peek" front and center in bright white balanced the message I was trying to send.  Careful not to forget the "code" I added a strong gradient and some subtle dots that are intended to look like bubbles rising in the code.  Those embellishments can be easily removed and the logo reduced to two colors very easily, fulfilling one of the rules of logo design.

The small leaves set behind the name are decorative fleurons that provide some distinction for an otherwise wordy logo.  It's a purely subjective decoration that I have an odd affinity for.

Codepeek was a great project that Jay and I took from concept to production in just over a week.  It gave me an opportunity to create a light, playful identity that I'm very proud of.

Comments welcome

CPAN Improvements, Take 2.

By J. Shirley on February 2, 2010 5:54 AM |
Comments welcome

I'm now revisiting my CPAN post from before.  The illustrious charsbar commented about CPAN options that certainly do a good job hiding the things you don't need to see, except for when you need to see them.

I thought I'd give some examples to show how these options are not good enough, and not really what I'm after.

First, imagine the case of local::lib being setup.  Then you run CPAN (1.9402) after local::lib aliases are setup; As expected, right after 'cpan', you are met with a configuration prompt.  It tells you that you have no access to write to /root/.cpan.  Of course, because we're good developers and use local::lib.  This works well, the user configuration is created but then there is a problem:

nolock_cpan[1]> o conf halt_on_failure yes                             
 halt_on_failure [yes]
Catching error: "/etc/perl/CPAN/Config.pm is not writable at /usr/local/share/perl/5.10.0/CPAN/HandleConfig.pm line 286\cJ\cICPAN::HandleConfig::commit('CPAN::HandleConfig') called at /usr/local/share/perl/5.10.0/CPAN/HandleConfig.pm line 213\cJ\cICPAN::HandleConfig::edit('CPAN::HandleConfig', 'halt_on_failure', 'yes') called at /usr/local/share/perl/5.10.0/CPAN/Shell.pm line 393\cJ\cICPAN::Shell::o('CPAN::Shell', 'conf', 'halt_on_failure', 'yes') called at /usr/local/share/perl/5.10.0/CPAN.pm line 375\cJ\cIeval {...} called at /usr/local/share/perl/5.10.0/CPAN.pm line 372\cJ\cICPAN::shell() called at /usr/local/bin/cpan line 198\cJ" at /usr/local/share/perl/5.10.0/CPAN.pm line 391
	CPAN::shell() called at /usr/local/bin/cpan line 198
That wasn't what we wanted, right?  Here's another point, and an easy bug.  If CPAN knows it created a user configuration, automatically reload it.  Minor nit.  CPAN.pm has a plethora of open bugs, it's daunting to just file a bug because you don't want to file a dupe.  After I write this post, I'll see about that.

So, you exit cpan and restart, it says the other process isn't responding.  Overwrite it?  Sure!  Now we're in business.  This is not a good user experience.  So far it looks like everything is broken, and there isn't anything shown to the user that CPAN is ready to do what it is supposed to do.

Now that we're here, setting the various options charsbar pointed out works. As expected, now just the "perl Makefile.PL" is loud and the installation prompts fill the backlog.  It is much improved, as the more important details are present.  The screen is still filled with all sorts of information that I don't need, or even want.  Test passes, etc.  The verbosity options merely affect CPAN.pm operations, and not the actual building.  I want a very nice filter.  

When things fail, the situation is no different regardless of the CPAN options.  I have pages and pages of text to deal with, the only benefit is that now I aborted on a failure.  I have no way to jump in and attempt to resume after fixing this error.

Here's the output of the first test failure (namespace::clean) that just stops the install in its tracks:
t/07-debugger.t .......... 
Loading DB routines from perl5db.pl version 1.32
Editor support available.

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

main::(t/07-debugger.t:26):	    package Foo;
Unknown error
Compilation failed in require at /home/ems/perl5/lib/perl5/Term/ReadLine/Perl.pm line 63.
 at /home/ems/perl5/lib/perl5/Term/ReadLine/Perl.pm line 63
	Term::ReadLine::Perl::new('Term::ReadLine', 'perldb', 'GLOB(0x8465e28)', 'GLOB(0x83ba9e8)') called at /usr/share/perl/5.10/perl5db.pl line 6073
	DB::setterm called at /usr/share/perl/5.10/perl5db.pl line 2237
	DB::DB called at t/07-debugger.t line 26
Test::Builder::CODE(0x8429fc8)(/home/ems/perl5/lib/perl5/Test/Builder.pm:2426):
2426:	    $Test->_ending if defined $Test;
Attempt to reload Term/ReadLine/readline.pm aborted.
Compilation failed in require at /home/ems/perl5/lib/perl5/Term/ReadLine/Perl.pm line 63.
END failed--call queue aborted at t/07-debugger.t line 63.
 at t/07-debugger.t line 63
Attempt to reload Term/ReadLine/readline.pm aborted.
Compilation failed in require at /home/ems/perl5/lib/perl5/Term/ReadLine/Perl.pm line 63.
END failed--call queue aborted at t/07-debugger.t line 63.
 at t/07-debugger.t line 63
Test::Builder::DESTROY(/home/ems/perl5/lib/perl5/Test/Builder.pm:317):
317:	    my $self = shift;
t/07-debugger.t .......... Dubious, test returned 9 (wstat 2304, 0x900)
No subtests run 
t/08-const-sub.t ......... ok   

Test Summary Report
-------------------
t/07-debugger.t        (Wstat: 2304 Tests: 0 Failed: 0)
  Non-zero exit status: 9
  Parse errors: No plan found in TAP output
Files=9, Tests=73,  0 wallclock secs ( 0.02 usr  0.03 sys +  0.42 cusr  0.07 csys =  0.54 CPU)
Result: FAIL
Failed 1/9 test programs. 0/73 subtests failed.
make: *** [test_dynamic] Error 255
  FLORA/namespace-clean-0.13.tar.gz
  /usr/bin/make test -- NOT OK
//hint// to see the cpan-testers results for installing this module, try:
  reports FLORA/namespace-clean-0.13.tar.gz
Running make install
  make test had returned bad status, won't install without force
Stopping: 'install' failed for 'F/FL/FLORA/namespace-clean-0.13.tar.gz'.
Failed during this command:
 FLORA/namespace-clean-0.13.tar.gz            : make_test NO

We're still not in any position to help the user.  What do to from here?  Well, the only thing is to see cpan-testers results.  This doesn't help anybody succeed.

So, even with the verbosity options set to the quietest setting, it does nothing for the output of the various Makefile.PL/Build.PL outputs.  There isn't any assistance offered, or even help for the user to plug into a google search.

If these modules are on the CPAN, it is reasonable to assume a standard of behavior.  Such that my desired output is feasible:

 * Fetching {module name}...  ok
 * Unpacking {module name}...  ok
 * Following dependencies...  ok
 * Testing {module name}...   ok

The other thing would be to have a full dependency list calculated at the start, so it can be determined what packages need to be installed and in what order, just to suppress the enter-mashing problem.

I suppose that a lot of this could simply be an output processor for the make/install loop, and then other CPAN loops.

If the Perl community wants to tout "the CPAN" as the killer feature, then CPAN.pm needs to be a killer feature.

I'm hoping the next version of a CPAN shell keeps this in mind, and it ultimately boils down to these priorities:
  1. Don't inundate the screen with useless messages on success.
  2. Don't be terse and not include messages on failure.
  3. Help the user.
On a related note, I came across an article titled Marketing the Entire Box (including the wrapper) while writing this.  It's a good read which I highly recommend.

Developers may find marketing to be slimey and sleazy, but understand that having a tool that insults and frustrates the user is just as much marketing as having a beautiful website with quality typography and information architecture.

I'll get off my soapbox now.

Comments welcome

Improving CPAN, make money and help Perl.

By J. Shirley on January 22, 2010 9:46 AM |
Comments welcome

I have a new server to setup, which will be a staging and development environment.  This means I'll be installing much more than is typical, and I figured it is a good chance to test the legs of Task::Kensho.

The first line summary is that I'm slightly disappointed, because there were failures in mid-stream and while it continued, it wasn't exactly intuitive as to the failure.  One of my biggest complaints about working in any programming language is when you get ambiguous failure messages.  Failures with messages "Can't locate namespace/clean.pm in..." followed by a tremendous deluge of test failure messages counts there.  Especially when namespace::clean should have been installed.

Update: The bounty and details are at the bottom, but sartak is also throwing in $100.  $200 to make a CPAN client that doesn't scare people.  Lets do it, people.

And here is the long version.  I setup a Linode 360, deployed Debian 5.0 on it.  After it booted, I added my user account and setup sudo.  Then proceeded down the path of having a working development environment:

sudo apt-get install perl mysql-server libdbd-mysql-perl lib-dbd-sqlite3-perl build-essential unzip

If you don't install unzip, CPAN can't find it and will error when it encounters a package that is zipped.  Why people upload packages to the CPAN as a zip I'll never know, but that's their (silly) choice.

After this, (as root) I install local::lib
sudo su -
cpan local::lib

On Debian 5.0, CPAN has the capability of automatically configuring itself.  This is nice, and just works.  So far so good.

Now, under my user account:

perl -Mlocal::lib >> .profile
. .profile

At this point, I can use CPAN as my user and install into my perl lib directory and not deal with anything on the system level.  No more sudoing, so enter Task::Kensho.
cpan Task::Kensho

Here you have a lot choices, but fortunately they are easy to understand.  Since I'm working with DBIC and Catalyst, with lots of Moose, those were the choices I made - as well as selecting the various command-line options and other utilities for developing.

Unfortunately, the Moose section failed.  Sub::Identity failed to download, thus blocking namespace::clean from installing, subsequently failing MooseX::Types and then I had a little storm of failure.  This is quite frustrating, but I just ran "cpan namespace::clean" in another session and was able to install it properly the second time.

Now to be safe I installed MooseX::Types and MooseX::Types::Path::Class, since that was the point that it failed.

Here's an important bit.  If I wasn't paying attention I would have no idea what failed, or why it failed.  CPAN silently continued on to the next module and I had to scroll up to see the failures and only my experience with Perl and CPAN was able to allow me to continue.

Also, there is a lot of enter pushing.  There are options to automatically follow, but because of failures like above I didn't set that.  Good thing, or I wouldn't have everything installed.

I had the same issues with several other modules, mostly in the Task::Moose bundle.  Each one, while installing separately, was successful; only when part of Task::Kensho did these fail. I don't mean this as a criticism of Task::Kensho, instead it is about the CPAN client.

It has messages that are quite specific:
Warning: Prerequisite 'Parse::Method::Signatures => 1.003012' for 'A/AS/ASH/TryCatch-1.002000.tar.gz' failed when processing 'F/FL/FLORA/Parse-Method-Signatures-1.003013.tar.gz' with 'make_test => NO'. Continuing, but chances to succeed are limited.

Too specific, CPAN knows it is going to fail and instead of stopping to ask the user for help or doing something that will be useful, it continues on and buries the failures amidst dozens of lines of meaningless test failures.

It's not a terrible experience, but it is extremely verbose and the most important messages are hidden.  You have to either decide between hitting enter constantly at each dependency step, and catching when things fail, or simply hope that things will succeed.  In my experience, they won't succeed and as such I'm forced to press enter a lot and keep another session open so that I may install modules that fail by hand.

This is not an experience that a user who is new to Perl should endure.

In an effort to be constructive, here is how I envision a much better process.

CPAN has a default output mode that is not so verbose.  I don't need to see the result of unpacking a module, the prerequisites that aren't found and the requirement list.  I should instead see something like this:

 * Fetching {module name}... ok
 * Unpacking {module name}... ok
 * Following dependencies...

In the case of a failure, or an attempt to fetch a dependency that has failed to install, CPAN should immediately pause and ask the user what to do.  The reasonable choices are: Attempt to refetch/install, Show Details or Abort.  If you show details, it should show the entire log from the Unpack to the Failure.

I'm not familiar with CPAN internals, and don't really care to be.  So, here's my offer to solve this problem.

$100 in cash, check or paypal, to anybody who gets a mode of CPAN working as described.  The money is just a token, and I have no idea how long it will take to do this.  It doesn't seem complex to simply reduce output and change that "Prerequisite failed when processing" message I listed above to something helpful.  Maybe $100 is too little, but the point is you're helping the Perl community by making our most valuable tool more functional.  Comments welcome to flesh this out, maybe other people are interested in matching additional funds to whoever can make CPAN not so daunting to new users.

I will test it in the same fashion as above, starting with a fresh debian 5.0 install and local::lib and whatever CPAN modules need to be installed for this to work.  I will then fire off installing Task::Kensho.


Comments welcome

Using lazy_build for maximum effect.

By J. Shirley on January 1, 2010 2:11 PM |
Comments welcome

Rather abruptly I just came to a conclusion that I could remove a swath of code if I just had called a clearer method, and used a lazy_build to populate an accessor.

I have a list of items that is persistent, but I perform various calculations that are costly and prefer to only do them on demand.  In other words, lazily.  To avoid any unnecessary recalculation I also want to preserve the returned value.  The conditions that cause the result to be stale are very well defined.

So, the simple solution was to rename my calculation method to _build_expensive_thing, create an attribute with lazy_build and in my method that invalidates, clear all those.

In simpler and more exact terms, this:

Comments welcome

My favorite feeds.

By J. Shirley on December 9, 2009 12:14 PM |
Comments welcome

Continuing my entry from yesterday, I'd like to just list some of my favorite feeds at the moment.  These are just the various blogs that I'm particularly enjoying at the moment, and I decided to limit it to only 3.

nothingmuch's blog at http://blog.woobling.org/
It's hard to find someone who knows so many languages and can communicate the knowledge in such a thorough and easy to understand way.  His blog is simply a glimpse into his capabilities, but mostly he provides recipes for simply doing things better.  He has a knack for simplifying common tasks (with the usual side effect of added robustness).
lestrrat (Daisuke Maki) at http://mt.endeworks.jp/d-6/
I like Maki-san for a variety of reasons.  He's probably one of the most entertaining Perl hackers to be around at a conference. He has a really phenomenal view of Perl and programming in general, because he's making a living running a consultancy in Shibuya (Tokyo) and also running the Japanese Perl Association.  When he writes it's interesting to read his perspective, since I think he offers a fairly unique perspective.
The downside of his blog is that many entries are in Japanese.
Stevan Little at http://stevan-little.blogspot.com/
Stevan is the attentive care giver of Moose (founder, guider?) and all around encyclopedia of programming knowledge.  He offers a perspective that is fairly unique, because of his very deep understanding of what seems to be all programming languages.  Oh, and of his crazy involvement in Moose.  It's pretty amazing what he manages to accomplish.

There are many more blogs I read, but lately these have been the most interesting. As my interests or the content shifts, I'll post updates to my favorites (and try to limit to just 3 people in each post).

Comments welcome

Being in Open Source.

By J. Shirley on December 9, 2009 12:06 PM |
Comments welcome

My wife and I have been together for over 7 years. In that time, she has watched me go from a developer to an Open Source contributor. The latter transformation is largely due to the Catalyst framework, and in particular mst encouraging me to actually contribute.

I don't think she understands why, and I'm not sure if I did either. To be very clear, I'm not a contributor in the truly giving sense of a word. To be fully honest, I contribute in a way that benefits myself. I have learned more from the core hackers than in any job, course or conference. This is my ultimate motivator to stay involved in the community.

The main take away from participating in the Perl community is my own personal and professional development. I learn. I learn quickly and discover many great things I wouldn't discover on my own. There is an additional benefit of finding a way to work on some very fun things.

It saves me time and troubles doing what pays me, so my job gets easier and better as time goes on.

I try to make a difference, but I know that my contributions are nothing remarkable. Anything that I've done that was remarkable was simply because I happened to arrive at a point first.

Even though my contributions are functionally marginal, I feel incredibly gifted and thankful to be accepted in a community as great as the modern Perl hackers.

These inventors of great things spontaneously evolve an idea into a functional product in amazingly short time. To witness these moments is something you cannot get in any office, Internship or academic setting.

I'm involved in Open Source because I've never found a more efficient and thorough vessel of learning. The skills I've developed while simply being around these giants are, at least for me, unattainable anywhere else.

Out of the various Open Source projects I've participated in, none have been as influential as the Perl community. In particular, the Moose and Catalyst sub-communities.

Thank you all who have made this community what it is.

Comments welcome

Plack and the Perl WSGI (PSGI).

By J. Shirley on December 8, 2009 8:13 AM |
Comments welcome

For those not familiar in what's happened since Rails has taken off, and Django has become a very robust and popular framework, there has been a movement towards something coined WSGI, Web Server Gateway Interface. This is a specification that is very prevalent in the Python community, and is generally accepted as a Good Idea. In a nutshell, it tries to normalize and enhance communication from an application to the frontend webserver (so that lighttpd, apache and nginx differences are nullfied)

Ruby has a reference implementation called Rack, which takes and shares many ideas of WSGI, but makes it Ruby-ish.

Perl now has Plack, an astounding effort by Tatsuhiko Miyagawa. Plack has been awarded the "Module of the Year" award at London Perl Workshop, and in my opinion is very well deserved.

Within Plack, you can write very lightweight applications just using what Plack offers. You can also use Plack to handle deployment of several other frameworks, including Catalyst (via Catalyst::Engine::PSGI).

As an example of what can be done, I first saw Tatsumaki. Tatsumaki is an event-driven HTTP server that handles streaming (as well as long-poll comet services).

I built an application using Tatsumaki to handle streaming live race results to people who couldn't make it to the track.

It worked out very well, except for a small memory leak (that has been fixed). I had, at peak, 615 concurrent clients with an average of about 380 concurrent clients.

I was using the Plack server directly (Tatsumaki::Server), and having clients connect directly to it. I had a peak throughput of 10Mbps, with an average of 1.6Mbps of data going through Tatsumaki.

I call that a fantastic success, and thank Miyagawa-san for his hard work in getting this software to where it is. Without Tatsumaki, and Plack, I would have been doing a hacky long-poll solution that would have been much slower and less featured.

I also built a YUI3 based Multipart XmlHttpRequest library so that I can stream using YUI3 (I prefer this over jQuery) but IE failed to work, so I had to fall back to long-poll clients which worked more similarly across all browsers.

Comments welcome

Advent Season is upon us..

By J. Shirley on December 7, 2009 10:00 AM |
Comments welcome

There's a lot of Perl Advent articles around this year. It's very neat to see this, and rather than add yet another article, I'll instead reference the articles I find to be very useful and stand out.

How Catalyst Happens
mst's great writeup on how Catalyst evolves, works with contributors and collaborators. If you're curious how large open source projects handle a large number of contributors, this is a good read (275 contributors at the time of writing)
RJBS writes about Sub::Exporter
One thing I think has turned a lot of people away from Perl is the exporting and namespace handling (partially due to the out-of-the-box weakness of Perl's OOP). RJBS thankfully wrote Sub::Exporter, and it cleans up this into a very sane API.
Convert CGI apps to Plack
If you haven't heard of Plack, you're missing out. Miyagawa's awesome new reference implementation of PSGI (Perl's WSGI) is simplifying a lot of lives, mine included. This little recipe shows how you can convert your old school CGI apps to a managed and sane Plack-handled set of scripts. Of course, there is a lot more to Plack you should read about.
Using local::lib
I love local::lib, and this article by Stephen Scaffidi is a good writeup on setting it up. The big thing to remember with local::lib is to upgrade Module::Install and Module::Build to make sure everything runs as smoothly as possible

That's it for now, I'll post more of my favorite advent articles as we get closer to Christmas.

Comments welcome