[Grok-dev] Re: Atom and RSS feeds in Grok

Brandon Craig Rhodes brandon at rhodesmill.org
Mon Jun 23 15:28:19 EDT 2008


"Derek Richardson" <derek.richardson at gatech.edu> writes:

> Currently, in Vice, there is one view that never changes ... This view
> adapts (IFeedable, IBrowserRequest).  To make an object able to be
> fed, you do two things:
>
> 1. Write an adapter from the object's class to IFeed
> 2. Provide IFeedable on the object
>
> This way, the view contains what is the usually the *same* for all
> requests for the feed, regardless of context, and the adapter
> encapsulates everything that *varies* by the context.

This approach sounds completely unacceptable.  The goal here is not for
there to be a single view, like:

 (IFeedable, IBrowserRequest), "feed"

that makes all syndicatable objects on a Grok site grow a "/feed" view
which renders them as some single kinds of feed (Atom or RSS, depending
on the developer's settings?).  Rather, the goal is for a Grok developer
to be able to declare several feeds on a single object, so that "/rss"
on his favorite container could return one kind of feed, "/atom" could
return another, and maybe even "/atom_recursive" return a third which
differs not only in content but in format.  Your suggestion does not
sound capable of supporting this basic use case.

Even worse, your scheme doubles the number of interfaces in play, merely
in order to provide information which is redundant.  To review: you
suggest splitting container syndication into two separate adaptation
steps:

 container --(custom adapter)--> IFeed object --(universal view)--> HTML

This split means that you are unable to drive the rendering process by
the fact that the developer has written the correct adapter that gets
his container and provides IFeed information (like its feed name, feed
title, and so forth).  Instead, the developer has to take a second step
of attaching the IFeedable marker to his container before your view will
pick it up.

And not does using the IFeedable marker require a second step, but,
strictly speaking, it's a fraudulent adapter registration!  Let's look
at it again:

 (IFeedable, IBrowserRequest), "feed"

As you can see, this view makes the promise that "if you provide an
object that satisfies IFeedable, then I can answer a browser request by
rendering it."  But this is false!  It's not the presence of the marker
interface that makes your view able to process an object; in fact, if
you run your view on an object that's merely marked IFeedable, then the
view will fail and say something like "Cannot adapt your container to
the IFeed interface."  It's really the ability to *be adapted* to IFeed
that makes the object renderable, and you place the burden on the
developer to consistently make double-registrations for every container
that he wants to syndicate, and to make them all correctly.

We can now proceed to yet another issue:

Because this is Grok-land, I can actually hide this ugliness and
complexity, by writing the grokker for "grok.Feed" such it actually does
the double-registration for the user - maybe it will register itself as
the container-to-IFeed adapter while also remembering to place IFeedable
on the container itself.  Then the burden placed upon developers goes
away.

Until, that is, they encounter a problem and fire up a debugger to
examine some mistake they made in their adapter.  If they have practice
debugging Grok applications, they will know that all other Grok views -
grok.View, grok.XMLRPC, and grok.REST, for example - have one of their
own content objects as their "context".  This is, so far as I know, an
iron rule in Grok: in any view, "self.context" will always be the
user-defined object that lives at the URL that one would get by chopping
off the view's name.

But this will not be the case with your "two-storey" views!  The URL
will simply say something like:

   http://.../app/container/feed

Which makes it look like the "context" of the view "feed" should be the
object named by "app/container".  But the developer, in his debugger,
will discover that the "/feed" feed view is actually an object he's
never seen before that lives in "vice.outbound.core"; that its "context"
is an instance of his "grok.Feed" adapter, which, it turns out, doesn't
even have a URL of its own (!); and that only by going inside of its
"context" can he then find his container.  This seems to create an
important, and unnecessary, asymmetry with the other kinds of Grok
views, and, even worse, does it "magically" without the user being able
to guess from the appearance of his "grok.Feed" declaration that what's
being created is any different than any other sort of Grok view.

> Your approach would require adding all the methods that currently live
> on the adapter to the view, so that the view can render an object of a
> class and so that it can be selectively overridden, to minimize
> boilerplate. ... perhaps the view boilerplate lives on one superclass
> and is simply inherited repeatedly, so you don't actually rewrite it.
> But I object to it being there at all.  I contend that your route
> results in one class that is less cohesive and more tightly coupled
> than my two class approach.  It is better to separate the constant and
> varying than to tramp the constant through every variation.

You make a big deal about this, but really the only "constant" element
in your dinky little feed View that I can see is that it takes Python
"datetimes" provided by the user in their IFeed adapter, and turns them
into date strings of the format required by the RSS and Atom feed
specifications.  Big deal!  You prefer the expense, messiness, and
complexity of your "two-storey" scheme, just so the developer doesn't
have to inherit, from the Feed superclass, a tiny bit of logic that
reformats dates?

That doesn't make sense.

> The clincher would be if someone wanted to change the view and use the
> same IFeed-adapted objects.  In your scenario, this would result in a
> combinatorial explosion of views.  In my scenario, it results in one
> more view and zero more adapters.

No, it wound not have that result, because any sensible developer, on
realizing that, say, five of his content types are similar enough that
the same adapter could syndicate all of them, will simply tag them all
with an interface that (gasp!) rather than being a marker is an actual,
honest assertion that they share some of the same attributes and
methods, and then write something like:

    class MammalFeed(grok.Feed):
        grok.context(IMammal)
        grok.formats(rss='rss')
        def update(self):
            sci_name = '<i>%s %s</i>' % (self.genus, self.species)
            self.title = "The Mammal %s" % sci_name
            self.description = ("Exciting recent events in the hunting"
                                " and cooking of %s" % sci_name)

See?  Simple, happy, fun.  Explicit rather than magical.  Wait... what
is that?  Do I hear... a cave man speaking?  Let's listen...

   GROK NOT WANT CONFUSING INCONSISTENT MAGIC.  GROK SMASH.

There you have it.

-- 
Brandon Craig Rhodes   brandon at rhodesmill.org   http://rhodesmill.org/brandon


More information about the Grok-dev mailing list