Hi Hans,
On 2009/09/30, at 21:25, Hans Dieter Pearcey wrote:
> Excerpts from Pedro Melo's message of Wed Sep 30 15:42:51 -0400 2009:
>>> I'm sure Dave would say, "why don't you just use Catalyst with
>>> Mason"? But I expect you have a reason, given that you are obviously
>>> aware of Catalyst. :)
>>
>> Its a good question, but I did my homework on this one :). Basically
>> Catalyst doesn't add any value to this site:
>>
>> * I don't need multiple views per controller, only straight HTML;
>> * all my Model's are alteady abstracted away;
>
> These are strange things to give as reasons to not use Catalyst.
> Both View and
> Model in Catalyst are pretty thin -- most of the Views are a tiny
> wrapper
> around a templating engine, and most of the Models are a tiny
> wrapper around
> some external class.
The second reason was more of a explanation that I can move from one
to the other easily because all my "models" (aka business logic) is
already on a set of Moose objects totally outside Cat.
The first reason is actually a good reason. If I needed to generate
both a site and a RESTy API, Catalyst would be much better because I
can reuse all the dispatching logic, all the controller logic, and
just use a different view for each one.
In my case I don't need that, so I don't need the flexibility of
multiple Views that you get from Cat.
> Not using Catalyst because you didn't need those misses
> the point -- it's like saying "I didn't use Perl because I don't
> need to
> emulate awk's line-splitting behavior."
I don't think it does. Cat is more complex than Mason. To add a new
page, I need to tweak a controller, and then create the template file.
I need to keep those two in sync.
With Mason, I just add the page. Simple as that.
So if my site is actually simple and doesn't need Cat features, I
think I'm better served with a simpler solution, Mason.
KISS at work.
>> * the URLs are pretty simple, I don't need any chaining stuff.
>
> Hardcoding URLs all over the place is still a bad idea. $c->uri_for
> was useful
> before Chained became popular, and it continues to be useful
> independent of
> Chained, because it takes things like protocol, hostname, port, and
> SCRIPT_NAME
> into account.
I have a draft article on my blog why uri_for is a bad solution in
certain situations. uri_for is only available if you have a $c object
*for the target site*.
If you have both a front-office and a back-office site then you can't
use uri_for in the back-office to generate a link to a action in the
front-office, it just wont work.
But yes, hardcoding URLs would be a big mistake. And we don't do it
for a long time (before Cat and uri_for() existed even). What we do at
$work is this: we create a App::URI class with a method for each
public URL that we have, on all the sites. For example, we would have
a "member_area()" that would take a $member object or a $member_id
scalar, and (based on the current environment, like ENV, any Request
objects he has access to, phase of the moon, whatever), spits out the
proper URL.
For example, in our cat apps, our top level Root auto action has
something like this:
$c->stash->{u} = App::URI->new( base => $c->req->base );
Depending on the the needs, some App::URI's are more complex than
others. For example, I have one that based on a user cookie, generates
different URLs for 'base', allowing me to redirect a specific user
that is having problems to a different server for further analysis. A
live "lets debug *this* user" click on the back-office, and presto -
all accesses for that user switch to a new server, usually with debug
on.
On Mason, I don't have a perfect solution to keep this 'u' object
alive per request. Right now, I'm using a Guard object to clear a
global HTML::Mason::Commands::u so each component can just $u-
>method() anywhere, and this $u will be cleaned up at the end of my
Mason handler.
I guess I could just use notes/pnotes, but just using $u is easier.
So yes, uri_for is "nice" but only works if you can get a $c for the
site where the URL you want is located, and that is not always
accessible.
The tradeoff is that I need to keep these two in sync, the App::URL
class and the layout on disk of my Mason components. Its a tradeoff
that works for me for now, but might not work for you. I do like the
fact that I can use $member_object or $member_id as parameters to my
App::URL methods though.
Something for the future: I could probably extract my App::URI from
the Cat internals, walking the Dispatcher internals.
Also for future testing: on the Mason side, I could also create a <
%method> on each component with a specific name to house the methods
of my App::URI class and walk the in memory component cache to fetch
them, but this only work if we preloaded all the components to memory.
> If you'd said:
>
> * I'm always running my app under a single environment (FastCGI),
> and I don't
> care about having a standalone dev server
I don't. Even for Catalyst I develop with the app_fastcgi.pl script
under a local nginx on the laptop. It makes a lot of sense to have
this setup because I don't have do deal with static content on the dev
side. Usually you would use the Plugin::Static and then on production
switch to a nginx/lighttpd server for static, forwarding the rest to
fastcgi.
I just start as fastcgi. The startup time is the same, and with -d the
same debug features are there.
> * I don't need a separate webserver-independent config file for my
> app
I don't understand this one.
> * My app will never need to change internal structure while
> maintaining its
> current URL layout
If it ever does this, I would rather write mod_rewrite rules, in C,
fast, than deal with that on the App site.
It makes more sense to me to use the fast and expressive rewrite
engines that lighhtpd/nginx have than any other solution.
For example, to skip dhandlers I sometimes rewrite /user/ID into /
user/?id=ID.
> * My app will never live under any path other than / (or wherever
> it is
> right now)
This is true, they wont.
If they did, it is very simple to mkdir path and mv * path, and adjust
my App::URI class.
The way I have my App::URi's I would bet that I would only need to
change one line.
> I might not believe you on all those points, but you'd at least be
> saying that
> you don't need the core things that Catalyst provides.
I guess I failed to explain myself. My main point was exactly that: I
don't need most of what Cat does for me.
Mason is simpler, faster (but framework overhead is meaningless most
of time, given that database access will be your bottleneck), and
easier to develop on.
Also, Mason has a lot of upside:
* cache is builtin: this is *huge* for us; the fact that I can cache
each component individually is so flexible (and I can expand this
point if you want me to);
* development is simpler: no dev server restart for most of the
changes, only when Model classes change.
* production mode (preloading, static source) is wonderful.
Some of those items could be implemented with Cat, for sure, but they
are not core.
> (The other feature I
> think of as "core Catalyst" is the plugin architecture, which I've
> left out
> because subclassing HTML::Mason::Request is close enough, though
> that has its
> own gotchas too.)
I don't use Plugins much with Cat. I could expand this but it is OT
for this list. Ping me off-the-list if you want my reasons.
I do use base Controllers a bit, but I still find them limited.
I also would avoid subclassing Mason::Request...
>> Besides, the development environment of Mason is much better IMHO. I
>> don't have to restart the app_server.pl everytime I change stuff,
>> only
>> when the models change.
>
> Are you aware of the -r option (restart) to myapp_server.pl in
> Catalyst?
Yes. Compare that with "not having to restart". This is one of my Cat
apps:
(the Model, business logic, mostly DBIC Results/ResultSets)
find lib -type f -name \*.pm | wc -l
370
(the Cat app)
find site/WMG/lib -type f -name \*.pm | wc -l
61
Restarting the dev server is measured in seconds, multiple seconds.
Compare that with not having to restart most of the time.
My Model workflow is simple:
* tweak test case;
* tweak model while:
* run test case until it passes.
Then I restart the dev server and tweak components without further
restarts.
>> And I think that Mason has better performance on production
>> environment: the component preload, and the static_source features
>> are
>> awesome.
>
> Premature optimization, and in any case, is this based on anything
> more than a
> guess?
No, ab and siege results for my particular app.
And you should read the entire phrase to understand where that part
"Premature optimization is the root of all evil" was used. I'll do
that for you and highlight the part that I think applies in this case:
(Knuth paper is here: http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.103.6084&rep=rep1&type=pdf
, quote is on page 8, second column, search for evil)
We should forget about small efficiencies, say about 97% of the
time: premature optimization is the root of all evil. **Yet we should
not pass up our opportunity** in that critical 3%.
I see component preload and static_source as a easy 3% that doesn't
cost me nothing (in my case memory is cheap).
Also, it adds a nice side effect. You can update the files to a new
version without worrying about your App mixing old and new components.
Not that I would depend on that side-effect for important sites, but
it is useful in some situations.
For example, this is an old site, I don't recommend this anymore, but
it was useful at the time: I have two mod_perl app servers on the same
component roots in production. The production is running with
static_source, the pre-production is not. I can upload new versions of
the component, do some live testing on the pre-production server, and
restart the production server when I'm sure everything is ok.
Of course if the production server crashes it will see the new files,
and thats why I don't use this anymore, but it is nice :).
>> But, even if I make a bad decision right now, and the site grows to a
>> point where Cat is actually a better solution, I can still reuse all
>> my Mason components as a Cat view.
>
> Only if you are very disciplined about segregating components that
> use web
> framework features (cookies, etc.) from those which use only
> templating
> features; otherwise you'll need to go back through them all again.
Cookies are usually abstracted on my apps.
But sure, you need to be careful with that. But I don't think that
this part would be much code to rewrite, compared to all the templates.
> All that said, it's your app, and you should optimize for your time
> as a
> developer. If you are comfortable with what Mason gives you and
> aren't
> interested in learning (more) Catalyst at this point, go for it.
:)
I started with Cat 5.005 more than 3 or 4 years ago, and have wrote
and put to production about 10 sites using it. The biggest was the one
I mentioned before in this email.
Please understand that my decision to choose Mason was not of a
beginner. It was well though out, and based on my experience of Mason
since 1999 when I did a webmail Mason powered for 300k users.
Also I do like Cat, a lot, but I don't think its the answer to all of
the world problems. I do think Mason is a excellent framework, with a
lot of upside over Cat *if* you are disciplined enough. I would agree
that Cat gives a more consistent framework in some areas, but Mason is
no slouch.
But my problem with Mason is the deployment phase. Right now it is
very much geared towards mod_perl and that is something that we would
like to remove from our tool chain, and move to FastCGI.
Hence my presence here: to improve Mason FastCGI experience.
> My intent is
> to correct what I think are your mistaken impressions about Catalyst,
Well, maybe I'm mistaken about Cat, I don't think so, I do know it
pretty well. I might have failed to explain my reasons on my first
attempt. I hope to have done better this time.
Best regards,
|