A post came to my attention today covering "Best of breed controllers for MVC Web Frameworks." It covers, again, toolkits like Ruby On Rails, Django, CherryPy, and so on. The author initially treated this as a recent phenomenon of the last few years, but he was quickly corrected by Philip Eby in the first comment.

Publishing objects on a nice URL is nothing new, and one of the best toolkits to do this sprang up in 1996 - Bobo, aka, The Python Object Publisher. In the comments, some of the legends and myths are covered and dispelled concerning Bobo's origins. My former boss and all-around-great-guy Paul Everitt mentions in the comments (and on his on weblog):

I remember thinking last year, after all this time, most packages haven’t caught up to what Jim had on his laptop after the plane ride back. So many systems seem more like the “Gateway” in CGI, than systems that adopt the object model of the web.

A few days ago I started writing a post on my own about my experiences with this back in the mid-nineties. Now that the history of Bobo has been covered elsewhere, I can just tell of my experiences with it prior to my joining Digital Creations in mid 1997.

The problem of "numerous web frameworks" is nothing new for Python. In 1996 I had crafted my own, taking some (very light) inspiration from the great WebObjects. I was aware of this tool "Bobo" but I didn't quite grasp its significance at the time. When I published the first version of my tool, netstijl, to the Python web-sig, Paul responded with a "yeah, we've done that too" reply.

A few months later, at a rarely-paying job high on the east benches of Salt Lake City, I was growing frustrated with an application I was working on. My responsibility was writing a socket server that queried closed-caption text feed archives from television, and returning responses to a Java Applet Client which would show the results and also pull down still images associated with those results. This was before server side Java, RMI, etc. My part of the code was written in Python, and was a good model-controller separation. But the Java client development was coming along atrociously slow. So sometime in early spring, 1997, I decided one day that I was going to turn my work into a web application and not care about the applet.

I turned to Bobo for my work. By the end of the day, the conversion was done. I worked on a new set of controllers for a few hours in the morning, had lunch, and spent the rest of the day making the HTML look pretty.

One Day was all that took.

Over the next couple of weeks, new features were added. The biggest of these was the "advanced search" which used HTML Frames and "multipart/x-mixed-replace" to push data to the client, such as the images that were shown next to the search results. All of this on my model from the socket server implementation, but now published via Bobo and my controllers and templates. In short time, I had done what we were having trouble accomplishing with the Java Applet, but now using just HTML, Bobo and Python 1.3 and 1.4.

Ever since that spring, I have been using that same basic toolkit. In September 1997 I joined Digital Creations as 'Principia 1.0' was being developed, and worked applications built on Principia and Zope (which was the open source Principia) there for the next four years before coming back to Utah to be poor (wink) as both on my own and with a couple of different companies I've continued to develop and deploy Zope based applications. I've done just about every different kind of Zope development imaginable. DTML Scripting, ZClasses (Briefly), ZPatterns (a Philip Eby invention), CMF, scripts and templates over RDBMS based data (often still published along a readable URL!), 'Product based', building our own frameworks over Zope, and through gateways to our own data management frameworks that had little knowledge of Zope but could communicate through a new model layer and take advantage of Zope for managing not only views and web publishing, but for managing transactions.

Other things that made Bobo cool were some of the little features that you didn't necessarily need, but were useful when you did - security and transactions. Security has always been a feature of Bobo, Principia, and Zope. Bobo also came with a transaction manager that - to this day - starts a transaction at the beginning of a request and commits if the response is successful and aborts if there's an error. With it, I never had to worry about half-written data (so long as I was using a persistent database manager), or data being written in one database and not the other... Unless of course that database was pre-InnoDB MySQL or an LDAP directory (and I even made a couple of valiant efforts to do transactional LDAP writing, at least within Zope. They never quite worked properly though).

I remember coming across this feature in 1997, before I joined Digital Creations, and how happy it made me. Web development was still very tough at the time, and I still bore many scars from CGI programming where I'd often have half-written data before an exception happened and I didn't get a full file made. When I started using BoboPOS, the persistence system that became the ZODB (Zope Object Database), such problems magically disappeared!

Bobo was even doing REST-ish communications back in the day. There was a 'bobo Client' library which basically allowed for RPC / Corba-ish communication, but using HTTP as the backbone. Again, this was long before XML, XML-RPC, SOAP, webMethods, ICE, and so on. I used it many times to script batch updates that I needed to make to an application server. I don't have any code in front of me, but basically it looked like this:

john = boboclient.Object('http://www.example.com/people/johndoe') john.setJobTitle(jobtitle='Vice President, Software Engineering')

On the 'Object(...)' call, you could set up authentication parameters, what HTTP method to use, etc. And basically all that the bobo client stuff would do is turn the method call, 'setJobTitle' into a GET or POST to the url with the method name attached. As a GET, it would look like this:

http://www.example.com/people/johndoe/setJobTitle?jobtitle=Vice%20President....

Bobo on the server would then turn that into a traversal path and method call, like:

root()['people']['johndoe'].setJobTitle(jobtitle='Vice President....')

And all that John Doe's class might have to do is something like this:

class Person(...): def setJobTitle(self, jobtitle): """ Update the job title for this person """ self._jobTitle = jobtitle

That's a very simple example, but not really that far of a cry from what I still do today. In fact, using Ajax and Zope 3 has been extremely easy because of things like this, and I have some MochiKit based helpers that let me construct Javascript client objects to server side 'browser views' (which are also being controllers in this case) to do operations that are very similar to the simple example above.

It's now been about nine years since I started programming Python. For almost all of that time, I've developed for the web. And for all but the first seven or eight moths, I've used Bobo or one of its descendants. Now I'm using Zope 3, which is the completely re-architected Zope framework and application server. And I'm amazed at what we've done in the past month and a half on it. We've watched so many frameworks and concepts come and go, go into vogue and then out. All this time, Bobo has been sitting at the heart of Zope and even larger systems built on top of Zope (CMF, Plone, CPS, to name a few), doing the simple job of publishing objects on the web. How complex and overburdened those objects may have gotten in Zope 2 is a different debate. For as long as Django has been alive as an internal project before bursting its way onto the public scene recently, Zope and the CMF have been quietly and steadily managing many large television and newspaper sites around the world.

On fads... I remember fondly when it seemed of utmost importance to make Perl work in or with Zope. And then it was Java - "yeah, but could it work with J2EE / JSP?" and early PHP. But I believe that the core Bobo ideas are still extremely valid. Because although Zope 3 is a new and clean architecture compared to the jungle of Zope 2, the principal ideas (and even some of the very core code) seem to have changed very little, even as other trends have come along for the rest of the Python community to try to duplicate... I never understood servlets in Java. And the Python implementations were even harder to understand. Bobo... I got it.