Saturday, February 7, 2009

Repoze.bfg

As mentioned earlier, I've spent time looking at other frameworks lately.

I've spent more time on Chris McDonough's repoze.bfg than any of the others so far. This is probably because, as discussed below, it's very minimal. It's also documented well. Finally, it follows a few standard old Zope patterns that don't require much thought for me to process. Given all that, I can understand it quickly, and so am enticed to spend more time to read and think a bit about its design.

I looked at it again because of this recent bit of marketing: http://plope.com/whats_your_web_framework_doing. Chris makes his point, which is valid; and he's selling to his design's goals, which is the point of this kind of presentation.

As an aside, I'm a "can't we all just get along" kind of guy, so the fact that the trade-offs of repoze.bfg's design are not discussed in comparison with the other frameworks bothers me, even though having done so would have made the piece much worse marketing and much harder-to-read communication. (A repoze.bfg design tradeoff example: if you always need authentication and authorization for your web apps, you'll need to plug in and understand more WSGI middleware, and then the given comparison is not as pertinent, at least for Grok and Django.) I actually wouldn't be surprised if repoze.bfg still would do very well in the chosen metric, if the set up actually did include authorization and authentication middleware in the profile; and if it didn't discard the webob.Response. That would have been mildly more interesting to me. But, whatever, it's marketing, and I get Chris' point.

The name of the framework, "bfg" is funny on multiple levels. The level that sticks with me is that the F[*&^%$#] G[un] is really not that B[ig]. As the documentation points out, this is a very minimal framework:

Minimalism: repoze.bfg provides only the very basics: URL to code mapping, templating, and security. There is not much more to the framework than these pieces: you are expected to provide the rest.

That's nice for a "pay for what you eat" story, as the documentation says elsewhere. But it's also insufficient for any website I've ever made. There are at least some suggested patterns to follow elsewhere within the repoze meta-project: repoze.who and repoze.what are available for authentication and authorization, for instance.

But it is a framework that wants more guidance, more "rails," more framework, to get some basics done. What about web form helpers: maybe we ought to use Ian Bicking's stuff. Or what about REST helpers? You might be able to write some interesting adapters from a generic RESTful view to a CRUD-ish interface, like the patterns I've seen in Rails. But it's not there now (and the documentation states that it is an active goal to hide the zope component architecture, which could have helped with this).

While it's nice to be lightweight, I think this would make a more appealing sales pitch. Maybe it's in the plans to build related libraries and integrate them in "building with repoze.bfg" tutorials, or maybe it's antithetical to Chris' goals, who knows.

Of the three features that the framework provides, the view and templating story is the least interesting to me. It seems very similar to the Zope 3/Grok story. I intend to checkout Ian Bicking's webob library, and I hope to use chameleon at work and for hobby projects, but that's the extent of it.

The security story is very similar to Grok's. They both forego framework-level security checks during traversal, I believe, while they differ in the last step: repoze.bfg security-protects the last traversed object within the view code, as I understand it, while Grok security-protects the view. For what it is worth, I prefer the repoze.bfg approach.

The traversal story is the most interesting to me. When I first heard the repoze.bfg traversal plan of "__getitem__ over the model, period," as opposed to the more flexible standard traversal story of Grok/Zope 3, I was skeptical, but the more I think about it the more I like it. The traversal story in Zope 3 has always been a pain to use for me, and while there might be a more powerfully flexible way to alleviate that pain than the repoze.bfg approach (and I think Grok might have tackled this already), the __getitem__ simplicity still is appealing.

In that vein, I find that the assertion that the repoze.bfg code is not MVC but "MVT" (Model-View-Template) like Django doesn't feel right. repoze.bfg doesn't provide a model story; it provides a traversal story. As such, you could be traversing over models or controllers; the code doesn't care which. This is "TV" (Traversable-View); or "[MC]V," from a regex perspective on MVC; or some other odd acronym. Not MVT.

In any case, while I might explore using repoze.bfg on some hobby projects, primarily to get my hands dirty with WSGI and get a better handle on a couple of Ian Bicking's libraries, I won't be working with this at work, and I have a higher personal priority to get some time with Django. I'll probably continue to follow repoze.bfg's development from a distance for now...and be glad that I don't have to write any marketing myself.

2 comments:

chrism said...

Thanks for the blog post Gary! Looks like you've given it a good
once-over. I think you have a few misunderstandings, so I'll point
them out here.

"If you always need authentication and authorization for your web
apps, you'll need to plug in and understand more WSGI middleware".
That's not quite true. While authentication is not built in,
authorization indeed is).
And you don't need middleware to provide an authentication source:
repoze.bfg can also be configured to trust the Apache-style
REMOTE_USER CGI envvar
In my experience, configuring BFG security is far less complex than
configuring PAU or PAS. You *can* of course get more complex as
necessary via repoze.who, which is a lot like PAS. FTR, TurboGears 2
is using repoze.who for their authentication system as well, so we get
to share some of the maintenance and feature-add burden for these more
complex cases.

Wrt form validation and generation: There are a good number of
general-purpose form post helpers out there: formencode,
repoze.formapi, repoze.monty. There are also a good number of
general-purpose form generation libraries out there: tw.form,
io.formish, repoze.lxmlform, and so on. We tend to treat form
validation and form generation separately, instead of combining them
into a formlib-like framework. One of the reasons we do this is that
each piece is smaller, and the resulting packages can be used in
repoze.bfg as well as any other WSGI framework fairly easily, so we
tend to share the maintenance burden with other Python frameworks. In
practice, this works quite well.

"What about REST helpers?" We do indeed allow for this sort of thing
using adaptation. But you're right about the CA helping here; this is the one place
we don't really try to hide it.

Wrt "repoze.bfg doesn't provide a model story, it provides a traversal
story. As such, you could be traversing over models or controllers;
the code doesn't care which". This is incorrect: bfg traversal is
unwilling to traverse over or into view code like Zope does, it is
only willing to traverse over models in a model graph. The last model
found becomes the context, and we adapt it to a named view using the
next element of the path. During traversal, we *find* a model to be
the context. We also support URL dispatch using Routes. And in that
mode, BFG *generates* a model, which is the context. So it literally
does use models, and they are very distinct from views (or
controllers, whatever you want to call them).

And FTR, as for the BFG version of the
profile test throwing away
webob.Response, that's mostly because it *can*. Pylons can't; it
makes one for you whether you need it or not. Grok and Zope3 work
completely differently, but to a large extent it's true there too:
you're not going to throw away the code that creates a response in the
real world. In bfg, however, we do it all the time; it's even
documented
. The same thing for being able to disable authentication: in bfg
it's the default that it's disabled. You enable it specifically .

As far as needing rails: BFG doesn't quite share Zope's (or Django's)
ethos of ship-with-lots-of-stuff. Instead, we try to keep the core
small, and let people add stuff via addon packages. It's just a
different ethos, and folks will choose whatever fits their brain at
the end of the day, I suppose.

Gary said...

Hey Chris.

Point taken with authorization being built in: I had forgotten about the ACL bits.

I was aware of most of the other libraries you mentioned--and I certainly didn't mean to imply that there were not good form generators/validators out there. I was just saying that bfg wasn't guiding users in any particular direction for forms, which is simply an observation of your philosophy, as you say towards the end.

Cool about REST being possible with interfaces. Your response is certainly valid, though I was thinking more about RoR-style REST support. One could probably build something like it on top of the interface hook you showed that supports it.

My response to your disagreement about my MTV comment got so big that it turned into another blog post. http://codesinger.blogspot.com/2009/02/my-claim-mtv-is-silly.html

Thanks for the comment and corrections.

Gary