For the past few weeks, I've been working on a real Zope 3 application for a customer. Prior to this, I've just done the little never-completed apps that I've mentioned here, but they were enough to get me some general insight into how things worked.
So on to the experience. Overall, it's been really good. This customer has always edited the bulk of their content via FTP, and our software would parse out the contents and metadata and index it. In Zope 2, knowledge of FTP and catalog indexing were the responsibility of this "wrapped page" object. In Zope 3, FTP views are separate from HTTP and 'Browser' views. Content indexing is now all managed with events, interfaces, and adapters. Common metadata is handled, by default, via object annotations and an IZopeDublinCore adapter that provides easy access to that data. This means that the core class of the base 'model' object is tiny, and its collaborators are what start coming together to provide the application specific functionality.
This customer also had other managed content that they used a web interface to administer. This included structured data like press releases, event calendars, and so on. It also included some major data management regarding company operations. All of this was in a separate interface in the old application, independent of the rest of the content. With Zope 3 we were able to build a custom content management user interface that could access it all. This was done from the ground up. The CMS needs were extremely basic - access the content and edit it. There was no workflow or anything else required. The user interface to administer the content is done in one skin, while the public sees all of the content via a completely different skin. But all of the object access is the same. This is very different than Zope 2, where just about every object inherited the Zope Management Interface. Now, the ZMI is just another skin.
Another Zope 3 advantage over Zope 2 is that it's fairly easy to provide custom views for exceptions. In Zope 2, there was a template called 'standard_error_message' that you might put in a subfolder to customize, and in that template you might try to guess at what the error was or have template-driven logic to respond to a few different errors. Since this was a major web site overhaul, we needed a custom NotFound view that had logic in it that could query a special tool about redirects, and if that wasn't found, show a pretty page specific to the NotFound error. In Zope 3, this is as easy as providing any other web browser view - this one is just bound to an INotFound interface, which is the interface of a core NotFound exception that is raised by the publishing machinery. Since it's just another view, it can be bound to a skin layer and thus only behave this way on the public view of the site but not on the CMS view.
Lastly, in regards to this particular project, it was really easy to layer everything up into a nice stack. There's the core CMS, which we'll use on other projects. On top of that is a layer dealing with common functionality that this customer and its sister companies will all use some (or all) of. Then on top of that is the customer specific layer, with custom skins, views, content components, utility components, and so on. This was all quite easy to set up and build on. This is all possible in Zope 2 - we have written similar stacks - but it was easier in Zope 3. I think this is because of the separation of concerns. It's much easier to take a common component out of one layer and provide a lot of new application specific functionality for it without subclassing. It's all about adaptation.
How might this compare against other systems? I don't know of any other app servers, besides Twisted based ones, that can provide FTP access to content. Zope has provided this since Zope 2.0. I also don't know of any that provide a concept like 'skins'. Since many app servers, even content focused ones, use an RDBMS for storage, I imagine that they provide 'admin' interfaces as a completely different set of components and database queries. For content management, the skins of Zope 3 (and also Plone/CMF and many other Zope 2 based content management systems) allow objects to be dressed up very differently. In this regard, skinning is not just about putting different colors or backgrounds on things. It's about using whole different sets of presentation components for different uses. It's really quite powerful, and I really like that it's built into Zope 3. Zope 3 continues to build on the strong security that has been an integral part of the Zope story dating back to the days even before Principia. The authentication system - actually, a lot of the security system - seems to be a lot more pluggable than even before. Since Zope has been used in major media and government sites since its inception, and knows that restricting access and safely delegating control are important elements to many institutions, it has this part down.
David Heinemeier Hansson, the primary author of Ruby on Rails, was interviewed recently on the O'Reilly Network. In his interview, he talks about the differing experiences between J2EE and PHP development, and how that influenced RoR:
So I was situated at the intersection between two widely popular approaches to software development. The one represented by PHP was quick-n-dirty and the one represented by Java was slow-n-clean. So combining those influences into the ultimate goal of quick-n-clean did give me some confidence that I at least had a shot at appealing to both camps.So how do I think Zope 3 measures up against this? Zope 3 is far from the dirty of quick'n'dirty, but it's not quite quick'n'clean like Rails. The full Zope 3 "stack", which includes the Zope 3 app server (zope.app) is a pretty exhaustive stack which provides a lot of great functionality but it can take some time to grasp. That said, I think one could build a base system build on the core zope system (zope.component, zope.interface, zope.schema, etc), the template system (if desired - zope.tal, zope.tales, zope.pagetemplate), and the storage system (again - if desired, any or all of persistent, transaction, BTrees, etc) and use those as the base for a quick'n'clean system while taking advantage of what Zope's component framework has to offer - interfaces, adaptation, etc. That adaptation is wonderful. There are some other Python systems that do a more comprehensive job, but I find them too complex to grasp.
The full Zope 3 system is not quite slow'n'clean either. It is very clean! In fact, the component architecture is simpler and cleaner in Zope 3.1 than it was in Zope 3.0! A lot of the core concepts have been cleaned up. There is XML based configuration involved. But I don't mind it. In fact, I think that it's good for any system of this size to have component registration and configuration be separate from the regular code importing/loading process. For very small web applications, it feels like overkill. But I'm very grateful for it in an application like this. I used to wage wars against ZCML (the configuration language used for Zope 3 component configuration), but I think that its syntax is now quite manageable and it's very well documented. ZCML, and the large structure of the Zope 3 application server, can make some development slower than a Rails style system, but it is still significantly faster than a J2EE system - you get to use Python (of course), and in fact, the Python code you write is much more 'normal' than comparable Zope 2 code. Concepts such as implicit acquisition are effectively gone, API's are clean... It's quite nice.
The metric that I can use to measure quickness and cleanliness is the fact that three people - only two of them developers, and only one of them having any prior experience with Zope 3 - did this project from scratch in about four weeks. Granted, there were some long days and weekend work in there, and a lot of our internal milestones slipped (or were just pranced over). But we did meet our deadline! As we start working on the solutions for the client's sister companies, the cleanliness factor will really show itself. We've come up with not only a custom solution, but a usable CMS web based interface, utilizing AJAX and providing features such as drag and drop reordering and inline renaming. All of that is pretty admirable and even normal for a few weeks worth of hard work. But to have a reusable stack that provides some major functionality in that time frame as well as a complete solution for one customer? That's hot.