Hi Hans,
Post by Hans Dieter PearceyPost by Pedro MeloPost by Jonathan SwartzI'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
* 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.
Post by Hans Dieter PearceyNot 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.
Post by Hans Dieter PearceyPost by Pedro Melo* 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-
Post by Hans Dieter Pearceymethod() 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.
Post by Hans Dieter Pearcey* 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.
Post by Hans Dieter Pearcey* I don't need a separate webserver-independent config file for my app
I don't understand this one.
Post by Hans Dieter Pearcey* 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.
Post by Hans Dieter Pearcey* 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.
Post by Hans Dieter PearceyI 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.
Post by Hans Dieter Pearcey(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...
Post by Hans Dieter PearceyPost by Pedro MeloBesides, 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.
Post by Hans Dieter PearceyPost by Pedro MeloAnd 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 :).
Post by Hans Dieter PearceyPost by Pedro MeloBut, 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.
Post by Hans Dieter PearceyAll 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.
Post by Hans Dieter PearceyMy 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,