On 2009-06-17, Jim Fulton <j...@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 answered. Thanks. 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: > > > http://docs.repoze.org/bfg/narr/urlmapping.html#differences-between-traversal-and-url-dispatch > > 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 > question. > > > Jim > > -- > Jim Fulton > Zope Corporation > > > -- Best Regards, Sergey Schetinin http://s3bk.com/ -- S3 Backup http://word-to-html.com/ -- Word to HTML Converter _______________________________________________ Web-SIG mailing list Web-SIG@python.org Web SIG: http://www.python.org/sigs/web-sig Unsubscribe: http://mail.python.org/mailman/options/web-sig/archive%40mail-archive.com