In response to my post about my recent real-world Zope 3 experiences, Martijn Faassen posts his. He covers notes on maturity. Zope 3.1 is quite mature, but there are a couple of small problem areas which we also bumped our heads against - namely the built in form machinery. The default machinery is not bad, but it does seem to be primarily targeted at basic object add/edit forms and introspection. zope.formlib, an extension developed by Zope Corporation and released to the public. We did not use zope.formlib, as it requires Python 2.4 and I thought we were having issues with Zope 3.1 and Python 2.4 on our development server. I think I was wrong about that, but I was under pressure to get this project underway so I stuck with the safe solution. I was actually trying to get zc.catalog running, and may have just not configured things properly. Oh well. Now I should have time to evaluate future plans.
I wasn't that involved with some of the heavy form development, but a co-worker was, and I think he would have benefited from zope.formlib.
A bad thing, or annoyance, about Zope 3: at this time, there doesn't seem to be any ZODB import/export functionality like there is in Zope 2. Some people who have written custom applications like bug trackers have written custom XML import/export facilities for their application, but that doesn't help for content management situations. fssync, a tool for moving Zope 3 objects between file system and ZODB, seems to be missing from the distribution. I'm not sure what to do here when content has to move between servers. I'm guessing a full copy of the ZODB's storage file is what's in order?
A good thing, though, about Zope 3: generations. A good thing with an object database behind a language like Python is that your persistent data can be pretty free-form. But as applications grow, data structures change. For our Zope 2 based RDBMS applications, we wrote a tool called 'updater' which contained methods that could be selectively executed to update RDMBS data and structure (and also could do some ZODB tweaks as well). For ZODB applications, with Zope 1 and 2 you'd often provide some persistent protocol tweaks, such as __getstate__ and __setstate__ methods that could rewrite the data on the way to/from the ZODB, and in that way they could reflect structural changes. Or you could write hooks in your code to check the existence of a new attribute, or its structure, and respond accordingly. But it wasn't the most elegant solution - how long should those hooks stay around? How are they ultimately impacting the speed of data storage and retrieval? Enter generations. With generations, you create a schema manager which basically specifies a unique key for your application or package (usually a dotted Python name, like 'zope.app.generations' or 'foo.bar.contentking'), the minimum supported 'generation' of your package, and the latest 'generation'. You also provide evolution modules with the name of their generation, like 'evolve1.py' and 'evolve8.py'. When Zope 3 starts up, it looks through these generation schema managers and will run the evolution code in order to catch up to the minimum supported generation. It provides utilities for the evolution code to locate objects matching a certain criteria or implementing a certain interface. This solves many problems that afflict the __getstate__/__setstate__ solutions, since the evolution scripts stay around forever (making it possible to upgrade really old deployments) while also executing only once. Application code shouldn't have to be performing checks like:
if item.preferredFormat.startswith('Y'): # Waaa, old format. Rewrite this to the new way ...And with Zope 3's generations support, it doesn't have to.
Oh yeah, Martijn also mentions his extended catalog queries experience in Zope 3 - code I'd love to see. Querying a catalog is not all that obvious right now. but I should say that it does work quite nice for full text indexing.