[Grok-dev] Re: sprint mini-report 2

Martijn Faassen faassen at startifact.com
Fri May 2 04:55:45 EDT 2008


Hey Brandon,

I'm going to vigorously argue against you here. That's not to say the 
arguments don't have any merit by themselves - you make good points 
about ORM mapping which I will take to heart. I just don't see them as 
relevant as points against the 'grok.traverse' directive.

Brandon Craig Rhodes wrote:
> Martijn Faassen <faassen at startifact.com> writes:
> 
>> * A spin-off discussion from the megrok.rdb discussion resulted in
>> our inventing a grok.traversable directive and we now have a team
>> that works on its implementation.
> 
> Their time might be better spent on turning megrok.trails into
> something worthy of a first release.  

I disagree. megrok.trails is a major philosophical change, while this 
codifies a pattern we've seen in current Grok applications.

That's not to say megrok.trails isn't a worthwhile effort, but the 
ability to tell a class which attributes are traversable fits Grok's 
current traversal paradigm without requiring a major shift.

> In general, RDB applications
> should seek to have simple, orthogonal URLs like:
> 
>   /app/person/brandon_rhodes
>   /app/person/martijn_faasen
> 
>   /app/account/br38
>   /app/account/expiretest
>   /app/account/faasen
 >
> Because, in general, one courts disaster by trying to think of
> relational objects as being "beneath" each other, as a traversable()
> directive would (if I understand the concept correctly) encourage:
> 
>   /app/person/brandon_rhodes/accounts/br38
>   /app/person/brandon_rhodes/accounts/expiretest
>   /app/person/martijn_faasen/accounts/faasen
> 
> Among many other problems (for example, uniqueness; in general,
> allowing traversal of attributes in an ORM will give you many URLs for
> a single object), URLs that traverse from one object to another
> destroy the properties of identity and uniqueness that RDBs are famous
> for.  For example, moving the "expiretest" account to someone else in
> the above example will result in its URL changing (!), which is a deep
> violation of the idea that a URL should be a permanent name for
> something.

That's an interesting argument. I'd argue that if you set up your 
traversal namespace in the second way you sketch out, the things in the 
individual accounts/sections should have been modeled as *being* unique 
per 'person' section, or, alternatively, your application should be able 
to deal with this information being in multiple places (possibly 
zc.shortcut would be interesting here).

The point that moving these to another person would break the URL is a 
good argument, but there is no reason to assume that all models of this 
kind will allow moving in the first place. While I agree that modeling 
things this way with an ORM may frequently be less desirable, I'd also 
argue that there are cases where such structures *are* useful.

Anyway, it doesn't matter: grok.traverse is useful to build your first 
structure as well:

class PersonContainer(grok.Container):
      pass

class Person(grok.Model):
      pass

class AccountContainer(grok.Container):
      pass

class Account(grok.Container):
      pass

class App(grok.Model):
     grok.traverse('person')
     grok.traverse('account')

     def __init__(self):
          self.person = PersonContainer()
          self.account = AccountContainer()

Any arguments against the grok.traverse() directive connected to the 
properties of ORMs won't work anyway, as we see grok.traverse as 
independent of whether an ORM is used at all. It just came up in the ORM 
discussion. We noticed a pattern common in Grok applications: use of the 
'traverse()' method to do this, or misuse of containers to contain 
heterogeneous objects. This we want to get rid of.

> I will gently suggest that ideas like "traversable()" are the result
> of long experince with the ZODB ruining people's minds. :-) How?  By
> convincing them that a URL should not be a unique name for something,
> but rather should simply be an impermanent description of how to find
> something at this moment.  When people use the ZODB too much, they get
> used to the idea that moving an object from one folder to another
> should change its name - they get used, in other words, to separating
> the URL from an object's identity.

Again, arguing for a major philosophical shift of how applications are 
built is all very well, but that doesn't take away that this is how 
applications are frequently built with Zope. There are drawbacks to 
traversal, but there are also benefits (I'll go into some of what I see 
as benefits at the bottom).

> In every Grok application that I have written so far atop RDBs, it
> simply turns out to be a small disaster (and, yes, I've tried it!) to
> put objects "under" other objects.  

I didn't have to deal with such a disaster yet in my little application, 
but you have more experience. :)

> That's why I wrote megrok.trails;
> I realized that things only becomes simple when the URLs for one kind
> of object are orthogonal from the URLs for all others:
> 
>     class MyTrails(trails.TrailHead):
>         grok.context(MyApp)
>         trails = [
>             Trail('/person/:shortname', Person),
>             Trail('/account/:username', Account),
>             ]

What happens if you go to /person or /account directly? Are there models 
and views for that?

I'd argue that if you have a URL called /a/b you typically want /a to at 
least not return a 404 error. My feeling is that modeling this with 
traversal as I did above encourages the filling out of the URL space, 
with a PersonContainer and AccountContainer.

There are other benefits to using traversal:

The structure of a traversal-based URL space is not centrally defined, 
but near the objects itself. This allows an easier composition of larger 
applications from disparate parts which don't know about each other (a 
major strength of Zope in general). If you *do* model things using 
nested names, there are other potential benefits: locally defined 
permissions and roles are inherited.

To conclude:

* grok.traverse is actually neutral in this whole discussion: you can 
use it to model things either way.

* grok.traverse is not connected to ORMs, but useful for generally 
mapping out URL namespaces.

* a traversal based approach has benefits, not only drawbacks. Since 
they also have a history in our community, I'd rather explore these 
benefits further and see whether we can turn this into a unique 
strength, not a weakness.

Regards,

Martijn



More information about the Grok-dev mailing list