|
|
|
ZCML needs to do lessThe separation of component wiring from the actual component code is a strong theme in Zope 3. To do the wiring, it was decided very early on not to use Python but something more restrictive. Extensible, but restrictive in terms of its abilities. The result was a configuration engine that allows component configuration and registration ("the wiring") through simple configuration files. The only backend right now, ZCML, uses an XML syntax for that. Common criticismNot everyone has been happy with how ZCML turned out. From what I've seen, the common criticism is two-fold: The Python purists usually complain that the XML is ugly, that it's hard to read, hard to write, just awkward for Python programmers, and so on. They have some points there, but it's really hard to please a Python programmer in aesthetics. (It's all Guido's fault, really. The Perl folk will put up with almost anything!) I'll therefore not get into this debate, at least not now. I'm speculating that the die-hard Zope 2 coders probably don't worry too much about the aesthetics (It's not like Zope 2 code ever looked good anyways...). According to my observations, their major complaint is the indirection ZCML introduces. The fact that component registration is needed, separated from the code, isn't as much as a problem as the fact that many important component issues lie in ZCML and not in Python. That makes reading and therefore understanding, maintaining and debugging code harder. Policy vs. automation and shifting the focus of ZCMLI think the latter criticism has a point. Right now, ZCML is used for both policy and automation. I have come to believe that ZCML's focus should only be policy because automation is better done in Python. For example, I think ZCML should try to do much less on-the-fly construction of objects, let alone whole classes. Ideally, things that are registered through ZCML are importable somewhere from Python (I realize that in reality it would be a bit difficult to do everywhere). Basically, ZCML directives should become mere on/off switches which is what 90% of policy is about: Switching on a certain component in favour of another one. These sort of on/off switches are typically ZCML one-liners, such as: <adapter factory=".foo.BarFooAdapter" /> <utility factory=".foo.FooUtility" /> The rest of the information (what is adapted and what is provided) doesn't concern ZCML as much as it concerns the Python code, which is where one has to deal with the adapted API and the to-be-provided API after all:
class BarFooAdapter(object):
adapts(IBar)
implements(IFoo)
... # deal with IBar objects here and provide IFoo API
class FooUtility(object):
implements(IFoo)
... # provide IFoo API here
The good news is that the above is already possible. In my opinion, it should become the preferred way of doings things (perhaps even the only one). Less magic in ZCML, more explicitness in PythonA good example of what can go wrong in a ZCML directive are browser pages. The on-the-fly creation of classes there definitely needs to end since the extent to how much magic this entails is just ridiculous. It was also awfully painful when we started bringing ZCML to Zope 2 via Five (and it continues to be painful!). Introducing some explicitness will only cost a few lines more Python code, though (optional) base classes should help a great deal there. After all, this kind of automation is what base classes are very good for, even in the Component Architecture! Another aspect are the names of browser pages. Unlike named utilities, which don't care about the name they're registered with, it does matter to browser pages what name they have (if not to themselves, then to other browser page "siblings"). Imagine the following (over-simplified) example:
class FooPages(BrowserView):
def form(self):
return u'<html>...<form action="@@update.html">...</form>...</html>'
def update(self, data):
self.context.data = data
self.request.response.redirect('@@index.html')
def index(self):
return u'<html>...</html>'
How do you know that @@update.html actually refers to the update method and that @@index.html refers to the index method here? You don't by looking at the Python code, even though that's where this information would be quite useful. Given Python 2.4's decorator abilities, we can provide such a feature in a nice syntactic form, for example:
class FooPages(Pages):
adapts(IFoo, IBrowserRequest)
@page(u'edit.html')
def form(self):
return u'<html>...<form action="@@update.html">...</form>...</html>'
@page(u'update.html')
def update(self, data):
self.context.data = data
self.request.response.redirect('@@index.html')
@page(u'index.html')
def index(self):
return u'<html>...</html>'
The registration would look like that: <browser:pages class=".browser.FooPages"> <require permission="zope.View" attributes="index" /> <require permission="zope.ManageContent" attributes="form update" /> </browser:pages> Note that we still need and want the security here. Policy is not always about on/off. Security in Zope's understanding, for example, is application policy and therefore doesn't belong in Python. I would say that security is the only big exception to the on/off rule and it's a traditionally very import one in Zope. Also note how this fictitious directive above has a usage similar to the content directive (regarding the require subdirective). Repeating existing patterns where possible lowers the barrier tremendously, which brings us right to the next topic: Reducing directive and directive functionality proliferationFollowing the ZCML-should-not-create-things-on-the-fly paradigm, we can also get rid of some ZCML directives or directive functionality easily and thus reduce the directive proliferation that has happened over the years. As someone who has written a book and given trainings on Zope 3, I can't tell you how important that is from both a teaching and learning point of view. The more people can reuse what they've learned already when learning about new things, the easier it is for them. Having to write a line more here and there for explicitness' sake is small price to pay in return. In a current proposal of mine, I already suggest to get rid of browser:layer and browser:skin directives. They were quite a low-hanging fruit, given the simplifications that the skinning system had already seen previously. Half of this proposal is actually about passing on that simplification from under the hood on to the developer. Here are some other directives and some directive functionality that are on my preliminary hitlist:
In total that makes 15 directives of roughly 80 we have in Zope 3.2. If we'd get rid of all 15 of them, we'd end up with 65 which would still be a lot, but also a lot less than 80. Guidelines for new packagesIn conclusion, we can compile some guidelines for writing new packages from the above:
Comments
Posted by Philipp von Weitershausen @ 12/14/2005 07:36 AM.
-
Categories:
Zope 3
-
2 comments
|
Latest blog posts
Latest animations
Latest documents
|
||