For the past weeks I've been toying around with egg-based installs of Zope and flexible WSGI-based deployment using PasteDeploy [1]. Both essentially challenge the concept of instances as we know them.

What is an instance?
--------------------

* Start/stop scripts for a pluggable application called Zope

* A collection of "plug-ins" for Zope-the-application (in Zope 2 these
  were called Products, in Zope 3 we say packages) that make up the web
  application.

* Configuration of Zope-the-application (site.zcml)

* Server configuration (zope.conf)

So, an instance actually defines the web application by keeping "plug-ins" in lib/python or Products and by saying how they work together (site.zcml and package-includes). And then instances also define how they're deployed (again site.zcml, and zope.conf).


Pluggable app vs. libraries
---------------------------

While the idea of Zope as pluggable-application may have its value to some people, a library approach is much more natural to most Python developers.

Imagine you're writing a GUI application. Without question you'd use some sort of GUI toolkit (e.g. wxPython). Would you expect you would have to hook into the the "wxPython application" as a plug-in? Isn't it more natural that you simply write your application and just use the wxPython *library* wherever necessary? Indeed it seems so, and that's probably why it really is that way.

Zope 3 has now been successfully split up into separate pieces: individual libraries. I'd therefore like to propose an alternate approach to developing web applications with Zope: the library one, rather than the pluggable app one.

The good news is that Zope is already there (thanks to the split-up). We just need to slightly change the way we develop applications with it.


Writing an application using the Zope libraries
-----------------------------------------------

How would you actually write an application that *uses* Zope instead of plugging into it? Simple. You do what any other Python developer does: start a package. Then proceed as follows:

1. Since you're using Zope you'll put all the kinds of Zope-based components in that package that you know: ZODB-persistent classes, views, Page Templates, etc. The more Zope 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 distutils/setuptools.

2. You configure the application's components. Surely you want the Zope publisher, the Zope security machinery, etc. So before configuring the applications own components, you want to load those components from Zope that you're reusing. That means your package's configure.zcml file will start off by including lots of Zope bits and pieces. Then it might configure all the components that are specific to your application.

3. You make the application startable. A GUI application would simply have a main() routine. A modern web application has a WSGI application factory. So, you'd write a WSGI application factory that does a few but necessary steps (usually that only involves parsing zope.conf and site.zcml) and then hands over the work to Zope's own WSGIPublisherApplication.

(If that does sound like a lot of typing to you, don't worry. We'll solve that problem later.)


The application is a single package!
------------------------------------

So what have we got now? A Python package that defines a WSGI-capable web application. And it's self-consistent! The whole web application is actually defined in that one package plus setup.py (which is needed for dependencies).

If you compare that to the old instance-based approach, this is a *major* leap forward. With traditional instances, your application was made up of whichever plugins you had in lib/python or Products and whether or not they were enabled in site.zcml or package-includes. So developing on an application such as Plone led to "interesting" solutions like having the Products directory be a subversion checkout with lots of externals. I've seen similar solutions in the Zope 3 world, too.

With eggs and and a library approach to Zope, this is a thing of the past: 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.


Deploying the application
-------------------------

Thanks to eggs, the application is easily installed, including its dependencies. Thanks to WSGI and PasteDeploy, the application is also easily deployed:

1. Write a configuration file (e.g. deploy.ini) that connects the application to a WSGI server, like so::

  [app:main]
  use = egg:MyApp

  [server:main]
  use = egg:Paste#http
  host = 127.0.0.1
  port = 8080

2. Write a site.zcml file that includes your application package and contains deploy-specific ZCML directives that don't make sense in the application's configuration. A good example is the a default administrator user account.

3. Write a zope.conf file that configures the ZODB database.

After those three simple steps, you can then lauch the application by invoking Paste::

  $ paster serve deploy.ini

As we've seen, the application definition is clearly separated from the deployment. The application is concealed in the package, the deployment-specific stuff is in three configuration files (deploy.ini, site.zcml, zope.conf).


Automation
----------

What I've sketched out here sounds like a lot of typing. Indeed it is. At least with instances, you get some automation so you won't have to start from scratch. This where zopeproject [2] enters. It basically is mkzopeinstance for the library-based approach. It doesn't create an instance but

a) a Python package with common Zope library dependencies, a configure.zcml that includes the most common Zope libraries and a WSGI application factory that pretty much does the standard things upon startup (load zope.conf, load site.zcml, load ZODB databases).

b) a sample deployment of that application, in other words, a sample deploy.ini, zope.conf, site.zcml.

It also downloads the standard Zope library dependencies. After running zopeproject, you'll have a fully functional Zope-based web application (much like you do after running mkzopeinstance). That means with zopeproject your Zope server will be up and running just as quickly (if not even quicker since it even downloads and installs Zope for you).


Feedback
--------

As much as I see the library-driven approach replace the instance approach, I see zopeproject as the way to get started with an application instead of mkzopeinstance. I would like to ask everyone who's interested in checking it out and give feedback, both on these ideas and on zopeproject specifically.



[1] http://pythonpaste.org/deploy
[2] http://cheeseshop.python.org/pypi/zopeproject

--
http://worldcookery.com -- Professional Zope documentation and training

_______________________________________________
Zope3-dev mailing list
Zope3-dev@zope.org
Unsub: http://mail.zope.org/mailman/options/zope3-dev/archive%40mail-archive.com

Reply via email to