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!