[Web-SIG] Announcing bobo
maluke at gmail.com
Thu Jun 18 00:42:32 CEST 2009
On 2009-06-17, Jim Fulton <jim at zope.com> wrote:
> On Jun 16, 2009, at 11:02 AM, Sergey Schetinin wrote:
> > indeed there are quite a few
> > frameworks / components that do this thing and I kind of don't get why
> > people want to write their apps that way. I wonder if Jim or anyone
> > else could explain the rationale behind all these URL routing
> > libraries. Nobody minds calling functions from other functions --
> > that's basics of programming, but for some reason URL dispatching is
> > seen as something different. Why?
> > This is not a criticism, I just really would like to understand this.
> Fair enough. I'm not sure I understand your question. You need some way
> of mapping URLs onto Python objects that handle them. You can do this on a
> case by case basis by inspecting a URL and doing some sort of ad hoc
> dispatch in your application. Is that what you mean by "calling functions
> from other functions"? I've found it useful to have a standard mechanism
> for this that you can use over and over without reinventing it each time.
I guess didn't state my question properly, sorry. Let me explain what
I meant by "calling functions" analogy. My point is that when we
define a piece of functionality (as a function, class or whatever) we
don't say where to use it. I mean, we may define functions as "take
data from a this argument, process and return" and it's up to the
caller to pass that data into the function, function doesn't say where
that should come from or where in the rest of code should its body be
injected or anything like that. So function is a definition of
functionality and it is being called from somewhere else, the called
should know as little as possible about the caller and its place
relative to other calls its caller makes. At least that seems to be
the advice for good software design.
When considering webapps and what urls they should handle it seems
like the same should apply -- webapps define contained blocks of
functionality and the task of placing them somewhere in URL-space
belongs to the "caller" which in this case would be a configuration or
serving script or, most often, a parent application. Sure, this
requires inspecting the URL, or as you said, "ad-hoc dispatching". I
think that misrepresents this approach because all it boils down to is
a series of if's, maybe a dictionary lookup and possibly regexp
matching is some cases (I personally never had to use that for URL
dispatch though). If we were to look at a similar approach in a
different context, I don't think it would be fair to call a series of
if/elifs "ad-hoc logic", so it's the same thing here.
But let's go back to bobo, I can see how URL paths derived from file
and function names are nice and make sense, but I'm not as thrilled
with declaring the app path in a decorator. When looking at it from
the perspective of "caller defines when and how the subroutine is
called" I see that the entire (and very useful) level of abstraction
is gone -- the application path is defined right where the application
itself is defined. It's almost like declaring a piece of code and
saying "just inject this into file X at line Y" -- not pretty.
However, I have to admit, that if taken as an iterative improvement
over file/function name it looks very reasonable.
> In the original bobo (aka "python object publisher") that I wrote in '96, I
> mapped URLs onto object names in modules. Later, I extended this to use
> object keys and this grew into a traversal model. There were some
> difficulties with this approach:
> - I needed some way to decide which objects should be URL accessible. This
> led to some less than optimal rules.
> - The traversal model mapped well onto an object database, but not so well
> onto relational models.
> Many people have taken the approach of providing an explicit separate (from
> code) mechanism of mapping URLs onto their Python objects. Usually, this
> involves having a table mapping URL patterns of some sort onto object
> identifiers. I like explicit. :)
I like explicit too, and I like decoupled as well :) By giving up the
"manual" dispatching to some libraries people seem to dig themselves a
hole without even realizing it. There's so little code saved by doing
this, that I don't get it -- some of very useful features are given up
and it doesn't look like a tradeoff -- just giving control up without
a reason. ISTM that the reason is that this "manual dispatch" thing
seems more complex than it is in reality.
To some extent, various routing libraries make sense because they
provide some level of extensibility, you know, like generic functions
vs. series of ifs. But given how they are used -- one global routing
object usually -- the need for that extensibility wouldn't be there if
not this initial design.
In my view, this kind of routing also has the same flaw as the one I
see in bobo -- tight coupling. Apps know exactly what arguments they
want to get and those are directly "plugged" into data output of path
pattern used in the URL router.
So basically there's a way to do dispatch with things like URLMap from
Paste and other similarly minimal dispatch mechanisms that just plug
one into another any way you wish and effortlessly and they are pretty
much extensible as it gets -- they can be updated from anywhere in
code. This is a very simple alternative to the routing libraries that
I don't see used much. At the same time the problems with the popular,
routing approach make people write more and more of those hoping to
fix the problems that are actually inherent to the design. IMO anyway.
I guess I'd better give some examples of how I think the URL dispatch
"should be done", but I'm spent for today, sorry :) Maybe later, if
this discussion will continue.
Anyway, that was a long-winded way of asking a question you've already
Also, love the bobo/bozo naming :)
> BTW, Chris McDonough provides a nice comparison of traversal and what he
> calls "URL Dispatch" based on a mapping table (Pylons routes) in:
> One of my goals with bobo is express web applications with Python as much
> as practical. While bobo does support the ability to provide an external
> mapping, I definitely wanted to be able to express the mapping in the code.
> One of the advantages of recreating bobo in the 21st century is that I get
> to use Python decorators, which provide a way to be very explicit about
> which objects are available to handle URLs. (Other web frameworks use
> decorators for this purpose too. Bobo is *not* revolutionary in any way. :)
> I find the route syntax used by Rails and Pylons to be very appealing. It
> uses fairly simple path patterns with placeholders. It doesn't use regular
> expressions. I don't personally care for the controller+action model used
> by Rails and borrowed by Pylons, so, after looking at using Pylon's routes
> implementation, which I took a lot of inspiration from, I went with a
> slightly different model. Basically, a route maps onto an object and when a
> URL matches a route, we call the object. (Of course, there are other
> details, but they're covered by the bobo documentation.)
> I hope this helps and that I haven't totally misunderstood your original
> Jim Fulton
> Zope Corporation
http://s3bk.com/ -- S3 Backup
http://word-to-html.com/ -- Word to HTML Converter
More information about the Web-SIG