Tuesday, June 30, 2009

Refactoring with roles for testing

The programming I've been doing lately is very straightforward Perl. It's hard to think what might be interesting about it... and I don't want to look like an idiot and blather on about something that everybody else was doing in kindergarten.

So maybe this is nothing exciting, but it's what I was doing yesterday.

I'm working on replacing an ancient grew-up-over-seventeen-years Perl backend system with more modern Perl. Instead of using a database for most of it, information on state and status is encoded in Linux file permissions and empty files, and in strings in files. Etc. Etc. I'm updating a large portion of it to use a semi-real database (MySQL - but in this case it really is a step upward), but I'm a one person programming team and it just wasn't feasible to rewrite the whole system in one project. As it is, the project was really too big for one person, but it just wasn't possible to do a decent job without completely re-doing a fairly large chunk.

So I get to an interface to a part of the old system, where instead of just storing some flags in the database I have to write an empty file in one directory for one state, copy a file to a different directory for another state, append a line with an identifier in it to a file for a third state... You get the idea.

At this point it's not clear whether the section I'm interfacing to will ever be rewritten. The higher-ups have gotten pretty twitchy at how much this is costing, and I'll probably have to work on some PHP project part time in the fall. So I don't know if this interface code will ever be used in any other module. But it's irritating stuff to test and debug because it's used in the middle of a fairly long and complex process.

