[Zope3-dev] Re: ZCML bad ;-)

Jeff Shell eucci.group at gmail.com
Sat Jan 21 17:06:30 EST 2006


On 1/20/06, Shane Hathaway <shane at hathawaymix.org> wrote:
> Chris Withers wrote:
> > FWIW, I still hate ZCML for the following reasons:
>
> Everyone seems to agree on the direction suggested here:
>
> http://www.z3lab.org/sections/blogs/philipp-weitershausen/2005_12_14_zcml-needs-to-do-less
>
> I think that will resolve a lot of concerns.

I very much agree with that, and have been working a lot to start
using those styles where I can. I like using that for the adapters
especially, and now I'm designing and writing more adapters because it
is so much easier now to just write::

    <adapter factory=".formatters.DateFieldFormatter"/>

and not freak out over all of the ZCML options and which ones I really
should be providing. And then when I look at the python code, it's
much nicer to see all of the base classes, implements, and adapts
statements right there. When I revisit the code a couple of months
down the line, there's just more contextual information immediately
available.

I'll still heavily defend ZCML to an extent. I've written before about
how I've tried to do component-architecture-lite systems in Zope 2 in
the past, and doing a lot of the registration bits in Python cleanly
was just hard. No project of mine has ever done it quite the same way.

I definitely like the "on/off" feature of ZCML. In moderate to large
systems, it's nice to know when and how components are loaded and
registered. ZCML removes the mystery from that, and I love that - I
think it's critical, in fact, if Zope 3 is going to show off / succeed
as an integration platform. Being able to use code from a third party
package without having any side effects of spurious and unwanted
component registration is nice, as is being able to provide alternate
registrations for what that package provides.

But I'm really starting to get frustrated with a lot of the elements
in the ZCML browser: namespace. They do a lot behind the scenes and
maybe that's a good thing for new users to minimize the amount of code
they have to write or provide, but it gets frustrating (at least, it
has for me) when you start growing up beyond that.

Maybe the big base-class-mess of Zope 2 made it desirable to not even
require a base class for a Zope 3 view? Some of those viewmeta
directives are doing a lot of crazy dynamic class and method creation
to provide IBrowserPublish, traversal to the default view, or
rendering a certain attribute or template automatically as the
default. As I was starting to use Zope 3 in earnest, I wouldn't
understand when I should use browser:page versus browser:view, and if
I did browser:page with both a template and a class if there was any
way I could refer to the template from the class's methods since the
template was stitched in by ZCML.

Even though I've made a pro-ZCML case on the basis that most of the
directives and their attributes are reasonably well documented, what
the directives DO is another matter entirely. In theory, registering a
view is equivalent to zope.component.provideAdapter((ISomeObj,
ISomeSkinLayerOrRequest), provides, name). But the directives do so
much more than that. So while I'm often trying to stick with apidoc
for reference, I'm always going into Zope to see how things really
work and usually to ensure that I'm really doing things correctly. And
looking at some of the metaconfigure code is... Well, it's rough.
There's something defined in zope.app.publisher.browser.menumeta for
menuitems called 'extra'. I've been struggling to find out if I can
add things to menu items to render out like javascript onclick
handlers. And I mean s-t-r-u-g-g-l-i-n-g. I finally find this 'extra'
thing. It's not defined in any schema interface. What is it? What form
does it take? It's in the argument list in the directive handlers, but
not in the metadirective's schema. Should I write my own menu system?
I like being able to declare menus in ZCML - keeps their order easy to
control. But I don't want to be writing javascript handlers in it. I
don't want to be writing new directives. I've been crawling through
this code all morning. It's very convenient until you can't do what
you want... So then the issue becomes "should I just do it in Python?
Is there a way I can do it but still have it all work out nicely at
configuration time? I'm guessing there is if I write a custom
IBrowserMenu utility and write my own way of providing menus to it..."

The documentation about the IBrowserMenu interface is there, the menu
items too. But there's no clear path to translating ZCML like this::

<menuItems for="kbase.interfaces.IKnowledgeBaseArticle" menu="kbase_views"
    layer="kbase.skin.KBase">
  <menuItem action="@@display" title="Display" permission="zope.View"/>
  <menuItem action="@@editform" title="Edit"
      permission="br.cms.ManageContent"/>
</menuItems>

<menuItems for="kbase.interfaces.IKnowledgeBaseArticle" menu="kbase_actions"
    layer="kbase.skin.KBase">
  <menuItem action="@@delete" title="Delete" permission="br.cms.DeleteItem"/>
</menuItems>

into a custom IBrowserMenu utility that explicitly just lists these
menus or implicitly finds them by looking for an adapter I write that
does... stuff.

