Why I would not pick CGI::Prototype again

Aristotle on 2007-10-14T13:20:25

I started with CGI::Prototype on a project I still develop. I loved it at the time, but I have been looking to move away from it for a while. Back then it was the right choice: Catalyst wasn’t very well known nor very good yet, Jifty didn’t even exist, and even CGI::Application didn’t have ::Dispatch.

But CGIP just does too little and what it does do is mostly useless. Overall, it is is very stargate oriented.

  • Its core idea is the “stay on this page or go to another?” mechanism. This is directly in opposition to POST-redirect-GET – and therefore to good HTTP style. I didn’t have to fight CGIP to do things properly, but I had to ignore its offerings and manually devise everything I needed.

  • It is strongly targetted at classic process-per-request CGI environments. It tries to avoid compiling too much by implicitly require-ing subclasses in the dispatcher, and stores request-specific data in slots of the main object, which are effectively global variables.

  • Because the dispatcher plays double duty as an on-demand code loader, it’s hard to make it do URI-based dispatching sensibly. I’ve had to reinvent lots of the dispatching infrastructure that any more comprehensive framework would have given me for free, and my code is still less flexible than the routing provided by every other framework.

  • It treats the output – both the response headers and the body – as a single thing. That means you have to generate all output at once, or else you have to reinvent the mechanisms other frameworks provide to independently set headers and produce the response body – and indeed I ended up doing the latter.

  • It does nothing to help you decouple concerns. Normally, no variables are passed to your templates except self, whereby your templates call back into the application. This turned out to be a very bad idea. What should have been there is a mechanism like the stash in Catalyst, which lets you prepare data piecemeal in the controller, which is finally passed to the template. This too – you guessed it – I had to write myself.

Overall, between ignoring its suggested ways of doing things, overriding its defaults, and writing infrastructure myself, I basically wrote my own web framework on top of the tiniest bits of CGIP.


Valid concerns

merlyn on 2007-10-14T14:10:20

CGIP is deliberately very thin. It is a framework which abstracts away the most boring parts of every web app I've ever written. It's true that if CGIP::Hidden doesn't do what you want, you're left with only the thin framework above it. One of my long-term todo tasks was to make that a bit more pluggable, to handle the style that better suits REST-ful APIs in addition to hidden-field state passing, but none of my clients had that as a problem, so I didn't add it yet. :)

Your comment about data-push vs callback is a bit misplaced though. Certainly, prototype-based programming supports both manners, and my clients have used both, sometimes together. The rendering phase should generally not change the state of the app, but could use either data added during render_enter or computed during render itself via callback. Template Toolkit makes both accesses with the same syntax, so you can even move from one to the other. Maybe you missed that because there was no examples of computing and preloading during render_enter in the sparse documentation. I do have examples of that in my presentations.

It's a different way, not a wrong way :)

brian_d_foy on 2007-10-14T16:42:53

You don't have to like CGIP, and that's fine. This sounds like it might be in response to my last journal post. I wasn't trying to push CGIP on anyone, and really did mean it when I said that anyone who tells you what to use before they know your problem isn't worth listening to. I've recommended Catalyst to plenty of our clients, and usually do so first, saying "If this doesn't work for you, then we'll talk about CGIP". It certainly isn't something I recommend people start with if something else works better for them.

You like URI based dispatching, but I hate that. Even then, it's not hard to do in CGIP. It's not like URIs are magic. Once the application gets control, they are just input data like anything else. CGIP gets rid of the idea of run states and lets you switch courses at several points. You're decoupled from the starting point.

I'm not sure what you mean about the poor separation of concerns. In CGIP you can build up the data anyway that you like as you go along. The View gets access to it all and can display it anyway that you like, including hooking back into the Model directly. It's very decoupled. Although CGIP uses Template by default, one of our clients replaced that with XML/XSLT without too much pain.

It sounds like you don't like that you had to make the decisions and do the work to make CGIP do exactly what you wanted. That is, however, the entire point. You might not *like* it, but don't confuse that with valid technical arguments. :)

Re:It's a different way, not a wrong way :)

Aristotle on 2007-10-14T23:10:44

It started as a reply to your post, yes. Then I realised it was beside the issue. Anyway, it is why I wouldn’t pick CGIP again.

It’s not like URIs are magic.

They’re not, but CGIP scatters the responsibility for dispatch across all of your classes by way of the respond method, and it will not invoke a method other than respond in the course of dispatch, nor does it provide a built-in mechanism of passing parameters to it. So you have to rig up the entire machinery to parse the URI and route to the right method invoked with the right parameters, and integrate it with CGIP’s dispatch API.

You can do URI-based dispatch in CGIP in spite of CGIP.

It sounds like you don’t like that you had to make the decisions and do the work to make CGIP do exactly what you wanted.

Catalyst makes me take a lot of decisions. If that was what I had to do, I would like CGIP. But I didn’t make CGIP do what I want. I wrote everything of interest myself. The presence of CGIP was almost incidental.

In the end I inlined CGIP and trimmed it to the bits I actually used, discarding over ¾ of it in the process. Essentially, I now have an ad hoc, informally-specified, rigid implementation of half of Catalyst, to borrow Greenspun’s turn of phrase.

I’d like a framework that provides infrastructure so I don’t have to.

Re:It's a different way, not a wrong way :)

brian_d_foy on 2007-10-14T23:19:35

I'm not sure what you were doing with CGIP and URL dispatch, but I never had to scatter them across anything. It sounds like you were doing something the hard way.