Wednesday, May 20, 2009

Modeling identity with KiokuX::User

If you're developing a KiokuDB based application then you probably already know about KiokuX::User. Here is a useful technique to keep your model flexible when you use it: instead of consuming the role in your high level user class, consume it in a class that models identity:


package MyFoo::Schema::Identity;
use Moose::Role;

has user => (
    isa      => "MyFoo::Schema::User",
    is       => "ro",
    required => 1,
);

package MyFoo::Schema::Identity::Username;
use Moose;

with qw(
    MyFoo::Schema::Identity
    KiokuX::User
);

MyFoo::Schema::User represents the actual user account, and any object doing the MyFoo::Schema::Identity role is an identity for such a user.

Keeping the two separated will allow you a number of freedoms:

  • Accounts can be consolidated or migrated easily
  • You can add support for additional authentication schemes
  • You can rename users but keep the usernames as primary keys (needed for backends for which uniqueness constraints cannot be specified)

Obviously you should also keep a set of identities in each user object.

3 comments:

john said...

I'm a bit confused about Kioku Sets, should you subclass them like you do with DBIC ResultSets in order to model behaviors operating on Set, or should there be a different way to approache this?

nothingmuch said...

No. You could, but it's a much simpler object, so usually no functionality is necessary (it's just a dumb collection). It's derived from the Set::Object API

nothingmuch said...

Oh, and if you do need to wrap them, use delegation, not subclassing. There are actually 3 different concrete set types depending on their materialization state (Transient, for sets that were created by the user, Deferred for lazy loaded sets created by the linker, and Loaded for vivified sets created by the linker. Deferred and Loaded behaviors are swapped by reblessing).