Death to instances! =================== There. I've said it. You can beat me up now. Finished? Ok, then I can get to my point: I think Zope instances are an overcome concept, now that we've finally sorted out that Zope isn't an application anymore. Confused? Fair enough, I'll explain. Overcoming an identity crisis ----------------------------- Zope is in an identity crisis. Both Zope 2 and 3 don't really know what they want to be. A content management application? An application server? A platform? A set of libraries? They're sort of everything and nothing. In its long life time of almost a decade, Zope has therefore attracted *and* disappointed different kinds of people: * People who really weren't developers were attracted by the ZMI and all the through-the-web stuff, but sooner or later they had to discover the "Z-shaped" learning curve: in the beginning Zope is really easy, but when you get past a certain point it becomes very hard, until you've mastered it. Usually that involved learning a substantial amount of Python (remember, we're talking about non-developers here). * For a long time, Zope was pretty much the only thing out there that did cool web stuff with Python. But by trying to appeal to non-developers in a way that's so un-intuitive to developers (through-the-web development, anyone?), it has scared off so many Pythonistas that Zope, even after trying very very hard with Zope 3, is forever branded as the most un-Pythonic piece of code out there (even if that wasn't even true at the time this prejudicial judgement was conceived...). `Tres Seaver's keynote`_ at this year's `DZUG Tagung`_ in Potsdam revolved around this very problem. At the end, he suggested that Zope should make up its mind as to what it wants to be. His suggestion was that Zope should be a *platform*. Not an application. Not a server. Just a platform .. _Tres Seaver's keynote: http://www.palladion.com/home/tseaver/obzervationz/2007/behind_door_number_3_20070606 .. _DZUG Tagung: http://www.zope.de/8-dzug-tagung * with lots of libraries that help you create a web application (this is what's currently known as Zope 3), * with a particular set of those libraries (and a few legacy ones) that make up a "known good" assembly for a web application platform (this is what's currently known as Zope 2), * but *without* necessarily providing its own HTTP server implementation, its own process management tools, its own ways of installing software. What's important to note here is that Zope would not be an application that "eats" your 3rd party code to be pluggable. Instead, it'd be *you* who would write the web application and this application *happens* to use the Zope platform (the Zope libraries), just like other applications happen to use TurboGears or Pylons. Think of writing a GUI application that happens to use wxPython. Would you expect that you would have to launch the "wxPython-the-application" in order to launch your GUI app? I think not. So what's the problem with instances? ------------------------------------- Primarily an instance is a place that contains your code which is plugged into Zope-the-application. So strictly speaking your code isn't really the application, it's just stuff that plugs into Zope-the-application. And the configuration that's in the instance, too, doesn't configure your application. It configures Zope-the-application. And the scripts that are also in the instance are aptly named "runzope" and "zopectl". Instances therefore embody the concept of Zope-the-application. They're not very helpful in bringing forward the platform idea of Zope. So how would I write an app with *using* Zope instead of a plug-in *for* Zope? ------------------------------------------------------------------------------ Simple. You start by writing Python code. And where does Python code go? Right, into a package. So you start by creating a package. That's right, you don't start by making an instance. You simply start by doing something you'd do with any other piece of Python software you'd write: create a package with code. Naturally you're using Zope, so you'd put all the kinds of Zope-based components in that package that you know: ZODB-persistent classes, views, Page Templates, etc. The more of Zope's components you use, the more dependencies your application will grow, which can all be tracked using the a standard ``setup.py`` script that we know from other setuptools-based distributions. What's the next step? Configuring your application's components. Surely you want to use the Zope publisher so that your views will be found. And you probably want Zope's security machinery as well. So before configuring all the components that you yourself have written, you want to load those components from Zope that you're reusing. So your package's ``configure.zcml`` file will start off by including lots of Zope bits and pieces, perhaps like so:: ... ... Great. Now how do you start your application? Essentially what you'd want during developing time is a web server that processes all requests by sending them to Zope publisher (which will then invoke your application's components). PasteDeploy_ is a small library that helps connecting applications to web servers. It is configured using a simple INI-style configuration file, such as this:: [app:main] use = egg:zope.paste site_definition = configure.zcml file_storage = /path/to/datadir/Data.fs [server:main] use = egg:PasteScript#wsgiutils host = 127.0.0.1 port = 8080 .. _PasteDeploy: http://pythonpaste.org/deploy Here we configure the two bits we want to connect: * the application, represented by ``zope.paste``, a PasteDeploy-friendly frontend for any Zope publisher-based web application, and ``configure.zcml`` of which we've seen an excerpt above. * and the web server, which happens to be a simple one from a package called ``WSGIUtils``. After that little bit of configuration (which might remind you a bit of ``zope.conf``) you can start your application by invoking Paste:: $ paster serve your-app.ini Now the good news: this already works. Today. Automating the common case -------------------------- So all in all, writing an application with Zope-the-platform (instead of writing a plug-in for Zope-the-application) is pretty simple: 1. Start with a package and put your application's code in it. Add to its dependencies as you're using more of Zope's own components. 2. Configure your application's components, not forgetting to configure those components of Zope that you're reusing (the publisher, the security machinery, etc.). This configuration can go right into the application's package as well. 3. Hook the application up to an HTTP server. Done. Admittedly, that's a bit more work than with instances. With instances, you simply invoke ``mkzopeinstance`` and you ended up with a pre-configured runnable Zope-the-application. To get the same kind of convenience for beginners, we'd simply need a ``mkzopeapp`` script that creates a Python package with some pre-made component and server configuration. Good news, everybody! It exists! Here's how you'd get Zope up and running with it. First of all, you'd need to install mkzopeapp_ (it is suggested to perform all of this in a workingenv_ to avoid pollution of your global Python installation):: $ easy_install mkzopeapp .. _workingenv: http://cheeseshop.python.org/pypi/workingenv.py .. _mkzopeapp: http://cheeseshop.python.org/pypi/mkzopeapp Note that this doesn't mean you need to install Zope first or that Zope will be installed in the process. For now, that just installs the script that sets you up with an empty package layout. Now that the ``mkzopeapp`` script is available, we can simply invoke it, just like ``mkzopeinstance``:: $ mkzopeapp MyZopeProj Inside the ``MyZopeProj`` directory, however, it looks nothing like an instance. It's simply a standard Python package layout with a ``setup.py``. The Python package, though, contains a ``configure.zcml`` file that loads the most common Zope components. It also contains a ``develop.ini`` file that contains a simple HTTP server configuration not unlike the one we've seen above. To get the application up and running, we need to install its dependencies (which happens to be a lot of Zope libraries). We do that by activating the package as a development egg:: $ cd MyZopeProj $ python setup.py develop -f http://download.zope.org/distribution The ``-f`` switch tells setuptools where to find the Zope packages. Note that this may take a few minutes until all the packages have been downloaded. When that is done and ``MyZopeProj`` has been activated as an egg, you will also get a new script that you can use to directly start the application:: $ startMyZopeProj Starting server in PID 1217. Starting HTTP server on http://127.0.0.1:8080 Conclusion ---------- As we've seen, writing applications *using* Zope isn't any more difficult than plugging into Zope-the-application, thanks to mkzopeapp_. You might also have realized that this way of arranging a web application makes it much easier to install and distribute: you simply install that one package and it contains a runnable, configured application. And because it lists Zope's libraries as dependencies, they will be installed automatically as well. So you no longer install Zope and *then* add the application code. You install the application, and Zope happens to be pulled in as a consequence. And if your application package specifies a specific version of Zope, people won't have problems by accidentally having installed the wrong version of Zope. I could go on and come up with lots more advantages of the platform-centric view. And certainly there are a few things where instances still deliver more features (debugging comes to mind). Certainly those can be sorted out in the near future, hopefully with your help!