[Catalyst] Re: CatalystSites.org

Aristotle Pagaltzis pagaltzis at gmx.de
Wed Apr 16 12:19:12 BST 2008


* Chisel Wright <chisel at herlpacker.co.uk> [2008-04-16 11:50]:
> Just for chuckles - does anyone have an idea of the pain-level
> involved in converting a non-Chained application to Chained?
> 
> Or is it just not worth the effort for an established project?

Totally depends. I ported an app to Catalyst that previously was
basically one-action-per-controller. It cannot be called anything
less than a lot of work, but it paid of royally. The code is as
DRY as it was before, but it’s now far better structured.
Previously it was blocks of if-elsif chains grouping together
execution steps that are shared by some URIs but not others – now
it’s Chained. A typical controller looks something like this:

    sub base : Chained PathPart('doc') CaptureArgs(0) { ... }
    sub list : Chained('base') PathPart('') Args(0) { ... }
    sub item : Chained('base') PathPart('') CaptureArgs(1) { ... }
    sub view : Chained('item') PathPart('') Args(0) { ... }
    sub edit : Chained('item') Args(0) { ... }

This gives `/doc` (goes `base` then `list`), `/doc/*` (goes
`base` then `item` then `view`), and `/doc/*/edit` (goes `base`
then `item` then `edit`).

And then you can put stuff shared by all actions in `base`[^1],
and stuff shared by all actions that relate to a single document
(eg. stuffing that document into the stash) all in `item`.

By liberal use of `PathPart('') CaptureArgs(0)` you can force any
URI to step down any number of intermediate steps you require, so
you can use that to group together shared code any way you see
fit:

    sub foo : Chained CaptureArgs(0) {}
    sub bar : Chained('foo') PathPart('') CaptureArgs(0) {}
    sub baz : Chained('bar') PathPart('') CaptureArgs(0) {}
    sub qux : Chained('baz') Args(0) {}

This will dispatch `/foo/qux` across the entire foo bar baz qux
chain. Now consider:

    sub quux : Chained('bar') Args(0) {}

This will produce anoter end point, this one at `/foo/quux`, but
it will dispatch only across foo bar quux.

Chained lets you build trees of actions where each leaf is a URI,
and by using `PathPart('') CaptureArgs(0)` you can insert any
number of non-leaf nodes into it. Catalyst will just DTRT. So you
can use Chained dispatch just like other Perl-level flow control
mechanisms and code scoping.

What does all this have to do with your question?

Well, if you don’t specifically exploit this benefit of Chained,
and merely do most of the work at the endpoints of your chains,
then you don’t really gain much from switching. It is only worth
the bother (but then is *well* worth the bother) if you are
willing to restructure your code to benefit from Chained (not
necessarily immediately, mind – maybe as an ongoing refactor).
The feasibility and cost of that undertaking, however, depends
on your codebase and circumstances.

In my case, the code structure already quite naturally fit into
Chained, so porting about 1,500 LoC of controllers from the
ad-hoc style I describe above to Catalyst with Chained took
roughly a week, maybe even a little less, and was by far the
easiest part of the port.

How painful it will be in your case depends on how clean your
codebase is. If your controllers are thin, as they should be, and
you don’t have terrible spaghetti, it shouldn’t be too painful.
What’s more, since you are already writing for Catalyst, you
don’t have to get into a boil-the-ocean effort like mine was[^2]
(due to the fact that I was porting a non-Catalyst app).


[^1]: Usually nothing, but it’s convenient to have a single pivot
      point you for moving the entire enchilada to a different
      part of your URI space.

[^2]: Still is, actually. 2.5 months and not yet done, though I
      am finally close.

Regards,
-- 
Aristotle Pagaltzis // <http://plasmasturm.org/>



More information about the Catalyst mailing list