|
Back in January, I started doing work on the Perl Foundation grant for the perl survey. I'd gathered all the data together, and done a fairly sizable job of cleaning it up, when along came a new job and a horrendous set of deadlines for the now imminent Catalyst book. Meanwhile I was waiting for Skud to give me the original Perl Survey 2007 report which had fallen off the net. So for now, I'm going to go through the survey report fairly slowly, replicating the previously presented analysis in R code and writing notes about what extra things can be done with the extant data. Once this is done, I'll look at things that can be dropped from the old survey, and think about enhancing the next iteration of the survey with more questions. |
| Posted on Mon, 29 Jun 2009 12:51:25 -0000 | permalink |
| The new version of Catalyst::Example::InstantCRUD is on CPAN. This version uses FormHandler, is a bit nicer visually (I hope) and has a proof of concept experimental REST interface. |
| Posted on Mon, 29 Jun 2009 07:36:00 -0000 | permalink |
|
I wanted to drop in and explain my lengthy absence, especially given some interesting "part two" articles in my queue that several of you have emailed me hoping for an update. In particular there's a pending summary of all the feedback regarding ...
|
| Posted on Fri, 26 Jun 2009 13:19:10 -0000 | permalink |
|
In Packaging cross cutting Catalyst features I promised to start developing a generic Catalyst comment sub-system. Now I have incorporated the code samples into another experiment - ravlog(a blog engine by Gerda), and I would like to ask you what you think about it before releasing it to CPAN. Here is the current API - any comments are welcome. First you need to declare the controller using the new Moose style: The important part for us is of course with 'CatalystX::Comments::ControllerFormRole', the model_name attribute should hold the name of the model CatalystX::Comments will use to store the comments.After the declarations you can use CatalystX::Comments to put the comment form on the stash: |
| Posted on Sat, 20 Jun 2009 16:13:00 -0000 | permalink |
|
In my previous post on modeling identity I showed how to decouple identities from accounts. Here is a more in depth look at how and when to separate all the pieces of a user's data from one another. What is a user?Applications typically have an object that models the user, but strictly speaking this is not really the user. The user is the human operating the user agent that interacts with the application. The object approximating the human is a number of different things:
What's important to realize is that these things are actually separate parts of what the concept of a user means the system. Even if you roll all of them into a single class you should be able to make the distinction, and be able to break them out into separate objects should the need arise. Whenever the representation of users in your database is too limiting, it's usually a direct consequence of the different aspects of the users' representation being lumped into a single user entity. Refined conceptsHaving a language with which to talk about a problem space is a vital tool for understanding and solving a problem. Here are some terms for this domain:
There is significant overlap in these terms: For the duration of a session, user agent is synonymous with the user. Humans aren't made of software, so that's as close as the application will get. But this relationship is transient, the same user could use another user agent at a later point. For the application to treat the user agent as if it were the user it must prove an identity. Typically the identity is a username and a shared secret is used for verification, demonstrating that the meat operating the user agent is who it claims to be. The system stores any information about the user in the user's account data. All actions in the system are carried out by an actor. In order to perform an action this actor assumes a role. The tricky part is that the word "user" can be used to vaguely describe every one of these terms, usually without problems. However, when there is a need for a distinction this causes confusion. So When does "user" break down? Whenever you need to have multiple instances of these entities, associated with a single human. RolesRoles solve the problem of needing separate access levels for different users. A naive solution for multiple access levels involves an access level number (or even just a super user flag) that assigns additional privileges in the system, but it's very hard to change the access controls or to add finer grained permissions. If you assign each permission to each user separately this data quickly becomes unmaintainable as well. Role based access control is a well understood solution to this problem. Permissions are assigned to roles, and roles, in turn, are assigned to users. I won't explain RBAC, it's far too broad a topic (Google is your friend). The point I'm trying to make is that this useful abstraction relies on decoupling the notion of who the user is from what the user is allowed to do. Taking a page from capability based systems, instead of using roles as simple data you could even use them as the actual entry point to privileged operations. If the user doesn't have access to the role then sensitive operations are not blocked, they are simply inaccessible. This is a compelling case for making roles a first class entity in the system. Most applications won't need such flexible authorization, but for the applications that do this is a powerful abstraction. Suppose you have 3 roles: Guest, Unprivileged, and Administrator, these roles can be associated with very fine grained permissions. User agents representing unidentified users only have access to the Guest role, but logged in users can perform operations enabled by any other roles they've been granted. If Administrator is needs to be split up into Moderator and Superuser, most of the code remains unchanged, and the operation that updates the existing user data is simple too, so making this change go live is relatively low risk. IdentitiesSupporting multiple identities is another fairly well understood problem, at least recently. Many applications are starting to support OpenID authentication, and usually existing users expect to be able to associate their existing account with a new ID. Another example is when Yahoo bought Flickr. Flickr suddenly had two keyspaces for identities, Yahoo IDs, and Flickr usernames, both of which mapped to a single account keyspace. If you model identities as standalone data that references a user (as opposed to being a primary or surrogate key of the user) then you can easily integrate orthogonal authentication mechanisms like RPX, SSL certificates, or just simple usernames/passwords, without polluting any code except the authentication layer. The rest of the code can stay concerned with only the user account the IDs map to. ActorsIn this case I'm referring to actors in the UML sense, not the actor model sense. I don't have a positive example for multiple actor support, but there are plenty of negative ones. First and foremost is Google Apps. I've often wished I could access my work email/calendar from my personal account. Since my personal account will likely outlive my work account I don't want to use it for work or vice versa, but I still need to access the data from both. Fortunately for me email forwarding takes care of pretty much everything, but it's not a real solution. Instead of being able to quickly switch contexts, I need to copy all the data into one place. Google knows I have access to my work email through forwarding so it lets me pretend I am sending email from there when I'm using my personal account, but there's still no segmentation. Linode is another example. In order to manage work vs. non work machines I need to log out and log back in using a different account. Hypothetically, the two actors that would act on my behalf in a these examples would be "Yuval the employee of Infinity Interactive" and "Yuval the unique snowflake". These are both extensions of my person, but they serve different purposes. While an identity identifies the user from the outside, an actor identifies a user inside the system. AccountsIn a simple system there usually isn't a strong case for multiple accounts, except when consolidating two accounts (a rare occurrence). Multiple accounts are usually an artifact of not supporting multiple actors. However, if privacy or segmentation is a needed (suppose I would like to keep my personal data hidden from my colleagues) it becomes much more relevant. Unlike the other abstractions making this distinction is the responsibility of the user, not the application, so this is a niche feature. Websites like MyOpenID or Plaxo support contextual profiles ("personas" in MyOpenID), allowing you to use separate data in separate contexts. This masquerading ability is an important feature in the services they provide due to the sensitivity of the data, but would be useful in many other sites, especially social networks. Multiple accounts also facilitate shared accounts. A good example is twitter accounts for projects. These accounts don't represent a single human (usually the humans operating them have separate accounts), and the limitations are pretty painful:
Lightweight context switching would solve this. A single identity could be used to authenticate the user to the application, and access all the accounts the user should have access to. Accounts are closely related to actors. While accounts encapsulate the data belonging to user, actors define how a user interacts with other data. Tying it all togetherSo here is my "mega ultimate" model for user data. This is contained in a single transient (session bound) user agent object, with multiple delegates. These delegates are all broken out of the single user object. What remains of this object is a thin shell that unifies all of the delegates for a single user. This object represents the actual human, and all of the different objects they have access to. The user object is static, it serves as the hub through which all other objects are associated. The user agent object is dynamic, it defines what is known about a user for the duration of a session.
The object representing the user agent needs to pick the appropriate delegate for each operation, and in most cases there is one obvious delegate to use. Here is a diagram for the objects modeling an authenticated user:
The user agent object is responsible for picking the "active" instance of each of the multiple possible values. In this case the user has a single user account. This account has access to two different data contexts through two actors, Work and Personal. There are only two roles in this system, Unprivileged which doesn't require authentication, and Known User which is just a default role for authenticated users. The user has registered both a username an OpenID. The data in the dashed box has a lifetime of a single session, and represents the current set of behaviors the user is assuming, while the data on the right is persistent and represents anything the user can be. The user signed in using the username, and is currently operating in the Work context. The Work actor's assigned roles are currently active. Conversely, an unauthenticated user agent only has the guest role active, and makes no user data available:
A sign in action upgrades the guest user agent to an authenticated one by adding the auth token, which enables access to the full user data. All activity that is made possible by the Unprivileged role is available to both unauthenticated and authenticated users, but actions that require a signed in user must be performed through the Known User role. Here are some of the of the possibilities of this overengineering marvel:
These features aren't easy to implement with a single canonical user object whose ID is its primary key, and where all the data is stored as simple attributes of this objects. YAGNIForget the "ultimate" model. It's overkill. What's important is to merely understand the distinction between the different concepts. Most of the time you don't actually need to implement this distinction, a single user object will suffice. Just make sure you know when and where to break things down into smaller bits, and don't do things that will prevent you from refactoring this in the future. When you need to implement one of those tricky features, avoid ad-hoc workarounds. In the long run, without having clear separation of concepts you're likely to end up with denormalized user data and inconsistent behavior. Using duck typing (or roles or interfaces) you can simply treat your user object as an account/role/actor/identity object in the relevant parts of your code. As long as you keep the separation of the concepts clear in the usage, making the switch towards a separate first class object in the actual representation is a simple matter of refactoring. The tradeoff of creating more abstraction layers provides, as always, flexibility at the cost of complexity. Often times we resort to inferior workarounds because they seem simpler, when in truth they are just dumbing down the problem. KISS is not a synonym for "half assed". CatalystApart from a few nits these concepts map pretty well Catalyst applications, using the existing authentication framework. Using multiple distinct identities might require a bit of magic, as most user stores assume a user is an identity, instead of a user having multiple identity delegates. By default you can still have multiple identities per user, but the user to identity relationship is-a, instead of has-a. The object that ends up in $c->user must also be the object negotiating the authentication sequence. If you just treat each Catalyst level user object as an identity, and have the "real" user object become a delegate of that. The problem here is that of naming: $c->user->user can get pretty confusing when it really means $c->authenticated_identity->user. Alternatively, the realm object can traverse the identity objects, and work with the "central" user object directly. In this approach $c->user is the user agent object. A fully fledged user agent object would require custom work, as it must be tailored to your application's model of user data. Secondly, the RBAC plugin provides a controller level predicate check for roles. The roles I've been describing in this post are more involved. Each user has role instances that are actual objects in the model. The model is manipulated by calling methods on these objects. The low level operations are still implemented by the corresponding model objects, but the controller actions invoked by the user don't access them directly, they are proxied by the roles. Obviously the RBAC plugin can still check for the existence of these roles in order to generate simpler access violation errors earlier in the control flow, but it's no longer required to enforce the roles, enforcing is done using a safer capabilities inspired approach. Finally, actors and accounts are purely application specific abstractions. If required, they are your responsibility to implement in the model, not the responsibility of a plugin or framework. The EndI'd like to thank Chris Prather for his input and for inspiring this article in the first place by patientlty listening to my ranting as he was trying to rewrite the authentication subsystem of his IRC bots. |
| Posted on Tue, 16 Jun 2009 11:33:00 -0000 | permalink |
|
I tried a few times to learn CSS, but not really seriously, I guess, since I still know only the most basic things. So I am a bit lost now when I need a nice and universal CSS for FormHandler forms in Catalyst::Example::InstantCRUD. Or perhaps I should say HTML::FormHandler::Render::Simple forms instead of just FormHandler forms as theoretically the HTML rendering part is separated from the main FormHandler code, so that if this Simple renderer turns out really too simplistic I can also write a HTML::FormHandler::Render::NotSoSimple to get the right HTML. I started reviewing the options and it seems that there are three general approaches to having aligned forms:
Plus some appriopriate CSS. I think the 'no additional markup' option could never accommodate for error messages, so I leave this one out. This leaves me with three options. I am sure that not everything can be done in each one - but I think we can add a 'style' parameter to the renderer to make it configurable. Next thing is the recently popular CSS grids - anyone using them? They seem like a nice option for someone needing some universal defaults and the SenCSS example even contains a form styled in two ways (vertical and horizontal alignments) - but would it work with error messages? And the Blueprint one even shows a div with the error class - but how that is to be inserted into the form? I guess each one requires it's own way of HTML structuring. |
| Posted on Sun, 07 Jun 2009 19:09:00 -0000 | permalink |
|
A recurring subject on the Catalyst mailing list is about packaging functionality that is not entirely comprised in one of the Model View or Controller parts of the framework (and is not a full application on itself). This is hard and still there aren't many CPAN libraries that do that. One solution to that is writing "helpers" that generate the integration code into your application files. As with all code generation this solution creates many new problems - and ideally we would like to avoid it.
|
| Posted on Fri, 05 Jun 2009 17:00:00 -0000 | permalink |
|
Introduction This blog is a proposal and request for comments regarding adopting the XDG Filesystem Hierarchy as a option for managing all the non code data composing a Catalyst application. The Problem Right now when you create a new Catalyst ...
|
| Posted on Wed, 03 Jun 2009 16:47:48 -0000 | permalink |
|
Perl's reference counting memory management has some advantages, but it's easy to get cycle management subtly wrong, causing memory and resource leaks that are often hard to find. If you know you've got a leak and you've narrowed it down then Devel::Cycle can be used to make sense out of things, and Test::Memory::Cycle makes it very easy to integrate this into unit tests. Harder to find leaks are usually the result of combining large components together. Reading through thousands of lines of dumps is pretty impractical; even eating colored mushrooms isn't going to help you much. For instance, this is a classic way to accidentally leak the context object in Catalyst:
sub action : Local {
my ( $self, $c ) = @_;
my $object = $c->model("Thingies")->blah;
$c->stash->{foo} = sub {
$object->foo($c);
};
$c->forward("elsewhere");
}
That action will leak all the transient data created or loaded in every request. The cyclical structure is caused by $c being captured in a closure, that is indirectly referred to by $c itself. The fix is to call weaken($c) in the body of the action. This example is pretty obvious, but if the model was arguably cleaner and used ACCEPT_CONTEXT to parameterize on $c, the leak would be harder to spot. In order to find these trickier leaks there are a few modules on the CPAN that can be very helpful, if you know how and when to use them effectively. The first of these is Devel::Leak. The basic principle is very simple: it makes note of all the live SVs at a given point in your problem, you let some code run, and then when that code has finished you can ensure that the count is still the same. Devel::Leak is handy because it's fairly predictable and easy to use, so you can narrow down the source of the leak using a binary search quite easily. Unfortunately you can only narrow things down so far, especially if callbacks are involved. For instance the Catalyst example above would be hard to analyze since the data is probably required by the views. The smallest scope we can test is probably a single request. Devel::Gladiator can be used to write your own more detailed Devel::Leak workalike. It lets you enumerate all the live values at a given point in time. Just be aware that the data structures you use to track leaks will also be reported. Using Devel::Gladiator you can also find a list of suspicious objects and then analyze them with Devel::Cycle quite easily. Sometimes the data that is leaking is not the data responsible for the leak. If you need to find the structures which are pointing to a leaked value then Devel::FindRef can be very helpful. The hardest challenge is picking the right value to track, so that you can get a small enough report that you can make sense of it. Devel::Refcount and Devel::Peek can be used to check the reference count of values, but remember take into account all the references to a given value that are also in the stack. Just because the ref count is 2 for a value that's supposed to be referred to once does not mean that it's the root of a cyclical structure. A more managed approach is using instance tracking in your leaked classes, ensuring that construction and destruction are balanced on the dynamic scope. You can do this manually for more accurate results, or you can use something like Devel::Events::Objects. I personally dislike Devel::Leak::Object because you have no control over the scope of the leak checking, but if you're writing a script then it might work for you. Lastly, if you suspect you've found a leak then Data::Structure::Util is a rather blunt way of confirming that suspicion. |
| Posted on Mon, 25 May 2009 05:58:00 -0000 | permalink |
Are we going to need it?Odd flash of inspiration while washing up (yay for mindless activity) and also listening to a TED talk. I often grumble at Moose. Though not actually at Moose itself, just at seemingly everyone and everything jumping on the bandwagon. I also want to use Reaction, cos Matt wrote/writes it, and from the outside it feels like a great idea. But part of me doesn't think so. I think I know why now. Maybe I've been reading too many articles on Agile and so on. Specifically the principles of DoTheSimplestThingThatCouldPossiblyWork, and YouAintGonnaNeedIt. Reaction is a complex piece of software, built on top of two other pieces of complex software, Catalyst, and Moose. That's a whole stack of code. As people jokingly say "It installs half of CPAN". Don't get me wrong, software re-use is good and if I actually needed a piece of software that does all the many things that these three do, I'd use them. But I don't. Applications (and websites) don't often start complex, they gather complexity over time. For one or two web pages, maybe even ten, I can write them by hand. Ok so I probably copy the header and footer after a few. When I come to write the eleventh one, this becomes tedious. So instead I could use something like Template Toolkit's ttree, to produce a bunch of pages out of some templates. At some point I find myself needing something dynamic, or the concept of users, then I may go fetch Catalyst. And that's as far as I've got. Which step makes me need Reaction? The one where 90% of my website is interactive? I've not written too many of those, but the few I have, Catalyst has sufficed. You're probably thinking now, that I just don't write the same kind of applications/websites as others do. Thats possibly true. But again, Agile ways of doing things suggest we write the minimal amount of code we can get away with, to imlement the currently required features. That we don't plan ahead and add more code for potential features later, they will be re-thought anyway. That we release early, and often, and gather feedback for improvement, and then add new features. Not forgetting to refactor. To upgrade, to replace the entire framework if needed. To be practicalI think, what I'm looking for is, a guide for newcomers to explain and help ths progression. How to upgrade your site or code, from a few pages, to some dynamic bits, to a full blown interactive site. Or even not, not every site wants or needs to go that far. Not all code needs to be able to use email. There seem to exist many articles on how to write this complex code, but not enough that explain how to come to the conclusion that you need it. Maybe this is also why there are still many many more people writing about how to do CGI scripts in Perl, than how to use Moose. The transition is missing. (With thanks to Elizabeth Gilbert on nurturing creativity) Right, now I'm off to move the fledgling DBIx::Class website from some hand written pages to ttree. @public,programming,perl,thinking |
| Posted on Mon, 25 May 2009 00:22:35 -0000 | permalink |
|
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:
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:
Obviously you should also keep a set of identities in each user object. |
| Posted on Wed, 20 May 2009 06:44:00 -0000 | permalink |
|
One of the more entertaining part of working in e-commerce is dealing with PCI compliance. I say interesting because the standard is a mix of good things and inane things. Regardless, it’s required. One of the sections deals with authentication and authorization. We’ve traditionally done that sort of business internally, but the newest PCI standards gave us quite a few requirements that we didn’t feel like adding. Instead, we opted to offload that functionality onto our Windows machines. We already had some experience with this, as our internal Trac talks to Active Directory to ease our administration when interfacing with the other departments. Enough backstory. I had some hassle getting Catalyst::Authentication::Store::LDAP working with Active Directory. I wanted both authentication and roles, so here’s what I ended up with:
Plugin::Authentication:
default_realm: members
realms:
members:
credential:
class: Password
password_field: password
password_type: self_check
store:
class: LDAP
ldap_server: dc1:389
ldap_server_options:
timeout: 30
binddn: cn=SomeAccountYouSetup,ou=Accounts,dc=domain,dc=com
bindpw: password
user_basedn: ou=Accounts,dc=domain,dc=com
user_filter: (userPrincipalName=%s)
user_field: mail
use_roles: 1
role_basedn: ou=Groups,dc=domain,dc=com
role_filter: (member=%s)
role_scope: sub
role_field: name
role_value: dn
role_search_as_user: 0
role_search_options:
deref: always
I’m not really participating in Matt’s Iron Man but the flurry of Perl posting does leave me feeling a bit guilty for not saying a bit more about my language of choice. UPDATE: I’ve changed the configuration a bit to show what you need to change. |
| Posted on Fri, 15 May 2009 00:09:43 -0000 | permalink |
Software DIYAt work, we have a bunch of in-house written, from-scratch (more or less), software. As we're a software house, this isn't terribly surprising, you might think. However the software I'm talking about isn't the stuff we sell. It's the basic code that holds up the website. There's an entire self-written CMS, forms system, publishing system and a host of other things. Most of this stuff evolved, from simple CGI scripts written years ago, relying on text files and databases and so on. Some of those .cgi scripts even still exist in remote corners. Larger and frequently used systems have been refactored into more hands-off tools, optimised for minimal maintenance. Smaller systems languish, seemingly not enough used to refactor and improve. And yet they waste the time of us workers, more than we'd like. Managements idea is to replace everything with some off-the-shelf pre-written software, and all will be good. This is of course somewhat of a pipe-dream, one which the people actually running that project are quite aware of. It will need customising, of course. So there's two extremes: Software we've written from scratch, and software we just install, or pay for hosted. Where is the in-between layer? I'm thinking what we need more of is mostly-done solutions, components. Things like Catalyst plugins and similar come close, but even those are often self-contained. How do I integrate, for example, MojoMojo (wiki) and Angerwhale (blog) so that both use the same user source? Ok, those are both classed as complete applications, but that's my problem. I want them as parts of a whole. Anyway, all this rambling, what I actually want to get started on is: We have a system for writing forms, another one that builds a calendar of events, and a third that stores training courses and their dates/prices. None of these integrate with the other, and they're all updated by hand, that is, by programmers, not by people running the events/trainings. After stumbling around the internet for a while looking for a plausible off-the-shelf solution, I decided to just write one (this is how frustrating finding software has become..) I did find a couple of not too terrible sounding ones, but they appear to be all hosted. For eg: Tendenci, which is actually part of a CMS. So far I've managed to write a simple (i.e. not terribly normalised, but sufficient to reproduce existing systems) DB schema, and a somewhat bare Catalyst app. Now I need to make an admin interface/controller, and one to actually display the events list and the sign-up forms. @public,perl,ironman |
| Posted on Wed, 13 May 2009 17:10:23 -0000 | permalink |
|
Using KiokuDB with Catalyst is very easy. This article sums up a few lessons learned from the last several apps we've developed at my workplace, and introduces the modules we refactored out of them. Let's write an app is called Kitten::Friend, in which kittens partake in a social network and upload pictures of vases they've broken. We generally follow these rules for organizing our code:
Anything that is not dependent on the Catalyst environment (as much code as possible) is kept separate from it. This means that we can use our KiokuDB model with all the convenience methods for unit testing or scripts, without configuring the Catalyst specific bits. Functionality relating to how the app actually behaves is put in the Schema namespace. We try to keep this code quite pure. Glue code and helper methods go in the Model namespace. This separation helps us to refactor and adapt the code quite easily. So let's start with the schema objects. Let's say we have two classes. The first is Kitten::Friend::Schema::Kitten:
I've used the KiokuX::User role to provide the Kitten object with some standard attributes for user objects. This will be used later to provide authentication support. The second class is Kitten::Friend::Schema::Vase:
Now let's write a unit test:
This test obviously runs completely independently of either Catalyst or KiokuDB. The next step is to set up the model. We use KiokuX::Model as our model base class. The model class usually contains helper methods, like txn_do call wrappers and various other storage oriented tasks we want to abstract away. This way the web app code and scripts get a simpler API that takes care of as many persistence details as possible.
We can write a t/model.t to try this out:
Next up is gluing this into the Catalyst app itself. I'm assuming you generated the app structure with catalyst.pl Kitten::Friend::Web. Create Kitten::Friend::Web::Model::KiokuDB as a subclass of Catalyst::Model::KiokuDB:
And then configure a DSN in your Web.pm or configuration file:
>Model KiokuDB<
dsn dbi:SQLite:dbname=root/db
>/Model<
That's all that's necessary to glue our Catalyst independent model code into the web app part. Your model methods can be called as:
In the future I might consider adding an AUTOLOAD method, but you can also just extend the model attribute of Catalyst::Model::KiokuDB to provide more delegations (currently it only delegates KiokuDB::Role::API). If you'd like to use Catalyst::Plugin::Authentication, configure it as follows:
And then you can let your kittens log in to the website:
Some bonus features of the Catalyst model:
|
| Posted on Wed, 06 May 2009 14:30:00 -0000 | permalink |
|
NB: This is my first post in the EPO Iron Man challenge. (Warning: contains some expletives) First and foremost, the long awaited Catalyst 5.8 is out! My mind-share has primarily been with the 5.7x series so I've been pretty much out of the loop ...
|
| Posted on Wed, 22 Apr 2009 18:04:14 -0000 | permalink |
This is a more concrete version of the question from my last post. This is a form defined in FormHandler:This should be quite self-explanatory for anyone working with forms (and DBIC). Now - I think Model::DBIC should be just a role here, but that is just a side track. The real question is about the fields here - ideally I would want that doing: (this is after it is made a Role) - would add appriopriate methods to the fields - an example here could be validation of fields that need a unique value. I would like to not need to change the definitions above to: Fields like 'owner' above which are Compound fields and work mostly like a form itself and need to load the options for SELECT boxes from the model, set the values of fields from a database row etc: Ideally this definition should not need 'HTML::FormHandler::Model::DBIC' - applying this role to the root form should be enough. |
| Posted on Sat, 04 Apr 2009 09:14:00 -0000 | permalink |
|
Let's say you have a tree like data structure, something not exactly so uniform as a tree but with enough uniformity that it makes sense that large part of the code is recursive. My example is something representing an HTML Form for editing a complex data structure (with sub-forms etc.). The main form code is used for inflating external data represetntation (key, value pairs) into internal objects and validating it. But there are two additional 'aspects' of this form processing - this is generating the HTML of the form (with all the error indicators and messages) and saving the form data into the data store (by manipulating DBIx::Class schema for example). So you have a tree-like data structure and three separate functionality areas related to it. How do you structure the code?
|
| Posted on Tue, 31 Mar 2009 07:12:00 -0000 | permalink |
Auto-listing inherited methods in PODYou write a module, or a whole suite of modules, and (hopefully) nicely document all the methods in the classes next to the code. Great! Only now the problem is that the module suite is using some best practices, and builds re-usable base classes on top of re-usable base classes, until the actual user-usable classes are just icing-on-the-cake layers on top. Now your users have to figure out which methods on their resulting objects come from which of your base-base classes, and dive into various different pieces of documentation to piece together the methods they can call. No longer! Having been annoyed enough by this sort of POD wrangling already, theorbtwo came up with Pod::Inherit to help the module writers improve their documentation. Run it with the name of a class or the lib directory for your distribution, every class is investigated to determine which methods it contains, the inheritance tree is then searched to determine which base class actually defines that method. After the collection is complete, the POD from the original file is written to a new file with the extension ".pod" and adds a "INHERITED METHODS" section at the bottom (after all other sections, before any section named LICENSE, AUTHORS and so on. The INHERITED METHODS section consists of a list of classes the current class inherits from, with a link to that class. It then lists the names of the inherited methods. This will also include methods that are outside the current distribution tree, for example if the module inherits from Class::Accessor::Grouped, then "mkgroupaccessors" will be listed. So, having waffled a lot, here's what the output looks like when we run it over DBIx::Class: Apache::Pod, proper linkingAs an extra, I got annoyed enough at Apache::Pod for always linking to search.cpan.org when displaying links in my local documentation, that we came up with a way to have it figure out whether the link was in the local tree of files, and link there, or whether it was a true external link. Unfortunately in singleton mode (i.e. just parsing a single file, as it is when installed as an Apache PerlHandler), it can only guess by recursing up the file tree until it finds a directory that doesn't look like a class name. Unpretty, but works if you make the dirs all lower-case (yes, pragmas don't count). In batch mode however, it does have a good clue what its working on, so there it knows exactly what it can link, and what not. So having fixed that, we can run it over the DBIx::Class pod-inherited docs, and get sane linking too! DBIx::Class pod, inherited and linked sanely How's that for annoyed programmers? @public,perl,pod,dbix-class,dbic |
| Posted on Mon, 30 Mar 2009 20:49:44 -0000 | permalink |
|
The other day, someone emailed me about Ernst. I thought I marked the email as "reply to soon", but I actually deleted it. Oops. Anyway, if you are that person, please get in contact with me again, I'm really sorry for deleting your email. With that in mind, I thought I'd write a little about my plans for the
future with respect to Ernst. Basically, the current version is a
prototype that I wrote to see what metadescription systems are all
about. I liked the concept initially, and now that I've implemented
it, I like it even more. The implementation, however, does have some
problems. The biggest is that you have to Anyway, Moose has "metaroles" now, and using that feature will result in a cleaner implementation. The first step for a "real" Ernst will be to fix that problem. A Simple Matter Of Programming :) With a solid implementation of the internals, a new set of problems comes up: Should there be separate classes that exist solely to describe a class? It is a pain to have HTML snippets inline with your class attributes, after all -- but it is also messy to sequester them off somewhere that would require a config file to load properly. The idea is to describe attributes and classes, and the class is the best place to do that, but sometimes the descriptions are too verbose. What should we do about this? Should we use Moose's type constraint system? As I was implementing the first version, I was tempted to implement my own types. Moose's types were too inflexible at the time, I thought; I wanted types that could be incrementally validated, and that understood that they would both keep my program consistent ("HashRef[Str]") and be used to tell a user that his data was not valid. (A password type would be a String, of course, but it also had other restrictions like "Your password should be at least 8 characters long." and "Your password should contain at least 42 numbers." When generating a UI, you want to present all errors at once and a single Perl code block just isn't enough to do that; we need real introspection.) Anyway, this is another problem that Moose is solving; type constraints have received a lot of love lately, and I think we can do everything we need there. What should an "Interpreter" do? Right now, it is a class that has an "interpret" method. I think this is too flexible, as it doesn't really abstract anything away. You might as well just call it a function. We need to decide what interpreters should do, and then determine what the common API should look like. (There are interpreters in the Ernst distribution now, but I really wasn't sure what the API would look like when I was writing them. I just made them work.) Basically, if you have thoughts, let's discuss them on Speaking of the future, my "main project" right now is rewriting Angerwhale. Angerwhale started out as my first "real" Perl and Catalyst project, and grew to actually have some users. Looking back, I really should have discouraged people from using it -- too many ideas were experimental and turned out to not work in real life. (Do you really like PGP-signing your comments? It seems not; I only know of three people who post here that sign their comments. Everyone else stays anonymous. This leads me to believe that PGP-only authentication is a bad idea.) Anyway, the idea for Angerwhale-ng (or Angerwhale 2, even though there never was an Angerwhale 1), is to not be experimental anymore. I really want to create a real blogging platform, and replace Wordpress and MT throughout the Internet. Those platforms are too hard to extend, are messy internally (and extensions are messier), try too hard to be generic CMSes, and don't even have good support for writing about programming. (Nearly every Wordpress blog I see turns quotation marks inside code snippets into smart-quotes. WTF?) It's time to put a stop to that insanity and do blogging right. So, my high-level goal is to create a platform that is cleanly extensible in ways that I don't foresee. Angerwhale 1 tried to do this (and was pretty successful), but too many things required knowledge of the internals. I am aiming for something more transparent and flexible. Emacs is a great example of this. Nobody ever intended for Emacs to be an IRC client or mail reader. But thanks to the flexibility, those features arose naturally. Someone wanted them, and the tools to build them were already there. So they built them, and now everyone can have them. That is how I want Angerwhale to work. The biggest factor contributing to the extensibility will be KiokuDB. There will be no database schema; everything will be a Moose object in the database. That means that an extension that wants to hook something can be a role applied to an instance. (Just like you were extending a Moose class in memory.) Users may not have an "openid" field by default, but you can apply a role and then they will. (But actually, this specific case is better handled by delegation. Although I want things to be easy to extend without me providing explicit extension points, I will try to provide as many explicit extension points as possible. The goal is to be easily extensible AND to have very clean internals.) Since there is no database schema to mess around with, flexibility is easy. The app doesn't know or care about your extensions; they Just Work. (KiokuDB also helps in other areas -- performance will be a lot better than my ad-hoc file + attributes system that Angerwhale 1 uses. KiokuDB is really fast, and scales well too.) (One feature that doesn't fit into my narrative is that Angerwhale
will be a blogging platform -- one instance will be able to host many
blogs. That means that we can make better use of memory; one blog may
take 300M of RAM, but 1000 blogs will only take 305M. This means that
Angerwhale will be good for hosting individual blogs like this one,
but also good for hosting community sites like Planet Perl and use.perl. I
do intend to provide a public blogging service for Perl bloggers as my
first deployment, and hopefully replace The next part of Angerwhale will be a new web framework. It won't be like the other new web frameworks, though; the goal is to unify all the Perl web frameworks and provide a true framework framework for everyone to build on. (The goal of the other "new" web frameworks, it seems, is to provide fewer features under the guise of "simplicity". Forcing users to reinvent the wheel is not simplicity, though, and I think this idea sucks. Perl is about TMTOWTDI, not being told that your way is wrong and that you should go fuck yourself if you don't like my way.) The framework will consist of 4 completely separate parts. The first
is the "app engine", to support things that concern the entire
application. It knows nothing about the web, and doesn't care. (So
you can use it in non-web daemons too.) It will provide features like
timed events ("clean my sessions table every hour"), an event loop (so
that you can fork, fetch web pages, or access your database without
blocking other requests), logging, and debugging tools (you can embed
a It will be The next part is the HTTP helper,
The idea is that it will handle everything that is specific to the
web, but not specific to your application. (If you haven't tried
The third part of the framework is a component loader. Current web
frameworks tend to load components "automatically", but this is not
always the most desirable approach. Something like At this point, you have a solid foundation for building a long-running Perl application, you have a generic way of interacting with the web (complete with niceties like middleware), and you have a solid way of loading and configuring the application's components. That leads us to the last layer, the actual framework. Basically, you can do what ever you want here. I am planning on making it possible to use existing Catalyst controllers in the application, and to support Continuity. (I have use cases where I want both styles in my app -- Catalyst-style actions for the public part, and Continuity actions in the administrative area.) Stevan Little is currently working on a framework that is document-based; you make objects that know how to be mutated and how to render themselves, and the framework takes care of the rest. This will integrate cleanly with this framework, of course. If you really don't like framework-y stuff, just use So that's basically it -- the future of Perl web frameworks is unification. Users shouldn't have to commit to one way of thinking -- everything should work together. That is my goal. It's important to say that this isn't just pie on the sky -- I am actively working on these projects (and not by myself, this is a community project). I will be talking about this stuff more throughout the year. First at NPW, and at YAPC::NA, YAPC::EU, and YAPC::Asia. Hopefully by YAPC::EU and YAPC::Asia, this will be code you can use in your own applications! Anyway, ping me on irc and let's chat! |
| Posted on Wed, 04 Mar 2009 14:35:26 -0000 | permalink |
|
Like i said back in July, Catalyst 5.71000 would happen before the moose-ified 5.80 gets shipped. That day is here. Here's the basics on what's new since 5.7015: Relatively chained actions PathPrefix (I only mentioned that, oh, 2 years ag...
|
| Posted on Mon, 19 Jan 2009 21:04:02 -0000 | permalink |
|
A number of people I know through the Perl community have come together to form The Enlightened Perl Organization (EPO). The goal is to modernize Perl 5 and make it competitive with new developments in programming languages, given that it's unknown when Christmas (the delivery date for Perl 6) will arrive. My take on this is that while other organizations focus on ongoing development of Perl 6, EPO will seek to enhance Perl 5 and take it out of "maintenance mode." Enhancing Perl 5 will hopefully bring much needed modernization to the Perl 5 core that people can use sooner rather than later. One of the most exciting developments in the Perl community, which addresses some of the core criticism of Perl 5, is Moose, an object system that modernizes Perl 5. Unlike previous efforts efforts to enhance Perl 5's object system, this one seems to have gained a lot of traction with 136 current logins on the #moose IRC channel. Moose is different enough that some have even claimed that it is not Perl; however, this is clearly not the case as Moose and non-Moose objects and be freely intermingled within Perl projects. For some information Moose, check out this article by Jon Rockway. In addition to Moose, check out KiokuDB an interface for schema-less databases like Amazon SimpleDB and CouchDB as well as more traditional DBI for RDBMs. In addition to supporting projects, ideally Perl 5's core module list can be modernized so more people will be able to take advantage of and feel comfortable recommending modern approaches to Perl development. At the same time, I'd also like to see them tackle a few more persistent issues, the most important of which is CPAN usability. There is no doubt the Perl community and the CPAN are very compelling; however, installing CPAN dependencies is more difficult than it needs to be. Installation often requires many interactive prompts and can take a long time for applications with many dependencies. There are typically no 5 minute installs like exist for WordPress, PHPbb, and MediaWiki. Some exceptions include qpsmtpd and Catalyst using Matt Trout's cat-install script. I welcome EPO as another organization in the Perl community to keep Perl modern and vibrant. |
| Posted on Wed, 14 Jan 2009 01:21:00 -0600 | permalink |
|
I work for magazines.com and we are looking to add to our team! We’re a Perl shop, located in Franklin, Tennessee. We sell magazine subscriptions online. This year we’ve got a lot to do and I’m looking to add some developers to our ranks. I’m not sure how many yet, but I can give the following details:
We aren’t looking for a particular job level. I’m interested in juniors to seniors. The candidates we choose will depend on the choices we have. If you are interested then drop an email to me via cwatson at magazines dot com. I’m really excited about our work in 2009. I’m opening the year with two talks at the Orlando Perl Workshop and a commitment to work with the Enlightened Perl Organisation. I’ll eventually post this opportunity on jobs.perl.org but wanted to start here. Give me a shout! |
| Posted on Wed, 24 Dec 2008 02:32:42 -0000 | permalink |
|
I recently rejoined my team at magazines.com and have been pretty busy getting back into the groove there. It’s a busy place in Q4, so side stuff has taken a back seat. Well, that’s mostly WoW’s fault. While I’m at it, if you are a LAMP System Administrator in Nashville (or nearby) and are looking for a great opportunity, drop an email to cwatson at magazines dot com! On a side note, my first entry of the 2008 Catalyst Advent Calendar went up today. Enjoy! |
| Posted on Thu, 04 Dec 2008 00:14:20 -0000 | permalink |
|
I will be giving a talk titled Catalyst & Chained: Bondage for better applications at the Orlando Perl Oasis. Abstract: Need to build a web application and keep hearing about methods you aren't quite sure of? Know Catalyst but don't feel you rea...
|
| Posted on Wed, 26 Nov 2008 20:24:24 -0000 | permalink |
|
Code generation is hard. First of all it is hard to determine what really needs to be created - in (computing science) theory you can always uncurry the generator and use it as a library. So you need different theory to really determine if code generation makes sense at all. In practice many people use it - since it let's us start new projects faster (and more correctly). This is an interesting subject deserving many more blog posts - but for now I just wanted to toss the idea that joining forces with other Perl projects facing this problem could help us improve the mess that is Catalyst helpers now. I've learned about Module::Starter plugins from Recursive development that leads nowhere. |
| Posted on Thu, 23 Oct 2008 09:29:00 -0000 | permalink |
| Now that I use CGI::Application, Class::DBI and HTML::Template at work I can see the advantages of using Catalyst, DBIx::Class and Template Tookit. Personally, I find using HTML::Template as the most annoying of those three set backs - with TT I've got used that I don't need to worry about displaying the data I feed to the template, I need to make sure that it contains everything needed but that's all. I know that the view can take any data and display it. This makes a nice separation of work and of mind sets between the Controller and the View. Not so with HTML::Template. |
| Posted on Thu, 16 Oct 2008 09:45:00 -0000 | permalink |
|
I generally avoid blog posts that are less than a million words, but today you are in luck; I am just going to share two shell aliases that I find quite helpful for Catalyst development: alias cs="perl script/*_server.pl -d" alias carpcs="perl -MCarp::Always script/*_server.pl -d"
Maybe a little hackish, but very helpful. I use |
| Posted on Sun, 28 Sep 2008 17:05:52 -0000 | permalink |
|
Continuing the move of internal server stuffs to external hosts, the Mango domain is now hosted on DreamHost. I looked into DreamHost, BlueHost and HostGator. Linnode, etc. They all have their pros and cons. For me, I couldn’t ignore the $50 off for DreamHost. That means I’m paying $60 a year to host most of my stuff. That will pay for itself the first month I downgrade my DSL service. In the end, the mission critical bits are on GitHub in the event that DreamHost has another round of outages. |
| Posted on Wed, 17 Sep 2008 01:22:03 -0000 | permalink |
|
I’m slowly trying to move things off of my home computers and on to servers in the outside world, preferably servers that someone else has to backup and maintain. As such, the Handel source has moved to using GitHub. It’s git. It’s free. And it’s backed up. http://github.com/claco/handel/ The old repository is still available for now. I’ll try and keep it up to date, but the sooner you move to using GitHub, the better. |
| Posted on Mon, 08 Sep 2008 21:36:32 -0000 | permalink |
|
It’s been on the CPAN for a few weeks, but I’ve not taken the time to pontificate about what exactly Graphics::Primitive and its cadre of helpers are. BackstoryI started working on Chart::Clicker quite a while back. I’d just come from a job as a senior Java developer and still had AWT and Swing on the brain. I’d developed a custom charting package in perl a few months before but wasn’t happy with the results. I sought out a solid charting package to emulate and was heavily inspired by JFreeChart. One of the side effects of this was my disappointment with the availability of general graphics packages on the CPAN. I was jealous of the simple classes in Java that reduced a lot of the work in making graphics: Point, Rectangle, Color and more. I released Chart::Clicker and was happy. I had emulated a lot of the ideas inside Clicker, writing general Component, Font, Color and Border classes, to name a few. As time went by and people began using Clicker it because clear to me that these concepts could be generalized and turned into a general framework for creating graphics. Thus became Graphics::Primitive. Enter Graphics::PrimitiveGraphics::Primitive is a collection of objects that allow you build a 2d “scene”. The building block of these scenes is a Component. It has a width and height, colors (fore and back), borders, insets and padding. A Container builds on Component and yields a component that can contain other components. To allow for more than plain ol’ boxes Graphics::Primitive provides TextBox, Canvas and Image. While these entities are all pretty simple, but you can create complex results by nesting them. Creating OutputGraphics::Primitive is really just a data structure. It doesn’t actually do any drawing. Drawing is done by Drivers. The only driver at present is Cairo. It makes a great first driver, however, as it provides PDF, PostScript, PNG and SVG output. LayoutGraphics::Primitive also doesn’t concern itself with laying out your components. Graphics::Primitive will leave components wherever you put them if left to its own devices. To handle automatic layout management I created Layout::Manager. As you add components to a container you can provide constraints for them. Then you can ask an instance of Layout::Manager to “layout” your container (and any containers contained in it). This concept is borrowed from Java’s layout managers. It is worth noting that each container has it’s own Layout::Manager so you can choose the one that is most fitting for the look you desire. BenefitsGraphics::Primitive allows you to separate your data from your presentation. Creating an artifact in Graphics::Primitive allows you to change the output format. Need a PDF and a PNG? There’s no reason to rely on a conversion tool or a separate rendering path. Simply clone the component to pass it to each driver. What Can You Do With it?The aforementioned Chart::Clicker is made using Graphics::Primitive. You can look over examples of its output. The examples are all pngs but any of those can be converted to any of the formats supported by the Cairo driver by changing a single parameter. There is a Catalyst view, which I released onto CPAN today. This allows you to serve your components via HTTP. Document::Writer aims to abstract the underlying Graphics::Primitive components into an API friendly to creating documents. It will likely change quite a bit as I refine the ideas and increase underlying features. Supporting CastI created a handful of other modules in an effort to reduce the work others might do when building similar code. Graphics::Color provides simple objects for various color spaces. I’ve got a list of color spaces to add, as well as conversion routines. Geometry::Primitive provides simple geometry entities such as Point, Circle and Rectangle. These objects serve as the base for Graphics::Primitive. Future PlansI’m currently sitting on code that allows serialization of a Graphic::Primitive scene using MooseX::Storage, but some API conflicts are stopping me from releasing until I work them out. Document::Writer will be getting lots of new features as I back out a lot of my crappy text code for a more robust text-layout engine based on Pango. There are supposedly bindings coming for perl that are not tied to GTK+. ConclusionGraphics::Primitive has been a lot of fun. If I’d known what I was getting into I probably would’ve run away screaming. There have been many nights that I couldn’t sleep because a problem was rolling around my brain and I had to get up and hack on it for a few hours. Please check it out and feel free to hit me up with ideas and suggestions. I’ll be giving a talk, hopefully, at PPW 2008. The presentation itself is made in Graphics::Primitive, just for extra oomph. |
| Posted on Thu, 04 Sep 2008 22:33:22 -0000 | permalink |
| Looks like one of the anomalies I described in my previous post is fixed now in the svn (see Revision 4773 of DBIC). Thumbs up! |
| Posted on Thu, 28 Aug 2008 21:52:00 -0000 | permalink |

English
FOAF