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

Alexander Limi limi at plone.org
Mon Jun 23 23:56:06 EDT 2008

Just a little pre-emptive strike here — you're both awesome people, Derek  
and Brandon — don't let this get out of control. You both have valid  
points, no need to overdose on the vitriol. In fact, if you met, I'm  
pretty sure you'd get along really well! :)

This simply seems to be a matter of style and slight miscommunication to  

Feeling-like-the-family-uncle-without-the-creepiness yours, ;)

— Alex

On Mon, 23 Jun 2008 15:32:50 -0700, Derek Richardson  
<derek.richardson at gatech.edu> wrote:

> Brandon Craig Rhodes wrote:
>> "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.
> How absurd a rebuttal! *Of course* this use case is supported. Just
> because you do not have to rewrite the view class *every* time you
> want to syndicate a different type of container does not mean you
> cannot register the unitary view class multiple times under the same
> name, with different functionality available at different url
> extensions.
>> 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.
> To be charitable, I will interpret 'number of interfaces in play' as
> meaning 'number of times the total number of interfaces is
> implemented.' Because it is patently untrue that the number of
> interfaces doubles, as you seem to imply with your vague wording. So,
> yes, each container must implement IFeedable to be known to be
> adaptable to IFeed, but this merely means registering the container as
> implementing IFeedable, not writing a new interface for every type of
> container to be fed.
> I don't know why you are so bothered by the total number of times that
> the total number of interfaces is implemented. Perhaps you would care
> to share why this matters in the least?
> Besides, this is an established zope 3 pattern. As an example, see
> zope.annotations.IAnnotatable. Philipp has this to say about
> IAnnotatable in the second edition of his book:
> """
> IAnnotatable
> Zope needs to determine if an object has an IAnnotations adapter very
> frequently, which means it needs to be done very quickly. Rather than
> trying to adapt each object to IAnnotations and reacting to success or
> failure, Zope uses an optimization. It requests that objects "promise"
> to be adaptable to IAnnotations.
> They do this by declaring to be annotatable, by providing IAnnotatable
> from the zope.annotation package. This interface does not promise any
> additional functionality expressed in methods or attributes. It is an
> implied contract, a marker interface. The implied contract is that it
> is possible to get an annotations adapter for any annotatable object.
> """
>> 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.
> See above. Your overblown vitriol should be directed at, not only
> Vice, but the Zope 3 codebase itself. Certainly the authors of Zope 3
> did not find their usage of exactly this pattern in zope.annotation to
> be "fraudulent," as you so graphically tar my adherence to this
> standard pattern.
>> 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.
> So, we see it - there is no substance to the above objections, since
> they will almost never impinge upon the end-programmer experience!
>> 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.
> Ha! Your approach falls before the same objection. To repeat a section
> of my original response that you conveniently redacted:
> """
> This approach that you are taking with feed items is exactly what I am
> contending should be done with the feed itself. To carry your feed
> logic above to its logical conclusion, you would not have FeedItem
> adapters either, but simply have a view that knows how to go from
> objects to the information required to render an object as an item in
> a feed. My position is consistent: adapters adapt objects of varying
> interfaces to a single interface so that they can be used by a single
> view.
> """
> I contend that to be consistently indirect in the same way is better
> to be inconsistent in the use of indirection. Plus, I think this is at
> worst a minor drawback in the face of my overwhelmingly better
> approach. So, let's talk about that next...
>>> 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.
> Even if this were true, it would not be a rebuttal of my initial
> claim, just a quantification of the abuse you commit - you are still
> abusive with respect to good design, just not as violently as you
> might potentially be. That's hardly a justification.
> And, furthermore, it's not true. You also might want to change the
> mime type, the encoding, the cache headers, etc. And you might want to
> add things not currently there, such as I have done for a private site
> that tgz bundles the feed document with all the enclosures, so that
> repeated queries do not need to be made. You can't rule out in advance
> the utility of this, except by being dogmatic.
> Plus, you are simply arguing the empirical effects I suggested as
> examples of how the bad design plays out, not answering the core claim
> that you are engaged in poor design.
>>> 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)
> Ah, if my use were but illegitimate. I suggest you take up the issue
> with Philipp and the other authors of Zope 3, rather than maligning me
> for using the technologies in the way they are clearly intended. This
> suggested amendment on your part is merely a stopgap measure for
> achieving a partial capture of what I achieve at the beginning, and
> with more work, besides!
> Derek

Alexander Limi · http://limi.net

More information about the Grok-dev mailing list