[Web-SIG] Announcing bobo
maluke at gmail.com
Fri Jun 19 01:46:54 CEST 2009
On 2009-06-18, Jim Fulton <jim at zope.com> wrote:
> (Note that this discussion is getting rather dense. I suggest reading my
> reply all the way through befor responding to individual points. :)
> On Jun 17, 2009, at 6:42 PM, Sergey Schetinin wrote:
> > 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
> > > 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
> > > from other functions"? I've found it useful to have a standard
> > > for this that you can use over and over without reinventing it each
> > >
> > 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.
> But software still lives in a namespace. You usually assign a function a
> name in a module or package. It often depends on other functionality being
> available under specific names. In web applications, we often need to know
> where other components are in the URL space. OTOH, often a function
> doesn't depend on it's name and you feel that a web application shouldn't
> care about it's URL. I get that. :)
Well, the app needs to know where its children are located and it
controls that. If the app needs to know its siblings' paths I think
that should be parametrized. That way, the parent can set up its
components that they know where to find each other but there's still
flexibility to it. Conventional paths work too, but there's plenty of
code reuse lost as a result.
Imagine a web forum app. The top level app is the topic list, there
are "discussion thread" apps that it exposes at some paths, those apps
would want to know the URL of the topic list so that they can link to
it. They may assume that it's one level up or they might actually have
a way to define where they are. In the latter case when the forum app
created its children, it would have let the children know that it is
Now consider someone writing a blog app for example, there are apps
that represent specific blog entries and it would be nice to be able
to reuse the "forum thread" component and expose it at a subpath, for
example as /blog/entry-name/discussion. If we were not just using
conventional paths in the implementation of that thread app we could
just tell it that it should refer to its parent as a "blog entry X" or
something. The point is that decoupling is a good enough thing to be
worth at least few extra lines of code. If the forum app was using
some routing library, things would be much more complicated -- it's no
longer a matter of a few lines of code but a major PITA.
> > 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.
> OK, so you expect there to be a URL mapping, typically accomplished via
> some configuration mechanism outside the code. Most routing systems either
> require or allow this.
> > 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.
> I wasn't trying to represent what you said. I was just guessing at what you
> said. So you don't mind routing systems that are configured through routing
> tables outside the code. (?)
As long as all the routing system does is match a prefix, no parameter
extraction, no regexp nonsense -- it's ok. However that makes it so
small nobody would bother calling it anything, certainly not "routing
system". Regarding configuration of these things -- I don't see any
need to bring in anything but straight Python for this, but that's
> > 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.
> Again, I get that you want to separate URL from the code, but I don't agree
> with your analogy. This may not matter.
> Something to note is that the paths used in bobo are often not absolute.
> If you use subroutes,
> http://bobo.digicool.com/index.html#subroutes, then the
> paths used will be relative to a position in a URL tree. In the referenced
> section, the paths in the Document and Folder resources are relative to the
> URLs used to access a document or folder.
> An innovation in bobo, I think, is that it combines routes and traversal
> ("URL Dispatch" and traversal in
> > However, I have to admit, that if taken as an iterative improvement
> > over file/function name it looks very reasonable.
> I'm not sure what you're referring to here.
I meant that bobo decorators seem a natural development to a system
that would assign URLs based on file and function names.
> > > 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.
> > > led to some less than optimal rules.
> > >
> > > - The traversal model mapped well onto an object database, but not so
> > > onto relational models.
> > >
> > > Many people have taken the approach of providing an explicit separate
> > > code) mechanism of mapping URLs onto their Python objects. Usually,
> > > 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.
> Nothing is given up. You can still configure paths externally if you want.
> (I'll have more to say on this below.)
> > 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.
> I don't understand what extensibility you're referring to here or if this
> has anything to do with your objection to specifying paths in the code.
> Note that bobo doesn't require a global routing object. Bobo provides
> various ways of knitting URL trees together by having resources invoke other
> resources, as is done in the document-tree example referenced above.
> > 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
> I'm confused. Generally, Python functions know what arguments they want to
> get. What does this have to do with routing?
> > and those are directly "plugged" into data output of path
> > pattern used in the URL router.
> Sorry, I can't parse this. :)
The bobo apps consume data output of bobo url parser, which is a
restriction that has nothing to do with the webapp functionality
itself. It might make sense to use some data from a parent webapp, but
it would need to be passed in a roundabout way. That's tight coupling
I was referring to.
Take the "forum topic" as blog entry discussion -- it's non-trivial if
the topic id in the database is taken from the URL path. There are all
kinds of reuse possibilities lost just by collapsing this level of
abstraction (path -> app mapping). Even if there are ways to
reconfigure the default mapping -- one ends up working against all the
routing stuff original developers of the component put in, unwinding
the tangle of tightly coupled implementation. Which is usually not
> > 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.
> Can you explain how you see this as different from:
How would one use those apps from non-bobo app? How would one put
non-bobo app into those mappings? I suppose there are ways to unwrap
and rewrap things, but wouldn't it be nice if we could finally just do
from somebody_else.forum import ForumApp
urlmap['/forum'] = ForumApp(db_config=...)
The point is that we can, thanks to WSGI, only if people were writing
their stuff the boring way and not build walled gardens that make one
thing easy and a thousand others impossible.
This sounds accusatory, but please don't take it that way. I'm just
voicing my opinion on the problem in python webdev that annoys many
people I believe. Unless you share that feeling there's no need to
take it into account.
> > 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 still don't understand what you perceive these inherent problems to be.
> On Jun 17, 2009, at 9:55 PM, Sergey Schetinin wrote:
> > On 2009-06-18, Aaron Watters <arw1961 at yahoo.com> wrote:
> > >
> > >
> > >
> > > --- On Wed, 6/17/09, Sergey Schetinin <maluke at gmail.com> wrote:
> > >
> > >
> > > > 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.
> > > >
> > >
> > >
> > > So you seem to be suggesting that a web component
> > > should not be aware of its URL in the same sense
> > > that an object is not aware of
> > > its variable name in the scope of the application
> > > that is using the object. Is that right?
> > >
> > > In particular you should be able to assign a
> > > component to any URL in the same sense that you
> > > can give an object any name. You should also
> > > be able to build relocatable URL trees which can
> > > be "mounted" anywhere in the "calling" application
> > > suite. Do I catch your meaning correctly?
> > >
> > Spot on.
> > > It's not clear to
> > > me whether Bobo allows or disallows this
> > >
> It does.
> > Generally, I think "allowing" it is not enough, I'd prefer it to be
> > *expected*, not just supported.
> To some degree, this is the approach that Zope 3 took, It (strongly)
> encourages you to separate application implementation from configuration.
> This was motivated by a well-intentioned desire for the kind of flexibility
> I think you're advocating. The result was elegant but hard to deal with. I
> think it's great to have this flexibility when you need it, but in my
> experience, 99% of web applications don't need this sort of flexibility and
> the methods needed to support the flexibility become a tax.
I suppose the reason is that this separating the configuration was
implemented as yet more stuff. My idea of configurable webapps is to
pass configuration at instantiation. No extra code. IMO, the more
complex configuration systems are needed when there's a need to
penetrate though levels of framework crust (hello tight coupling)
which is another thing I argue shouldn't be there.
> My design for bobo is based on the assumption that most people don't need a
> lot of flexibility while some do, where the former is the common case. It
> tries to make simple applications very easy to create, without making it
> hard to address more complex requirements. I feel good about bobo's ability
> to deal with simple applications. Time will tell if it accommodates more
> complex applications. :)
As I said, your reply did explain how you see bobo and its purpose,
and it makes complete sense. None of what I said is specifically about
bobo, just general trends in python webdev.
> This discussion falls into the larger debate of configuration vs convention
> and explicit vs implicit. I tend to prefer explicit, but am wary of systems
> that require a lot of configuration (having built one :). Most systems try
> to strike some balance, as does bobo.
> Jim Fulton
> Zope Corporation
http://s3bk.com/ -- S3 Backup
http://word-to-html.com/ -- Word to HTML Converter
More information about the Web-SIG