I'm still slogging away on multiple projects, trying to bring a big mess of scripts under some more component-like control for Zope 2. It's working out, somewhat. It's nice to have some of the big pieces of code out of the ZODB and under CVS control, and it's also nice to be able to reorganize very large scripts into classes, where refactoring is easier to apply (thus breaking the big algorithm into more manageable chunks).
This week, there is some interesting code to compare: the inheritence-and-member-heavy ZWiki for Zope 2 versus the interoperable-components of ZWiki for Zope 3.
Before I begin, however, I want to discuss my, um, "prejudices" against Wikis, and other disclosures. Firstoff, one has only to visit a page like ExtremeNormalForm in the big c2.com Wiki to understand my frustrations. This page is marked as recommended on the big WikiPagesAboutRefactoring page. The WPAR page itself is a frustrating exercise, as a big batch of bulleted lists, slightly organized, with little or no descriptions next to the links. Except for a word like Recommended. "Aha!", I think, "here's a good page to keep around when thinking about database design". Wrong. I click on it, and get a poem. It's a clever poem and means well, but it wasn't nearly what I was looking for. So I click on ExtremeNormalFormCommentary. Alright! Here's some meat in the form of a discussion. Ummm, drat, it takes a while to then get to ExtremeNormalFormDefined. The first thing THIS tells me is to see ExtremeNormalFormDefinitions. Which turns out to be about as useful as ExtremeNormalFormCommentary, only less so. So, I realize that this is not at ALL what I was looking for, I have not found any good refactoring thoughts, and I'm extra cranky about the Wiki telling me this was a recommended page. What was I wanting? A real narrative. Something to tell me "this is what this really is" in a cohesive document. Instead, I'm clicking and trying to parse page after page in a circular pattern, with no indication about whether ExtremeNormalForm, ExtremeNormalFormDefined, or ExtremeNormalFormDefinitions, is going to be the real page that I'm looking for - especially because all of them seem so helpful in their title.
Now, I know that Wiki experiences don't have to be this bad. But they usually are. Some are well maintained (the Zope 3 wiki is actually kept up pretty well). But all too often, the experience lapses, and you have four pages covering a single topic, none of which give any useful information to a casual visitor that isn't in on the secret Wiki club. Page after page of negative surprises. And don't get me wrong - I've gotten some really good information out of the Portland Pattern Repository wiki, but it can often be an arduous experience.
In any case, I do know that Wikis have their purpose and some of them are quite good. And, in any case, this entry is really about an architectural comparison between the primary Wiki implementation that exists for Zope 2, and one that was written for Zope 3 (the component architecture based Zope re-implementation). A dangerous thing to perceive is that criticism of Zope 2 and software written for it, in comparison to Zope 3, means that Zope 2 is bad. We're serving some huge sites on Zope 2, and have often been able to deliver full featured applications quickly on this platform that have run for months and years. But, there are some known issues with the way that Zope 2 development has progressed and how that tends to impact software written for it.
Zope 2 often makes it easy to do the "just lump everything into a class or into a fleet of mixins" style of development, which is how much of the Zope 2 codebase is written. While Zope 2 still works quite well, experience has taught us the limits of this system. It's often desirable to defer action of to delegates and helper objects. But making registries for those objects and being able to configure/register new helpers is not an easy task in Zope 2. It's doable, but (especially without a configuration language), it can become dangerously fragile. In any case, it's interesting to compare the 'ZWikiPage' class from ZWiki for Zope 2 - with 10 direct superclasses - to the 'WikiPage' class from ZWiki for Zope 3, with only one direct superclass (Persistent). The ZWikiPage class for Zope 2 is huge - even without its superclasses - as it pushes everything needed to be a Wiki page AND a Zope Object into this one class. And if one wants to customize the class, by adding or changing the available renderers (to include reStructuredText support, for example), one is typically told "just add another method to the class and change the static class member that lists the rendering options". Well yes, it is an easy way to work, but it presents new software configuration problems. If I add a new to ZWikiPage 0.17.0, and 0.18.0 gets released, I have to manually move my changes over to the new code. Again - Zope 2 makes this mode of development easy, perhaps too easy. Much of my own code has suffered from similar problems in the past because it was the easiest thing to do.
But it seems the tide is turning against this style of development. And it has been for some time. At times, the tide seems to be against Object Oriented Programming itself. Personally, I don't think OO is bad, nor that it's going to go away any time soon, but I can see the problems people have with it. Big heavy classes, heavy inheritance trees/mixins, it all becomes too easy to do. As Todd Coram once explained to me, it's as though the craze at one time was that a juice bottle would know how to drink itself and throw itself away, before everyone realized that it really just needed to know what to do when something else drank it, and it certainly didn't need to know anything about throwing itself away.
One of the more famous Design Patterns is the Adapter. Zope 3 uses these with a vengeance. One of the principal benefits is that it's so much easier to write a business / content object as doing just what that object is interested in, and then write adapters to make other parts of the system happy with that object. Let's look at the wikipage.py module from the Zope 3 version of ZWiki again. The WikiPage class, as noted above, has "Persistent" as its only superclass. Furthermore, it has very few class members. Looking at the rest of the module, we see a lot of Adapters. One adapter makes a wiki page look like a readable file, one makes it look like a writable file. One adapts the wiki page to the expectations of the text indexing system. Another one deals with email subscriptions, and another one deals with events (and uses those events to send out emails to subscribed parties). So what's the big deal here compared with ZWikiPage.py from the ZWiki for Zope 2? Well firstoff, the code is easier to navigate. MailSubscriptions.addSubscriptions is much easier to pick out of a source code browser than trying to find addSubscriptions from a monstrously large list of methods. Secondly, I can replace any of these classes easily with my own code in my own module, using Zope 3's configuration language.
Likewise, all of the renderers for the Zope 2 implementation are thrown into the big ZWikiPage class, and short of modifying the code itself or doing some monkey patching, there's nothing you can do to add to that list easily. In the ZWiki code for Zope 3, renderers are also farmed out as separate little objects, and configured as such. If I *shudder* wanted to add WWML as a new rendering type, I could write my own module/package and register it as a renderer through the configuration language. Here, again, I wouldn't have to touch the existing ZWiki code (either directly or through monkey patching).
Well, the other big important part of a Wiki page is viewing it (and editing, I suppose). A lot of the code in ZWikiPage.py (Zope 2) version centers around this. But, for better or worse, it's intermingled with all of the other ZWikiPage responsibilities. The componentized ZWiki moves this responsibility into a collection of web browser view components, one of my favorite Zope 3 features. Sometimes, a simple template is all that's needed to make a "view" for some base business/content object. Other times, so much more is needed. Views are a special type of adapter for adapting content to various output mechanisms - web browsers, FTP clients, XML-RPC, and more. Look at the wikipage browser views - here again are a bunch of dedicated classes. Some deal with setting up the mail subscriptions, others deal with adding comments to a page, and others even provide custom Browser Widgets. And of course, there is a view object to deal with rendering a Wiki page and generating all of the Wiki links. If one looks at the view code, you realize that none of it knows about StructuredText, reStructuredText, and so on. It asks the registry that I mentioned earlier. It uses the registry both to list the available rendering options, and to get the selected renderer and use that to generate the primary HTML.
So, with all of that touched on, what are some of the downsides to Zope 3 development? Well, there's the configuration language, ZCML. ZCML is necessary, however. It's what glues all of these things together. It's how you really register all of these little classes and objects into the global framework. It's something we have to live with, and it has a very flexible design. But, at the same time, it sure is a lot of typing that needs to be done in order to put all of this stuff together. It's Zope 3's most powerful feature (because it gives total control over configuration to anyone who wants it), but I still worry that it will also be a big stumbling block for new developers.
On the upside, all of this yields a very flexible and powerful system. Through the use of Adapters and Views, you can add all sorts of new functionality to software, including adding new XML-RPC interfaces to, oh, whatever you want. You can make distributable versions of Zope that are preconfigured to run a specific application (you can do this now, but Zope 3 makes it easier through its configuration language). If other code is written to use registries, adapters, etc, it's usually easier to extend by registering new components to be used with it. There are a lot of strong possibilities.