So I plopped it all into a Moose role and created a test case with a dummy package:

   use Test::More tests => 3;
   
   {
      package Test::SomeInterface;
      use Moose;
      with 'Some::Kludgy::Interface';
   }
   my $test = Test::SomeInterface->new;
   ok( $test, 'it compiled!' );
   ok( $test->process, 'it didn't blow up!' );
   ok( $test->some_status, 'it worked!' );

So now the funky interface code is packaged off by itself and easily replaced, it was much easier to test than buried in some larger module, and if I'm lucky I'll never have to look at it again.One nice side effect of doing this was that I was forced to clean up what I was passing in to the methods instead of relying on the fairly global object attributes.

Pretty obvious, I guess. But it's yet another way in which Moose makes programming more bearable - when fun is too much to hope for. I <3 Moose.

Tuesday, June 16, 2009

Where the cleaver falls...

Way back in the dark ages, I worked on one of the first projects at IBM to use that fancy new methodology, object oriented programming. They sent the whole team to a month of OO training, and then that wasn't quite enough to bring us up to speed, so they sent us to another month with a different traning company. I remember that one month used a well-regarded (at that time) book by Grady Booch. The whole object thing wasn't that hard to understand, but the thing that I couldn't quite wrap my mind around was how you figured out what to make the objects, how to split up the problem domain into pieces. So I eagerly flipped through the Booch book, thinking that they must have some words of wisdom on this point, and finally I found it. Buried somewhere in the middle they had one page with three paragraphs which basically said: and then a miracle occurs.

Pretty much the equivalent of the humorous saying somebody I know was fond of: Where the cleaver falls, there the chicken parts. (Maybe you had to be there...)

So I was working on a comment screen that needed a captcha. I had never used one before, but I figured it couldn't be that hard. HTML::FormHandler is a form processor, and a captcha is a form element, so it seemed obvious that a captcha field for HFH was in order. That part was easy... And then I realized that in order to check the value typed in by the user, the captcha had to be stored in the session. The session (in this case) is managed by a Catalyst plugin, and for the form field to be aware of the session just seems wrong. Too much mixing of areas of concern.

So a Moose role comes to the rescue. (Perl!) I created a Moose role that contained the captcha field, plus provided 'get_captcha' and 'set_captcha' methods. This seems relatively clean - or at least better than having the field mess with the session. Of course in order to access the session, the Catalyst context or session needs to be passed in to the form object. Not ideal, but not all that bad either. But now these methods are form methods... They could be turned into callbacks, or coderefs that are set on the field, but I've already had to deal with not-entirely-clean relationships between form and field before, so for now I decide to just call them as form methods. I don't really like this, because I'd prefer that the fields not know about the object that contains them, but it's easy and it works.

Then I realize that I'll need a URL for the image in the field. Damn. This is getting messy. I suppose that I can add yet another attribute 'captcha_url' and set THAT too. But then there's another required piece of code that's neither form nor field, but a controller action. Sigh. It's too many different pieces of code for one simple thing.

Oject oriented programming is no longer the new, shiny thing that it was so long ago, but the problem of splitting up the problem into nice little pieces is still with us. That OO training was for was an early attempt at an object oriented interface to a SQL database. It failed utterly. Looking back, I have to say that the problem wasn't fully understood - or at least we didn't understand it. It was a brave attempt, but a fair amount of knowledge about the problems associated with doing ORMs has grown up, and they're better these days.

So I guess progress is being made. In some places by some people..

Friday, June 5, 2009

Flexible extensions with Moose method modifiers

When constructing an API for a library intended to be subclassed by users, you run into the classic tension between power and simplicity. Too many ways to call your code, too many different methods and the user is overwhelmed. Yet if you don't have enough power, the user may by stymied when he reaches some level of complexity.

Moose method modifiers provide a lot of flexibility that doesn't necessarily have to be provided by an explicit API. In some cases they may provide stopgap ways of extending, in other cases they may actually be better than creating more complexity by providing more explicit hooks.

The main processing method for HTML::FormHandler is pretty straightforward:
sub process
{
   my $self = shift;

   $self->clear if $self->processed;
   $self->_setup_form(@_);
   $self->validate_form if $self->has_params;
   $self->update_model if $self->validated;
   $self->processed(1);
   return $self->validated;
}
The above method is called when a form is processed:
   my $form = MyApp::Form::User->new;
   $form->process( item => $user, params => $c->req->params );
The form is something like:
   package MyApp::Form::User;
   use HTML::FormHandler::Moose;
   extends 'HTML::FormHandler::Model::DBIC';

   has_field 'username' ( required => 1 );
   has_field 'some_attr';
A common need is to have particular fields be required in some circumstances and not in others. So maybe it would be nice to have some kind of callback to determine whether the field is required or not... But a simple Moose method modifier on one of the methods called in the 'process' routine will do the trick just fine:
   before 'validate_form' => sub {
      my $self = shift;
      $self->field('some_attr')->required(1)
         if( ...some condition... );
   };
Now maybe there's some magical API syntax that could achieve the same thing, but really this is pretty straightforward and easy. Maybe there's some additional database update that you want to do that's not directly related to the fields, such as recording that the user updated his record. Another Moose method modifier comes to the rescue:
   before 'update_model' => sub {
      shift->item->user_updated;
   };
...where 'user_updated' is a method on your DBIx::Class result source that sets a flag or an updated time or whatever you want. The same result could be achieved by subclassing the methods of course, but the method modifiers can also be used in Moose roles, making it possible to split up your form pieces into nice chunks that can be reused in multiple forms.
   package MyApp::Form::Options;
   use HTML::FormHandler::Moose::Role;

   has_field 'opt_in';
   has_field 'something_else';
   after 'validate' => sub {
      ...do some specific cross validation...
   };
   before 'update_model' => sub {
      ...some db processing...
   };
And then a form class could just be a collection of roles:
   package MyApp::Form::User;
   use HTML::FormHandler::Moose;
   extends 'HTML::FormHandler::Model::DBIC';
   with 'MyApp::Form::Options';
   with 'MyApp::Form::Login';
   1;
So the power and flexibility of HTML::FormHandler's API are increased without extra code simply by using Moose and its method modifiers. When I was originally hired to program in Perl I wasn't that happy about it, partly because the native Perl OO features are weak and kludgy. But with Moose that's a thing of the past. Perl + Moose are as good as or better than any other object oriented language I've worked with.