And the feeling I get here is kindof like the feeling I assume people
get in Zope 2 when they try to grow beyond a certain point. Up to
here, the system provides you with some nice and easy tools to do
_____. You can do _____ your own way and make it better if you just do
this: (pulls out new programming paradigm).

I like the approach taken in zope.formlib, which puts more trust in
the Python code and provides good but also simple / shallow base
classes (which aren't required, they just provide a lot of the common
functionality). Trying to do some custom forms with
zope.app.form.browser's forms in Zope 3.1 was challenging. Doable, but
challenging, especially as zope.app.form.browser's forms really wanted
to be built by ZCML. It's still very nice in theory from the "naked
objects" "scaffolding" "auto-admin" perspective: build add forms and
editforms automatically in 6 lines of ZCML! No programming required!
But the difficult step always comes when it's time to do just a bit of
programming from that, and then a bit more, and then a bit more. And
then you might think you provided a new custom form base class you can
use all over the place and get its template, only to find that ZCML
wrote over it for the subclass.

So I was happy to see zope.formlib, and to not see any meta.zcml
anywhere in that package. On the other hand, as much as I want to like
viewlets, there are things going on with the browser:view, page, and
viewlet ZCML directives that are madly (well, usually mildly)
frustrating.

> There's only one thing that bothers me about that article: it calls the
> people who complain about ZCML either "Python purists" or "die-hard Zope
> 2 coders", when you and I are neither.  We are Zope evangelists, and our
> concern is that the current ZCML is a significant barrier for others who
> want to learn and adopt Zope.

I think it's funny that in this conversation we have people saying
ZCML is a substantial barrier. In the "ZConfig syntax for ZCML"
discussion there are people saying that ZCML is a low or comfortable
barrier for people coming from XML heavy environments like J2EE.

I think there are a mix of people out there looking for something new,
and systems like Rails, Django, and TurboGears are all [currently]
appealing to those people. Many are frustrated PHP users. I gathered
this from the general remarks of the main developers of Django and
Rails in the "Snakes and Rubies" video. Both were looking for
something better, cleaner, etc. A lot of their users seem to be coming
from that camp - it's easy, it's fun, and it just feels cleaner and
more structured than PHP. It's not "quick'n'dirty"

The other camp seems to be coming from the J2EE side, where there are
more acronyms for technologies than stars in the sky. They've got the
environments that are often extremely clean, extremely decoupled, etc.
Coming from that into these new environments feels faster and easier
than J2EE while still using a lot of good object-oriented concepts.
It's not "slow'n'clean".

They call it "quick'n'clean".

I really think that the core of the Zope 3 component architecture is
beautiful. I had that zen moment recently where I went "oh, it's all
adapters, utilities, and multi-adapters!" When I stay the closest to
it - writing code that uses adapters to turn a list of schema fields
into something nice for file system representation and back - I'm
really happy with Zope 3. When I'm writing core content classes and
basic adapters (INameChooser, ISearchableText, IReadFile/IWriteFile)
and it all just works, I'm happy. Even when I'm using ZCML to register
classes, security, adapters, and some extra marker interfaces, I'm
pretty happy (but it does start to tear at me - "how much or how
little should I declare here?").

But these days, when I'm working in my browser/configure.zcml type
files, I get real grumpy, real quick. That's become the part where I
kindof close my eyes and hope I get everything right.

Zope 3 should dominate not only quick'n'clean, but
quick'n'clean'n'grown-up - an architecture that's closer to the scope
of a J2EE type system, that brings a lot of powerful concepts into
Python without a lot of complexity and without being cavalier with the
language, can handle complexity as well as simplicity, and is governed
by a few basic principals that we believe give plenty of benefits.
Interfaces/Schema combined with a few helper functions empower design
by contract without being restrictive or unpythonic, and that contract
alone can be used for so many things: web form generation and
validation; SQL generation, validation, and import; XML import/export;
documentation; RPC formatting; and of course - adaptation (duck typing
on steroids).

And I think that unless ZCML is simplified and starts doing less
automation as promoted by Phillip, that message will be lost. Again -
I like what zope.formlib offers, and I like the IFormAPI interface and
concept. I'd like to see more of a move in that direction for the core
facilities. Instead of "write these n lines of ZCML to auto-generate
an edit form for a schema/interface", it should be "write these 5
lines of Python to generate that form, and 1-2 lines of ZCML to
register it, name it, and protect it." And then, as the user may need
to customize the form, they can add to this class instead of having to
span the two worlds of ZCML automation and Python. It's much easier to
go up a good and simple base class tree and read / understand the code
than it is to go through ZCML meta configurations. And it makes the
distance between the main doctest documentation and how things work a
lot shallower. (I liked viewlets a lot more while reading the main
viewlet info file, and liked them less after reading about and
wrestling with their ZCML directives).

--
Jeff Shell


More information about the Zope3-dev mailing list