<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xmlns:planet="http://planet.intertwingly.net/" xmlns:indexing="urn:atom-extension:indexing" indexing:index="no"><access:restriction xmlns:access="http://www.bloglines.com/about/specs/fac-1.0" relationship="deny"/>
  <title>Planet Pypefitters</title>
  <updated>2010-03-10T17:15:12Z</updated>
  <generator uri="http://intertwingly.net/code/venus/">Venus</generator>
  <author>
    <name>Tres Seaver</name>
    <email>tseaver@agendaless.com</email>
  </author>
  <id>http://planet.pypefitters.org/atom.xml</id>
  <link href="http://planet.pypefitters.org/atom.xml" rel="self" type="application/atom+xml"/>
  <link href="http://planet.pypefitters.org/" rel="alternate"/>

  <entry xml:lang="en">
    <id>http://blog.repoze.org/Zope.de%20Reviews%20BFG%20Book/</id>
    <link href="http://blog.repoze.org/Zope.de%20Reviews%20BFG%20Book/" rel="alternate" type="text/html"/>
    <title xml:lang="en">Zope.de Reviews BFG Book</title>
    <content type="xhtml" xml:lang="en"><div xmlns="http://www.w3.org/1999/xhtml"><p>Jan Ulrich Hasecke <a class="reference external" href="http://www.zope.de/redaktion/dzug/nachrichten/bbthe-repoze-bfg-web-application-frameworkab-von-chris-mcdonough">reviews the repoze.bfg book</a>  via the Zope.de website (<a class="reference external" href="http://translate.google.com/translate?u=http%3A%2F%2Fwww.zope.de%2Fredaktion%2Fdzug%2Fnachrichten%2Fbbthe-repoze-bfg-web-application-frameworkab-von-chris-mcdonough&amp;sl=de&amp;tl=en&amp;hl=&amp;ie=UTF-8">English translation</a>).</p></div>
    </content>
    <updated>2010-03-06T05:00:00Z</updated>
    <author>
      <name>Agendaless</name>
    </author>
    <source>
      <id>http://blog.repoze.org/index.atom</id>
      <link href="http://blog.repoze.org" rel="alternate" type="text/html"/>
      <link href="http://blog.repoze.org/index.atom" rel="self" type="application/atom+xml"/>
      <title xml:lang="en">Repoze Blog RSS Feed</title>
      <updated>2010-03-06T05:00:00Z</updated>
    </source>
  </entry>

  <entry xml:lang="en">
    <id>http://blog.ianbicking.org/?p=158</id>
    <link href="http://blog.ianbicking.org/2010/02/10/why-toppcloud-not-agnostic/" rel="alternate" type="text/html"/>
    <link href="http://blog.ianbicking.org/2010/02/10/why-toppcloud-not-agnostic/#comments" rel="replies" type="text/html"/>
    <link href="http://blog.ianbicking.org/2010/02/10/why-toppcloud-not-agnostic/feed/atom/" rel="replies" type="application/atom+xml"/>
    <title xml:lang="en">Why toppcloud (Silver Lining) will not be agnostic</title>
    <summary xml:lang="en">I haven’t received a great deal of specific feedback on toppcloud (update: renamed Silver Lining), only a few people (Ben Bangert, Jorge Vargas) seem to have really dived deeply into it.  But — and this is not unexpected — I have already gotten several requests about making it more agnostic with respect to… stuff. [...]</summary>
    <content type="xhtml" xml:lang="en"><div xmlns="http://www.w3.org/1999/xhtml"><div class="document">
<p>I haven’t received a great deal of <em>specific</em> feedback on toppcloud (<strong>update</strong>: renamed Silver Lining), only a few people (Ben Bangert, Jorge Vargas) seem to have really dived deeply into it.  But — and this is not unexpected — I have already gotten several requests about making it more agnostic with respect to… stuff.  Maybe that it not (at least forever) require Ubuntu.  Or maybe that it should support different process models (e.g., threaded and multiple processes).  Or other versions of Python.</p>
<p>The more I think about it, and the more I work with the tool, the more confident I am that toppcloud should not be agnostic on these issues.  This is not so much about an "opinionated" tool; toppcloud is not actually very opinionated.  It’s about a well-understood system.</p>
<p>For instance, Ben noticed a problem recently with <a class="reference external" href="http://code.google.com/p/modwsgi/issues/detail?id=177">weird import errors</a>.  I don’t know <em>quite</em> why mod_wsgi has this particular problem (when other WSGI servers that I’ve used haven’t), but the fix isn’t that hard.  So Ben <a class="reference external" href="http://bitbucket.org/ianb/toppcloud/changeset/27a470352a5e/">committed a fix</a> and the problem went away.</p>
<p>Personally I think this is a bug with mod_wsgi.  Maybe it’s also a Python bug.  But it doesn’t really matter.  When a bug exists it "belongs" to everyone who encounters it.</p>
<p>toppcloud is not intended to be a transparent system.  When it’s working correctly, you should be able to ignore most of the system and concentrate on the relatively simple abstractions given to your application.  So if the configuration reveals this particular bug in Python/mod_wsgi, then the bug is essentially a toppcloud bug, and toppcloud should (and <em>can</em>) fix it.</p>
<p>A more flexible system can ignore such problems as being "somewhere else" in the system.  Or, if you don’t define these problems as someone else’s problem, then a more flexible system is essentially always broken somewhere; there is always some untested combination, some new component, or some old component that might get pushed into the mix.  Fixes for one person’s problem may introduce a new problem in someone else’s stack.  Some fixes aren’t even clear.  toppcloud has Varnish in place, so it’s quite clear where a <a class="reference external" href="http://bitbucket.org/ianb/toppcloud/changeset/614d5366be67/">fix related to Django and Varnish configuration goes</a>.  If these were each components developed by different people at different times (like with buildout recipes) then fixing something like this could get complicated.</p>
<p>So I feel very resolved: toppcloud will hardcode everything it possibly can.  Python 2.6 and only 2.6!  (Until 2.7, but then <strong>only 2.7</strong>!).  Only Varnish/Apache/mod_wsgi.  I haven’t figured out threads/processes exactly, but once I do, there will be only one way!  And if I get it wrong, then everyone (<strong>everyone</strong>) will have to switch when it is corrected!  Because I’d much rather have a system that is inflexible than one that doesn’t work.  With a clear and solid design I think it is feasible to get this to work, and that is no small feat.</p>
<p>Relatedly, <a class="reference external" href="http://blog.ianbicking.org/2010/02/09/leaving-topp/comment-page-1/#comment-151194">I think I’m going to change the name of toppcloud</a>, so ideas are welcome!</p>
</div></div>
    </content>
    <updated>2010-03-06T00:32:29Z</updated>
    <published>2010-02-10T06:41:45Z</published>
    <category scheme="http://blog.ianbicking.org" term="Programming"/>
    <category scheme="http://blog.ianbicking.org" term="Python"/>
    <category scheme="http://blog.ianbicking.org" term="Web"/>
    <category scheme="http://blog.ianbicking.org" term="silverlining"/>
    <author>
      <name>Ian Bicking</name>
      <uri>http://blog.ianbicking.org</uri>
    </author>
    <source>
      <id>http://blog.ianbicking.org/feed/atom/</id>
      <link href="http://blog.ianbicking.org" rel="alternate" type="text/html"/>
      <link href="http://blog.ianbicking.org/feed/atom/" rel="self" type="application/atom+xml"/>
      <title xml:lang="en">Ian Bicking: a blog</title>
      <updated>2010-03-06T00:32:29Z</updated>
    </source>
  </entry>

  <entry xml:lang="en">
    <id>http://blog.ianbicking.org/?p=143</id>
    <link href="http://blog.ianbicking.org/2010/02/05/toppcloud-and-django/" rel="alternate" type="text/html"/>
    <link href="http://blog.ianbicking.org/2010/02/05/toppcloud-and-django/#comments" rel="replies" type="text/html"/>
    <link href="http://blog.ianbicking.org/2010/02/05/toppcloud-and-django/feed/atom/" rel="replies" type="application/atom+xml"/>
    <title xml:lang="en">toppcloud (Silver Lining) and Django</title>
    <summary xml:lang="en">I wrote up instructions on using toppcloud (update: renamed Silver Lining) with Django.  They are up on the site (where they will be updated in the future), but I’ll drop them here too…

Creating a Layout
First thing you have to do (after installing toppcloud of course) is create an environment for your new application.  [...]</summary>
    <content type="xhtml" xml:lang="en"><div xmlns="http://www.w3.org/1999/xhtml"><div class="document">
<p>I wrote up instructions on using <a class="reference external" href="http://blog.ianbicking.org/2010/01/29/new-way-to-deploy-web-apps/">toppcloud</a> (<strong>update</strong>: renamed Silver Lining) with Django.  They are <a class="reference external" href="http://toppcloud.colorstudy.com/django-quickstart.html">up on the site</a> (where they will be updated in the future), but I’ll drop them here too…</p>
<div class="section" id="creating-a-layout">
<h2>Creating a Layout</h2>
<p>First thing you have to do (after installing toppcloud of course) is create an environment for your new application.  Do that like:</p>
<pre class="literal-block">$ toppcloud init sampleapp
</pre>
<p>This creates a directory <tt class="docutils literal"><span class="pre">sampleapp/</span></tt> with a basic layout.  The first thing we’ll do is set up version control for our project. For the sake of documentation, imagine you go to <a class="reference external" href="http://bitbucket.org">bitbucket</a> and create two new repositories, one called <tt class="docutils literal"><span class="pre">sampleapp</span></tt> and another called <tt class="docutils literal"><span class="pre">sampleapp-lib</span></tt> (and for the examples we’ll use the username <tt class="docutils literal"><span class="pre">USER</span></tt>).</p>
<p>We’ll go into our new environment and use these:</p>
<pre class="literal-block">$ cd sampleapp
$ hg clone http://bitbucket.org/USER/sampleapp src/sampleapp
$ rm -r lib/python/
$ hg clone http://bitbucket.org/USER/sampleapp-lib lib/python
$ mkdir lib/python/bin/
$ echo "syntax: glob
bin/python*
bin/activate
bin/activate_this.py
bin/pip
bin/easy_install*
" &gt; lib/python/.hgignore
$ mv bin/* lib/python/bin/
$ rmdir bin/
$ ln -s lib/python/bin bin
</pre>
<p>Now there is a basic layout setup, with all your libraries going into the <tt class="docutils literal"><span class="pre">sampleapp-lib</span></tt> repository, and your main application in the <tt class="docutils literal"><span class="pre">sampleapp</span></tt> repository.</p>
<p>Next we’ll install Django:</p>
<pre class="literal-block">$ source bin/activate
$ pip install Django
</pre>
<p>Then we’ll set up a standard Django site:</p>
<pre class="literal-block">$ cd src/sampleapp
$ django-admin.py sampleapp
</pre>
<p>Also we’d like to be able to import this file.  It’d be nice if there was a <tt class="docutils literal"><span class="pre">setup.py</span></tt> file, and we could run <tt class="docutils literal"><span class="pre">pip</span> <span class="pre">-e</span> <span class="pre">src/sampleapp</span></tt>, but <tt class="docutils literal"><span class="pre">django-admin.py</span></tt> doesn’t create that itself.  Instead we’ll get that on the import path more manually with a <tt class="docutils literal"><span class="pre">.pth</span></tt> file:</p>
<pre class="literal-block">$ echo "../../src/sampleapp" &gt; lib/python/sampleapp.pth
</pre>
<p>Also there’s the tricky <tt class="docutils literal"><span class="pre">$DJANGO_SETTINGS_MODULE</span></tt> that you might have had problems with before.  We’ll use the file <tt class="docutils literal"><span class="pre">lib/python/toppcustomize.py</span></tt> (which is imported everytime Python is started) to make sure that is always set:</p>
<pre class="literal-block">$ echo "import os
os.environ['DJANGO_SETTINGS_MODULE'] = 'sampleapp.settings'
" &gt; lib/python/toppcustomize.py
</pre>
<p>Also we have a file <tt class="docutils literal"><span class="pre">src/sampleapp/sampleapp/manage.py</span></tt>, and that file doesn’t work <em>quite</em> how we’d like.  Instead we’ll put a file into <tt class="docutils literal"><span class="pre">bin/manage.py</span></tt> that does the same thing:</p>
<pre class="literal-block">$ rm sampleapp/manage.py
$ cd ../..
$ echo '#!/usr/bin/env python
from django.core.management import execute_manager
from sampleapp import settings
if __name__ == "__main__":
    execute_manager(settings)
' &gt; bin/manage.py
$ chmod +x bin/manage.py
</pre>
<p>Now, if you were just using plain Django you’d do something like run <tt class="docutils literal"><span class="pre">python</span> <span class="pre">manage.py</span> <span class="pre">runserver</span></tt>.  But we’ll be using <tt class="docutils literal"><span class="pre">toppcloud</span> <span class="pre">serve</span></tt> instead, which means we have to set up the two other files toppcloud needs: <tt class="docutils literal"><span class="pre">app.ini</span></tt> and the runner.  Here’s a simple <tt class="docutils literal"><span class="pre">app.ini</span></tt>:</p>
<pre class="literal-block">$ echo '[production]
app_name = sampleapp
version = 1
runner = src/sampleapp/toppcloud-runner.py
' &gt; src/sampleapp/toppcloud-app.ini
$ rm app.ini
$ ln -s src/sampleapp/toppcloud-app.ini app.ini
</pre>
<p>The file <em>must</em> be in the "root" of your application, and named <tt class="docutils literal"><span class="pre">app.ini</span></tt>, but it’s good to keep it in version control, so we set it up with a symlink.</p>
<p>It also refers to a "runner", which is the Python file that loads up the WSGI application.  This looks about the same for any Django application, and we’ll put it in <tt class="docutils literal"><span class="pre">src/sampleapp/toppcloud-runner.py</span></tt>:</p>
<pre class="literal-block">$ echo 'import django.core.handlers.wsgi
application = django.core.handlers.wsgi.WSGIHandler()
' &gt; src/sampleapp/toppcloud-runner.py
</pre>
<p>Now if you want to run the application, you can:</p>
<pre class="literal-block">$ toppcloud serve .
</pre>
<p>This will load it up on <tt class="docutils literal"><span class="pre">http://localhost:8080</span></tt>, and serve up a boring page.  To do something interesting we’ll want to use a database.</p>
</div>
<div class="section" id="setting-up-a-database">
<h2>Setting Up A Database</h2>
<p>At the moment the only good database to use is PostgreSQL with the PostGIS extensions.  Add this line to <tt class="docutils literal"><span class="pre">app.ini</span></tt>:</p>
<pre class="literal-block">service.postgis =
</pre>
<p>This makes the database "available" to the application.  For development you still have to set it up yourself.  You should create a database <tt class="docutils literal"><span class="pre">sampleapp</span></tt> on your computer.</p>
<p>Next, we’ll need to change <tt class="docutils literal"><span class="pre">settings.py</span></tt> to use the new database configuration.  Here’s the lines that you’ll see:</p>
<pre class="literal-block">DATABASE_ENGINE = ''           # 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'.
DATABASE_NAME = ''             # Or path to database file if using sqlite3.
DATABASE_USER = ''             # Not used with sqlite3.
DATABASE_PASSWORD = ''         # Not used with sqlite3.
DATABASE_HOST = ''             # Set to empty string for localhost. Not used with sqlite3.
DATABASE_PORT = ''             # Set to empty string for default. Not used with sqlite3.
</pre>
<p>First add this to the top of the file:</p>
<pre class="literal-block">import os
</pre>
<p>Then you’ll change those lines to:</p>
<pre class="literal-block">DATABASE_ENGINE = 'postgresql_psycopg2'
DATABASE_NAME = os.environ['CONFIG_PG_DBNAME']
DATABASE_USER = os.environ['CONFIG_PG_USER']
DATABASE_PASSWORD = os.environ['CONFIG_PG_PASSWORD']
DATABASE_HOST = os.environ['CONFIG_PG_HOST']
DATABASE_PORT = ''
</pre>
<p>Now we can create all the default tables:</p>
<pre class="literal-block">$ manage.py syncdb
Creating table auth_permission
Creating table auth_group
Creating table auth_user
Creating table auth_message
Creating table django_content_type
Creating table django_session
Creating table django_site
...
</pre>
<p>Now we have an empty project that doesn’t do anything.  Let’s make it do a little something (this is all really based on <a class="reference external" href="http://docs.djangoproject.com/en/dev/intro/tutorial01/">the Django tutorial</a>).</p>
<pre class="literal-block">$ manage.py startapp polls
</pre>
<p>Django magically knows to put the code in <tt class="docutils literal"><span class="pre">src/sampleapp/sampleapp/polls/</span></tt> — we’ll setup the model in <tt class="docutils literal"><span class="pre">src/sampleapp/sampleapp/polls/models.py</span></tt>:</p>
<pre class="literal-block">from django.db import models

class Poll(models.Model):
    question = models.CharField(max_length=200)
    pub_date = models.DateTimeField('date published')

class Choice(models.Model):
    poll = models.ForeignKey(Poll)
    choice = models.CharField(max_length=200)
    votes = models.IntegerField()
</pre>
<p>And activate the application by adding <tt class="docutils literal"><span class="pre">’sampleapp.polls’</span></tt> to <tt class="docutils literal"><span class="pre">INSTALLED_APPS</span></tt> in <tt class="docutils literal"><span class="pre">src/sampleapp/sampleapp/settings.py</span></tt>.  Also add <tt class="docutils literal"><span class="pre">‘django.contrib.admin’</span></tt> to get the admin app in place.  Run <tt class="docutils literal"><span class="pre">manage.py</span> <span class="pre">syncdb</span></tt> to get the tables in place.</p>
<p>You can try <tt class="docutils literal"><span class="pre">toppcloud</span> <span class="pre">serve</span> <span class="pre">.</span></tt> and go to <tt class="docutils literal"><span class="pre">/admin/</span></tt> to login and see your tables.  You might notice all the CSS is broken.</p>
<p>toppcloud serves static files out of the <tt class="docutils literal"><span class="pre">static/</span></tt> directory.  You don’t actually put <tt class="docutils literal"><span class="pre">static</span></tt> in the URLs, these files are available at the top-level (unless you create a <tt class="docutils literal"><span class="pre">static/static/</span></tt> directory). The best way to put files in there is generally symbolic links.</p>
<p>For Django admin, do this:</p>
<pre class="literal-block">$ cd static
$ ln -s ../lib/python/django/contrib/admin/media admin-media
</pre>
<p>Now edit <tt class="docutils literal"><span class="pre">src/sampleapp/sampleapp/settings.py</span></tt> and change <tt class="docutils literal"><span class="pre">ADMIN_MEDIA_PREFIX</span></tt> to <tt class="docutils literal"><span class="pre">‘/admin-media’</span></tt>.</p>
<p>(Probably some other links should be added.)</p>
<p>One <em>last</em> little thing you might want to do; replace this line in<br/>
settings:</p>
<pre class="literal-block">SECRET_KEY = 'ASF#@$@#JFAS#@'
</pre>
<p>With this:</p>
<pre class="literal-block">from tcsupport.secret import get_secret
SECRET_KEY = get_secret()
</pre>
<p>Then you don’t have to worry about checking a secret into version control.</p>
<p>You still don’t really have an application, but the rest is mere "programming" so have at it!</p>
</div>
</div></div>
    </content>
    <updated>2010-03-06T00:30:14Z</updated>
    <published>2010-02-05T08:50:58Z</published>
    <category scheme="http://blog.ianbicking.org" term="Programming"/>
    <category scheme="http://blog.ianbicking.org" term="Python"/>
    <category scheme="http://blog.ianbicking.org" term="Web"/>
    <category scheme="http://blog.ianbicking.org" term="silverlining"/>
    <author>
      <name>Ian Bicking</name>
      <uri>http://blog.ianbicking.org</uri>
    </author>
    <source>
      <id>http://blog.ianbicking.org/feed/atom/</id>
      <link href="http://blog.ianbicking.org" rel="alternate" type="text/html"/>
      <link href="http://blog.ianbicking.org/feed/atom/" rel="self" type="application/atom+xml"/>
      <title xml:lang="en">Ian Bicking: a blog</title>
      <updated>2010-03-06T00:32:29Z</updated>
    </source>
  </entry>

  <entry xml:lang="en">
    <id>http://blog.ianbicking.org/?p=132</id>
    <link href="http://blog.ianbicking.org/2010/01/29/new-way-to-deploy-web-apps/" rel="alternate" type="text/html"/>
    <link href="http://blog.ianbicking.org/2010/01/29/new-way-to-deploy-web-apps/#comments" rel="replies" type="text/html"/>
    <link href="http://blog.ianbicking.org/2010/01/29/new-way-to-deploy-web-apps/feed/atom/" rel="replies" type="application/atom+xml"/>
    <title xml:lang="en">A new way to deploy web applications</title>
    <summary xml:lang="en">Deployment is one of the things I like least about development, and yet without deployment the development doesn’t really matter.
I’ve tried a few things (e.g. fassembler), built a few things (virtualenv, pip), but deployment just sucked less as a result.  Then I got excited about App Engine; everyone else was getting excited about "scaling", [...]</summary>
    <content type="xhtml" xml:lang="en"><div xmlns="http://www.w3.org/1999/xhtml"><div class="document">
<p>Deployment is one of the things I like least about development, and yet without deployment the development doesn’t really matter.</p>
<p>I’ve tried a few things (e.g. <a class="reference external" href="http://blog.ianbicking.org/2008/06/19/my-experience-writing-a-build-system/">fassembler</a>), built a few things (<a class="reference external" href="http://virtualenv.openplans.org">virtualenv</a>, <a class="reference external" href="http://pip.openplans.org">pip</a>), but deployment just sucked <em>less</em> as a result.  Then I got excited about <a class="reference external" href="http://appengine.google.com">App Engine</a>; everyone else was getting excited about "scaling", but really I was <a class="reference external" href="http://blog.ianbicking.org/2008/04/09/app-engine-and-open-source/">excited about an accessible deployment process</a>.  When it comes to deployment App Engine is the first thing that has really felt good to me.</p>
<p><strong>But</strong> I can’t actually <em>use</em> App Engine.  I was able to come to terms with the idea of writing an application to the platform, but there are limits… and with App Engine there were simply too many limits.  Geo stuff on App Engine is at best a crippled hack, I miss <a class="reference external" href="http://codespeak.net/lxml/">lxml</a> terribly, I never hated relational databases, and almost nothing large works without some degree of rewriting.  Sometimes you can work around it, but you can never be sure you won’t hit some wall later.  And frankly working around the platform is tiring and not very rewarding.</p>
<hr class="docutils"/>
<p>So… App Engine seemed neat, but I couldn’t use it, and deployment was still a problem.</p>
<p>What I like about App Engine: an application is just files.  There’s no build process, no fancy copying of things in weird locations, nothing like that; you upload files, and uploading files <em>just works</em>.  Also, you can check <em>everything</em> into version control.  Not just your application code, but every library you use, the exact files that you installed.  I really wanted a system like that.</p>
<p>At the same time, I started looking into "the cloud".  It took me a while to get a handle on what "cloud computing" really means.  What I learned: don’t overthink it.  It’s not magic.  It’s just virtual private servers that can be requisitioned automatically via an API, and are billed on a short time cycle.  You can expand or change the definition a bit, but this definition is the one that matters to <em>me</em>.  (I’ve also realized that I cannot get excited about complicated solutions; only once I realized how simple cloud computing is could I really get excited about the idea.)</p>
<p>Given the modest functionality of cloud computing, why does it matter? Because with a cloud computing system you can actually <em>test</em> the full deployment stack.  You can create a brand-new server, identical to all servers you will create in the future; you can set this server up; you can deploy to it.  You get it wrong, you throw away that virtual server and start over from the beginning, fixing things until you get it right.  Billing is important here too; with hourly billing you pay cents for these tests, and you don’t need a pool of ready servers because the cloud service basically manages that pool of ready servers for you.</p>
<p>Without "cloud computing" we each too easily find ourselves in a situation where deployments are ad hoc, server installations develop over time, and servers and applications are inconsistent in their configuration.  Cloud computing makes servers disposable, which means we can treat them in consistent ways, testing our work as we go.  It makes it easy to treat operations with the same discipline as software.</p>
<p>Given the idea from App Engine, and the easy-to-use infrastructure of a cloud service, I started to script together something to manage the servers and start up applications.  I didn’t know what exactly I wanted to do to start, and I’m not completely sure where I’m going with this.  But on the whole this feels pretty right.  So I present the provisionally-named: <a class="reference external" href="http://toppcloud.colorstudy.com">toppcloud</a> (<strong>Update</strong>: this has been renamed Silver Cloud).</p>
<hr class="docutils"/>
<p>How it works: first you have a directory of files that defines your application.  This probably includes a checkout of your "application" (let’s say in <tt class="docutils literal"><span class="pre">src/mynewapp/</span></tt>), and I find it also useful to use source control on the libraries (which are put in <tt class="docutils literal"><span class="pre">lib/python/</span></tt>).  There’s a file in <tt class="docutils literal"><span class="pre">app.ini</span></tt> that defines some details of the application (very similar to <tt class="docutils literal"><span class="pre">app.yaml</span></tt>).</p>
<p>While app.ini is a (<a class="reference external" href="http://toppcloud.colorstudy.com/appconfig.html">very minimal</a>) description of the <em>application</em>, there is no description of the environment.  You do not specify database connection details, for instance.  Instead your application <em>requests</em> access to a database service.  For instance, one of these services is a PostgreSQL/PostGIS database (which you get if you put <tt class="docutils literal"><span class="pre">service.postgis</span></tt> in your app.ini file).  If you ask for that then there will be evironmental variables, <tt class="docutils literal"><span class="pre">CONFIG_PG_DBNAME</span></tt> etc., that will tell your application how to connect to the database.  (For local development you can provide your own configuration, based on how you have PostgreSQL or some other service installed.)</p>
<p>The standard setup is also a <a class="reference external" href="http://virtualenv.openplans.org">virtualenv</a> environment.  It is setup so <em>every time</em> you start that virtualenv environment you’ll get those configuration-related environmental variables.  This means your application configuration is always present, your services always available.  It’s available in tests just like it is during a request.  Django accomplishes something similar with the (much maligned) <tt class="docutils literal"><span class="pre">$DJANGO_SETTINGS_MODULE</span></tt> but toppcloud builds it into the virtualenv environment instead of the shell environment.</p>
<p>And how is the server setup?  Much like with App Engine that is merely an implementation detail.  Unlike App Engine that’s an implementation detail you can actually <em>look</em> at and change (by changing toppcloud), but it’s not something you are supposed to concern yourself with during regular application development.</p>
<p>The basic lifecycle using toppcloud looks like:</p>
<dl class="docutils">
<dt><tt class="docutils literal"><span class="pre">toppcloud</span> <span class="pre">create-node</span></tt></dt>
<dd>Create a new virtual server; you can create any kind of supported server, but only Ubuntu Jaunty or Karmic are supported (and Jaunty should probably be dropped).  This step is where the "cloud" part actually ends.  If you want to install a bare Ubuntu onto an existing physical machine that’s fine too — after <tt class="docutils literal"><span class="pre">toppcloud</span> <span class="pre">create-node</span></tt> the "cloud" part of the process is pretty much done.  Just don’t go using some old Ubuntu install; this tool is for clean systems that are used only for toppcloud.</dd>
<dt><tt class="docutils literal"><span class="pre">toppcloud</span> <span class="pre">setup-node</span></tt></dt>
<dd>Take that bare Ubuntu server and set it up (or update it) for use with toppcloud.  This installs all the basic standard stuff (things like Apache, mod_wsgi, Varnish) and some management script that toppcloud runs.  This is written to be safe to run over and over, so upgrading and setting up a machine are the same.  It needs to be a bare server, but</dd>
<dt><tt class="docutils literal"><span class="pre">toppcloud</span> <span class="pre">init</span> <span class="pre">path/to/app/</span></tt></dt>
<dd>Setup a basic virtualenv environment with some toppcloud customizations.</dd>
<dt><tt class="docutils literal"><span class="pre">toppcloud</span> <span class="pre">serve</span> <span class="pre">path/to/app</span></tt></dt>
<dd>Serve up the application locally.</dd>
<dt><tt class="docutils literal"><span class="pre">toppcloud</span> <span class="pre">update</span> <span class="pre">–host=test.example.com</span> <span class="pre">path/to/app/</span></tt></dt>
<dd>This creates or updates an application at the given host.  It edits <tt class="docutils literal"><span class="pre">/etc/hosts</span></tt> so that the domain is locally viewable.</dd>
<dt><tt class="docutils literal"><span class="pre">toppcloud</span> <span class="pre">run</span> <span class="pre">test.example.com</span> <span class="pre">script.py</span></tt></dt>
<dd>Run a script (from <tt class="docutils literal"><span class="pre">bin/</span></tt>) on a remote server.  This allows you to run things like <tt class="docutils literal"><span class="pre">django-admin.py</span> <span class="pre">syncdb</span></tt>.</dd>
</dl>
<p>There’s a few other things — stuff to manage the servers and change around hostnames or the active version of applications.  It’s growing to fit a variety of workflows, but I don’t think its growth is unbounded.</p>
<hr class="docutils"/>
<p>So… this is what toppcloud.  From the outside it doen’t do a lot.  From the inside it’s not actually that complicated either.  I’ve included a lot of constraints in the tool but I think it offers an excellent balance.  The constraints are workable for applications (insignificant for many applications), while still exposing a simple and consistent system that’s easier to reason about than a big-ball-of-server.</p>
<p>Some of the constraints:</p>
<ol class="arabic simple">
<li>Binary packages are supported via Ubuntu packages; you only upload portable files.  If you need a library like lxml, you need to request that package (<tt class="docutils literal"><span class="pre">python-lxml</span></tt>) to be installed in your app.ini.  If you need a version of a binary library that is not yet packaged, I think creating a new deb is reasonable.</li>
<li>There is no Linux distribution abstraction, but I don’t care.</li>
<li>There is no option for the way your application is run — there’s one way applications are run, because I believe there is a best practice.  I might have gotten the best practice wrong, but that should be resolved inside toppcloud, not inside applications. Is Varnish a terrible cache?  Probably not, but if it is we should all be able to agree on that and replace it.  If there are genuinely different needs then maybe additional application or deployment configuration will be called for — but we shouldn’t add configuration just because someone <em>says</em> there is a better practice (and a better practice that is not universally better); there must be justifications.</li>
<li>By abstracting out services and persistence some additional code is required for each such service, and that code is centralized in toppcloud, but it means we can also start to add consistent tools usable across a wide set of applications and backends.</li>
<li>All file paths have to be relative, because files get moved around.  I know of some particularly problematic files (e.g., <tt class="docutils literal"><span class="pre">.pth</span></tt> files), and toppcloud fixes these automatically.  Mostly this isn’t so hard to do.</li>
</ol>
<p>These particular compromises are ones I have not seen in many systems (and <a class="reference external" href="http://toppcloud.colorstudy.com/comparisons.html">I’ve started to look more</a>).  App Engine I think goes too far with its constraints.  <a class="reference external" href="http://heroku.com/">Heroku</a> is close, but closed source.</p>
<p>This is different than a strict everything-must-be-a-package strategy.  This deployment system is light and simple and takes into account reasonable web development workflows.  The pieces of an application that move around a lot are all well-greased and agile.  The parts of an application that are better to Do Right And Then Leave Alone (like Apache configuration) are static.</p>
<p>Unlike generalized systems like buildout this system avoids "building" entirely, making deployment a simpler and lower risk action, leaning on system packages for the things they do best.  Other open source tools emphasize a greater degree of flexibility than I think is necessary, allowing people to encode exploratory service integration into what <em>appears</em> to be an encapsulated build (I’m looking at you buildout).</p>
<p>Unlike <a class="reference external" href="http://pip.openplans.org/requirement-format.html">requirement sets</a> and packaging and versioning libraries, this makes all the Python libraries (typically the most volatile libraries) explicit and controlled, and can better ensure that small updates really are small.  It doesn’t invalidate installers and versioning, but it makes that process even more explicit and encourages greater thoughtfulness.</p>
<p>Unlike many production-oriented systems (what I’ve seen in a lot of "cloud" tools) this encorporates both the development environment and production environment; but unlike some developer-oriented systems this does not try to normalize everyone’s environment and instead relies on developers to set up their systems however is appropriate.  And unlike platform-neutral systems this can ensure an amount of reliability and predictability through extremely hard requirements (it is deployed on Ubuntu Jaunty/Karmic <em>only</em>).</p>
<p>But it’s not all constraints.  Toppcloud is solidly web framework neutral.  It’s even <a class="reference external" href="http://toppcloud.colorstudy.com/php.html">slightly language neutral</a>.  Though it does require support code for each persistence technique, it is fairly easy to do, and there are no requirements for "scalable systems"; I think unscalable systems are a perfectly reasonable implementation choice for many problems.  I believe a more scalable system could be built on this, but as a deployment and development option, not a starting requirement.</p>
<p>So far I’ve done some deployments using toppcloud; not a lot, but some.  And I can say that it feels really good; lots of rough edges still, but the core concept feels really right.   I’ve made a lot of sideways attacks on deployment, and a few direct attacks… sometimes I write things that I think are useful, and sometimes I write things that I think are right.  Toppcloud is at the moment maybe more right than useful.  But I genuinely believe this is (in theory) a universally appropriate deployment tool.</p>
<hr class="docutils"/>
<p>Alright, so now you think maybe you should look more at toppcloud…</p>
<p>Well, I can offer you <a class="reference external" href="http://toppcloud.colorstudy.com">a fair amount of documentation</a>.  A lot of that documentation refers to design, and a bit of it to examples.  There’s also a couple projects you can look at; they are all small, but :</p>
<ul class="simple">
<li><a class="reference external" href="http://bitbucket.org/geraldmc/frank-src/src/tip/build-fs-layout">Frank</a> (will be interactivesomerville.org) which is another similar Django/Pinax project (Pinax was a bit tricky).  This is probably the largest project.  It’s a Django/Pinax volunteer-written application for collecting community feedback the Boston Greenline project, if that sounds interesting to you might want to chip in on the development (if so <a class="reference external" href="https://projects.openplans.org/greenline">check out the wiki</a>).</li>
<li><a class="reference external" href="http://github.com/ianb/neighborly/blob/master/INSTALL.txt">Neighborly</a>, with minimal functionality (we need to run more sprints) but an installation story.</li>
<li><a class="reference external" href="http://bitbucket.org/ianb/bbdocs/src/tip/create-layout.sh">bbdocs</a> which is a very simple bitbucket document generator, that makes the toppcloud site.</li>
<li><a class="reference external" href="http://bitbucket.org/ianb/geodns">geodns</a> which is another simple no-framework PostGIS project.</li>
</ul>
<hr class="docutils"/>
<p>Now, the letdown.  One thing I cannot offer you is support.  <strong>THERE IS NO SUPPORT</strong>.  I cannot now, and I might never really be able to support this tool.  This tool is appropriate for collaborators, for people who like the idea and are ready to build on it.  If it grows well I hope that it can grow a community, I hope people can support each other.  I’d like to help that happen.  But I can’t do that by bootstrapping it through unending support, because I’m not good at it and I’m not consistent and it’s unrealistic and unsustainable.  This is not a open source dead drop.  But it’s also not My Future; I’m not going to build a company around it, and I’m not going to use all my free time supporting it.  It’s a tool I want to exist.  I <strong>very much</strong> want it to exist.  But even very much wanting something is not the same as being an undying champion, and I am not an undying champion.  If you want to tell me what my process <em>should</em> be, please do!</p>
<hr class="docutils"/>
<blockquote><p>
If you want to see me get philosophical about packaging and deployment and other stuff like that, see my upcoming talk at <a class="reference external" href="http://us.pycon.org/">PyCon</a>.</p></blockquote>
</div></div>
    </content>
    <updated>2010-03-06T00:27:10Z</updated>
    <published>2010-01-29T20:21:57Z</published>
    <category scheme="http://blog.ianbicking.org" term="Packaging"/>
    <category scheme="http://blog.ianbicking.org" term="Programming"/>
    <category scheme="http://blog.ianbicking.org" term="Python"/>
    <category scheme="http://blog.ianbicking.org" term="Web"/>
    <category scheme="http://blog.ianbicking.org" term="silverlining"/>
    <author>
      <name>Ian Bicking</name>
      <uri>http://blog.ianbicking.org</uri>
    </author>
    <source>
      <id>http://blog.ianbicking.org/feed/atom/</id>
      <link href="http://blog.ianbicking.org" rel="alternate" type="text/html"/>
      <link href="http://blog.ianbicking.org/feed/atom/" rel="self" type="application/atom+xml"/>
      <title xml:lang="en">Ian Bicking: a blog</title>
      <updated>2010-03-06T00:32:29Z</updated>
    </source>
  </entry>

  <entry xml:lang="en">
    <id>http://blog.repoze.org/Darryl%20Cousins%27%20Codes%20Live%20with%20BFG/</id>
    <link href="http://blog.repoze.org/Darryl%20Cousins%27%20Codes%20Live%20with%20BFG/" rel="alternate" type="text/html"/>
    <title xml:lang="en">Darryl Cousins' Codes Live with BFG</title>
    <content type="xhtml" xml:lang="en"><div xmlns="http://www.w3.org/1999/xhtml"><p>Darryl has put a screencast online of the demo session he is doing this evening at the Christchurch branch meeting of the New Zealand Python Users' Group:</p>



<p>Nice demo, Darryl</p></div>
    </content>
    <updated>2010-03-05T05:00:00Z</updated>
    <author>
      <name>Agendaless</name>
    </author>
    <source>
      <id>http://blog.repoze.org/index.atom</id>
      <link href="http://blog.repoze.org" rel="alternate" type="text/html"/>
      <link href="http://blog.repoze.org/index.atom" rel="self" type="application/atom+xml"/>
      <title xml:lang="en">Repoze Blog RSS Feed</title>
      <updated>2010-03-06T05:00:00Z</updated>
    </source>
  </entry>

  <entry xml:lang="en">
    <id>http://blog.ianbicking.org/?p=168</id>
    <link href="http://blog.ianbicking.org/2010/03/03/toppcloud-renamed-to-silver-lining/" rel="alternate" type="text/html"/>
    <link href="http://blog.ianbicking.org/2010/03/03/toppcloud-renamed-to-silver-lining/#comments" rel="replies" type="text/html"/>
    <link href="http://blog.ianbicking.org/2010/03/03/toppcloud-renamed-to-silver-lining/feed/atom/" rel="replies" type="application/atom+xml"/>
    <title xml:lang="en">toppcloud renamed to Silver Lining</title>
    <summary xml:lang="en">After some pondering at PyCon, I decided on a new name for toppcloud: Silver Lining.  I’ll credit a mysterious commenter "david" with the name idea.  The command line is simply silver — silver update has a nice ring to it.
There’s a new site: cloudsilverlining.org; not notably different than the old site, just a [...]</summary>
    <content type="xhtml" xml:lang="en"><div xmlns="http://www.w3.org/1999/xhtml"><div class="document">
<p>After some pondering at PyCon, I decided on a new name for toppcloud: <strong>Silver Lining</strong>.  I’ll credit a mysterious commenter "david" with the name idea.  The command line is simply <tt class="docutils literal"><span class="pre">silver</span></tt> — <tt class="docutils literal"><span class="pre">silver</span> <span class="pre">update</span></tt> has a nice ring to it.</p>
<p>There’s a new site: <a class="reference external" href="http://cloudsilverlining.org">cloudsilverlining.org</a>; not notably different than the old site, just a new name.  The product is self-hosting now, using a <a class="reference external" href="http://bitbucket.org/ianb/silverlining/">simple app</a> that runs after every commit to regenerate the docs, and with a small extension to Silver Lining itself (to make it easier to host static files).  Now that it has a real name I also gave it a <a class="reference external" href="http://groups.google.com/group/silverlining-dev">real mailing list</a>.</p>
<p>Silver Lining also has its <a class="reference external" href="http://bitbucket.org/ianb/silverlining/src/tip/tests/functional/runtest.py">first test</a>.  Not an impressive test, but a test.  I’m hoping with a <a class="reference external" href="http://mail-archives.apache.org/mod_mbox/incubator-libcloud/201003.mbox/browser">VM-based libcloud backend</a> that a full integration test can run in a reasonable amount of time.  <em>Some</em> unit tests would be possible, but so far most of the bugs have been interaction bugs so I think integration tests will have to pull most of the weight.  (A continuous integration rig will be very useful; I am not sure if Silver Lining can self-host that, though it’d be nice/clever if it could.)</p>
</div></div>
    </content>
    <updated>2010-03-04T02:18:30Z</updated>
    <published>2010-03-04T02:18:30Z</published>
    <category scheme="http://blog.ianbicking.org" term="Packaging"/>
    <category scheme="http://blog.ianbicking.org" term="Programming"/>
    <category scheme="http://blog.ianbicking.org" term="Python"/>
    <category scheme="http://blog.ianbicking.org" term="Web"/>
    <category scheme="http://blog.ianbicking.org" term="silverlining"/>
    <author>
      <name>Ian Bicking</name>
      <uri>http://blog.ianbicking.org</uri>
    </author>
    <source>
      <id>http://blog.ianbicking.org/feed/atom/</id>
      <link href="http://blog.ianbicking.org" rel="alternate" type="text/html"/>
      <link href="http://blog.ianbicking.org/feed/atom/" rel="self" type="application/atom+xml"/>
      <title xml:lang="en">Ian Bicking: a blog</title>
      <updated>2010-03-06T00:32:29Z</updated>
    </source>
  </entry>

  <entry xml:lang="en">
    <id>http://blog.ianbicking.org/?p=164</id>
    <link href="http://blog.ianbicking.org/2010/03/01/throw-out-your-frameworks-forms-included/" rel="alternate" type="text/html"/>
    <link href="http://blog.ianbicking.org/2010/03/01/throw-out-your-frameworks-forms-included/#comments" rel="replies" type="text/html"/>
    <link href="http://blog.ianbicking.org/2010/03/01/throw-out-your-frameworks-forms-included/feed/atom/" rel="replies" type="application/atom+xml"/>
    <title xml:lang="en">Throw out your frameworks! (forms included)</title>
    <summary xml:lang="en">No, I should say forms particularly.
I have lots of things to blog about, but nothing makes me want to blog like code.  Ideas are hard, code is easy.  So when I saw Jacob’s writeup about dynamic Django form generation I felt a desire to respond.  I didn’t see the form panel at [...]</summary>
    <content type="xhtml" xml:lang="en"><div xmlns="http://www.w3.org/1999/xhtml"><div class="document">
<p>No, I should say <em>forms particularly</em>.</p>
<p>I have lots of things to blog about, but nothing makes me want to blog like <em>code</em>.  Ideas are hard, code is easy.  So when I saw <a class="reference external" href="http://jacobian.org/writing/dynamic-form-generation/">Jacob’s writeup about dynamic Django form generation</a> I felt a desire to respond.  I didn’t see the form panel at PyCon (I intended to but I hardly saw <em>any</em> talks at PyCon, and yet still didn’t even see a good number of the people I wanted to see), but as the author of an <a class="reference external" href="http://formencode.org/htmlfill.html">ungenerator</a> and as a general <a class="reference external" href="http://blog.ianbicking.org/on-form-libraries.html">form library skeptic</a> I have a somewhat different perspective on the topic.</p>
<p>The example created for the panel might display that perspective.  You should go read <a class="reference external" href="http://jacobian.org/writing/dynamic-form-generation/">Jacob’s description</a>; but basically it’s a simple registration form with a dynamic set of questions to ask.</p>
<p>I have created a <a class="reference external" href="http://svn.colorstudy.com/home/ianb/formencode_answer.py">complete example</a>, because I wanted to be sure I wasn’t skipping anything, but I’ll present a trimmed-down version.</p>
<p>First, the basic control logic:</p>
<pre class="literal-block">from webob.dec import wsgify
from webob import exc
from formencode import htmlfill

@wsgify
def questioner(req):
    questions = get_questions(req) # This is provided as part of the example
    if req.method == 'POST':
        errors = validate(req, questions)
        if not errors:
            ... save response ...
            return exc.HTTPFound(location='/thanks')
    else:
        errors = {}
    ## Here's the "form generation":
    page = page_template.substitute(
        action=req.url,
        questions=questions)
    page = htmlfill.render(
        page,
        defaults=req.POST,
        errors=errors)
    return Response(page)

def validate(req, questions):
    # All manual, but do it however you want:
    errors = {}
    form = req.POST
    if (form.get('password')
        and form['password'] != form.get('password_confirm')):
        errors['password_confirm'] = 'Passwords do not match'
    fields = questions + ['username', 'password']
    for field in fields:
        if not form.get(field):
            errors[field] = 'Please enter a value'
    return errors
</pre>
<p>I’ve just manually handled validation here.  I don’t feel like doing it with FormEncode.  Manual validation isn’t that big a deal; FormEncode would just produce the same <tt class="docutils literal"><span class="pre">errors</span></tt> dictionary anyway.  In this case (as in many form validation cases) you can’t do better than hand-written validation code: it’s shorter, more self-contained, and easier to tweak.</p>
<p>After validation the template is rendered:</p>
<pre class="literal-block">page = page_template.substitute(
    action=req.url,
    questions=questions)
</pre>
<p>I’m using <a class="reference external" href="http://pythonpaste.org/tempita/">Tempita</a>, but it really doesn’t matter.  The template looks like this:</p>
<pre class="literal-block">&lt;form action="{{action}}" method="POST"&gt;
New Username: &lt;input type="text" name="username"&gt;&lt;br /&gt;
Password: &lt;input type="password" name="password"&gt;&lt;br /&gt;
Repeat Password:
  &lt;input type="password" name="password_confirm"&gt;&lt;br /&gt;
{{for question in questions}}
  {{question}}: &lt;input type="text" name="{{question}}"&gt;&lt;br /&gt;
{{endfor}}
&lt;input type="submit"&gt;
&lt;/form&gt;
</pre>
<p>Note that the only "logic" here is to render the form to include fields for all the questions.  Obviously this produces an ugly form, but it’s <em>very obvious</em> how you make this form pretty, and how to tweak it in any way you might want.  Also if you have deeper dynamicism (e.g., <tt class="docutils literal"><span class="pre">get_questions</span></tt> start returning the type of response required, or weird validation, or whatever) it’s <em>very obvious</em> where that change would go: display logic goes in the form, validation logic goes in that validate function.</p>
<p>This just gives you the raw form.  You wouldn’t need a template at all if it wasn’t for the dynamicism.  Everything else is added when the form is "filled":</p>
<pre class="literal-block">page = htmlfill.render(
    page,
    defaults=req.POST,
    errors=errors)
</pre>
<p>How exactly you want to calculate <tt class="docutils literal"><span class="pre">defaults</span></tt> is up to the application; you might want query string variables to be able to pre-fill the form (use <tt class="docutils literal"><span class="pre">req.params</span></tt>), you might want the form bare to start (like here with <tt class="docutils literal"><span class="pre">req.POST</span></tt>), you can easily implement wizards by stuffing <tt class="docutils literal"><span class="pre">req.POST</span></tt> into the session to repeat a form, you might read the defaults out of a user object to make this an edit form.  And errors are just handled automatically, inserted into the HTML with appropriate CSS classes.</p>
<p>A great aspect of this <em>pattern</em> if you use it (I’m not even sure it deserves the moniker <em>library</em>): when <a class="reference external" href="http://www.whatwg.org/specs/web-apps/current-work/multipage/forms.html#forms">HTML 5 Forms</a> finally come around and we can all stop doing this stupid server-side overthought nonsense, <strong>you</strong> won’t have overthought your forms.  Your mind will be free and ready to accept that the world has actually become simpler, not more complicated, and that there is knowledge worth forgetting (forms are so freakin’ stupid!)  If at all possible, dodging complexity is far better than cleverly responding to complexity.</p>
</div></div>
    </content>
    <updated>2010-03-01T06:29:04Z</updated>
    <published>2010-03-01T06:29:04Z</published>
    <category scheme="http://blog.ianbicking.org" term="HTML"/>
    <category scheme="http://blog.ianbicking.org" term="Programming"/>
    <category scheme="http://blog.ianbicking.org" term="Python"/>
    <category scheme="http://blog.ianbicking.org" term="Web"/>
    <author>
      <name>Ian Bicking</name>
      <uri>http://blog.ianbicking.org</uri>
    </author>
    <source>
      <id>http://blog.ianbicking.org/feed/atom/</id>
      <link href="http://blog.ianbicking.org" rel="alternate" type="text/html"/>
      <link href="http://blog.ianbicking.org/feed/atom/" rel="self" type="application/atom+xml"/>
      <title xml:lang="en">Ian Bicking: a blog</title>
      <updated>2010-03-06T00:32:29Z</updated>
    </source>
  </entry>

  <entry xml:lang="en">
    <id>http://blog.repoze.org/PyCon%202010%3A%20%20BFG%20talks%20online/</id>
    <link href="http://blog.repoze.org/PyCon%202010%3A%20%20BFG%20talks%20online/" rel="alternate" type="text/html"/>
    <title xml:lang="en">PyCon 2010:  BFG talks online</title>
    <content type="xhtml" xml:lang="en"><div xmlns="http://www.w3.org/1999/xhtml"><p>The PyCon 2010 audio-video team has done a really bang-up job getting the
   conference talks recorded, edited, and online quickly,  The two BFG-relate
   talks are now available:</p>

<h4>Tres Seaver's "Evolving Your Framework Under Fire" talk:</h4>

  

<h4>Carlos de la Guardia's "Pay Only For What You Eat" talk:</h4>

  

Enjoy!</div>
    </content>
    <updated>2010-02-25T05:00:00Z</updated>
    <author>
      <name>Agendaless</name>
    </author>
    <source>
      <id>http://blog.repoze.org/index.atom</id>
      <link href="http://blog.repoze.org" rel="alternate" type="text/html"/>
      <link href="http://blog.repoze.org/index.atom" rel="self" type="application/atom+xml"/>
      <title xml:lang="en">Repoze Blog RSS Feed</title>
      <updated>2010-03-06T05:00:00Z</updated>
    </source>
  </entry>

  <entry xml:lang="en">
    <id>http://blog.repoze.org/PyCon%202010%3A%20%20repoze.bfg%20Sprinting/</id>
    <link href="http://blog.repoze.org/PyCon%202010%3A%20%20repoze.bfg%20Sprinting/" rel="alternate" type="text/html"/>
    <title xml:lang="en">PyCon 2010:  repoze.bfg Sprinting</title>
    <content type="xhtml" xml:lang="en"><div xmlns="http://www.w3.org/1999/xhtml"><p>Folks have been sprinting here at PyCon this week on a number of repoze-related projects:</p>
<div class="section" id="bfg-cookbook">
<h1>BFG Cookbook</h1>
<p>Andrew Sawyers, Chris Shenton, Shane Hathaway, and Reed O'Brien worked on an
example "BFG Cookbook" application, intended to run in the Google App Engine
cloud.  They succeeded in indirecting the storage of the recipe entries, with
working backends based on the GAE Big Table API, ZODB, Mongo, and an in-memory
(nonpersistent) storage.</p>
<p>Code for the project is available on bitbucket:</p>
<blockquote>
<a class="reference external" href="http://bitbucket.org/sawdog/bfgcookbook/">http://bitbucket.org/sawdog/bfgcookbook/</a></blockquote>
</div>
<div class="section" id="bfg-without-z-s">
<h1>BFG without Z's</h1>
<p>Reed also worked on re-doing the Mongo-based URL shortener he wrote at last
year's sprint, this time using the Ming bindings.  He is working to have
an example which uses none of the <tt class="docutils literal"><span class="pre">zope.*</span></tt> packaages, in order to show
how BFG can be used in a variety of ways.</p>
<p>Chris McDonough and Chris Rossi have been sprinting with the Pylons and
TurboGears folks on a package code-named "Marco."  Marco moves some of the
dispatching logic of BFG down into a package intended to be useful as the
basis for a version of Pylons:  if it succeeds, Pylons and BFG would become
"personality" layers on top of the shared Marco library.</p>
</div>
<div class="section" id="cms-architecture">
<h1>CMS Architecture</h1>
<p>Tres Seaver has been working on a CMS architecture which he has been
mulling for a long while now, code-named "Bonzai".  The architecture
decouples "asset repositories" from the "site layout" applications which
consume them, imposing a RESTy service layer between the two.</p>
</div>
<div class="section" id="sprint-humor">
<h1>Sprint Humor</h1>
<p>In reaction to the perhaps overly cute mascots adopted by a certain other
nameless framework, the BFG sprint team has adopted the "flying" or "war" pig
as a mascot (<strong>not</strong> the cute Porky type, but a real tusker!).</p>
<img alt="http://static.repoze.org/war_pigs_sprint.png" src="http://static.repoze.org/war_pigs_sprint.png"/>
</div></div>
    </content>
    <updated>2010-02-24T05:00:00Z</updated>
    <author>
      <name>Agendaless</name>
    </author>
    <source>
      <id>http://blog.repoze.org/index.atom</id>
      <link href="http://blog.repoze.org" rel="alternate" type="text/html"/>
      <link href="http://blog.repoze.org/index.atom" rel="self" type="application/atom+xml"/>
      <title xml:lang="en">Repoze Blog RSS Feed</title>
      <updated>2010-03-06T05:00:00Z</updated>
    </source>
  </entry>

  <entry xml:lang="en">
    <id>http://blog.repoze.org/Running%20BFG%201.2%20on%20Webfaction/</id>
    <link href="http://blog.repoze.org/Running%20BFG%201.2%20on%20Webfaction/" rel="alternate" type="text/html"/>
    <title xml:lang="en">Running BFG 1.2 on Webfaction</title>
    <content type="xhtml" xml:lang="en"><div xmlns="http://www.w3.org/1999/xhtml"><p>After hearing Brandon Rhodes' <a class="reference external" href="http://us.pycon.org/2010/conference/schedule/event/74/">talk on deploying applications to WebFaction</a>, and talking with one of the
WebFaction staff here at the PyCon 2010 sprints, I sprinted today on creating an installer script for
creating a BFG webapp inside a WebFaction account.</p>
<p>To use it in your WebFaction account, create an application in the control panel using the "Custom Installer Script" option, and paste the URL of the <a class="reference external" href="http://dist.repoze.org/bfg/1.2/webfaction_install.py">script</a> into the form.  Once the installer finishes, you
will have a "starter" application running in the webapp directory,   You can start hacking on the
code there, or upload your own app to it and tweak it there.</p></div>
    </content>
    <updated>2010-02-22T05:00:00Z</updated>
    <author>
      <name>Agendaless</name>
    </author>
    <source>
      <id>http://blog.repoze.org/index.atom</id>
      <link href="http://blog.repoze.org" rel="alternate" type="text/html"/>
      <link href="http://blog.repoze.org/index.atom" rel="self" type="application/atom+xml"/>
      <title xml:lang="en">Repoze Blog RSS Feed</title>
      <updated>2010-03-06T05:00:00Z</updated>
    </source>
  </entry>

  <entry xml:lang="en">
    <id>http://pauleveritt.wordpress.com/?p=67</id>
    <link href="http://pauleveritt.wordpress.com/2010/02/18/karl-and-zero-downtime-updates/" rel="alternate" type="text/html"/>
    <title>KARL and zero-downtime updates</title>
    <summary type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml">For the KARL project, the development team is primarily involved in operations.  Along with Six Feet Up as the hosting provider, we are responsible for many activities in “SaaS”.  Bugs are reported to us, we do the software updates, we help monitor the site, we do staging and testing of customer instances.
I really enjoy this [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=pauleveritt.wordpress.com&amp;blog=5206833&amp;post=67&amp;subd=pauleveritt&amp;ref=&amp;feed=1"/></div>
    </summary>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><br/><p>For the <a href="http://www.karlproject.org/">KARL project</a>, the development team is primarily involved in operations.  Along with Six Feet Up as the hosting provider, we are responsible for many activities in “SaaS”.  Bugs are reported to us, we do the software updates, we help monitor the site, we do staging and testing of customer instances.</p>
<p>I really enjoy this aspect.  It’s different from past involvement in open source projects, where involvement in the software is somewhat de-coupled from living with your mistakes. [wink]  Stated differently, we have a direct interest in stability, performance, quality, and even in things like making KARL easy to monitor by Zenoss.</p>
<p>We periodically update the software.  Which means restarting the app server.  Which usually means, downtime.  Over time, we’ve whittled that down.</p>
<p>First, KARL restarts fast.  Like, two seconds or so.  Thus, the impact is minimal.  Next, we use mod_wsgi, which lets us do “graceful” restarts in Apache.  Serve all your current requests and restart your processes.  These combine for providing very fast updates.</p>
<p>There’s one aspect that’s harder though.  Sometimes our updates require “evolve” scripts to update data.  For example, adding an index, or fixing a value that requires waking up lots of objects.</p>
<p>We used to do this live in a ZEO client, but when the evolve script takes more than a few minutes, we get prone to conflict errors with the running site.  Which means, shutting down the main site.  Which, sucks.  (I’ve become quite obsessive about performance and uptime.)</p>
<p>We have some ideas we think can mitigate this:</p>
<ul>
<li>SSD.  Six Feet Up has the solid-state disks installed.  Because of RAID and cabinet issues, the SSDs are going in the spare box in the rack.  We’ll then move the site over.  The hope is that evolve scripts get faster.  If the evolve scripts are bottlenecked elsewhere (e.g. ZEO single-threading), then that’s a different issue.</li>
<li>Read-only mode.  Perhaps we could leave the site in read-only mode during the update, with a little banner informing the user.  Preferably we could put the site in read-only mode without a restart.</li>
</ul>
<p>Any other ideas on minimizing downtime on such applications without major changes in architecture?</p>
  <a href="http://feeds.wordpress.com/1.0/gocomments/pauleveritt.wordpress.com/67/" rel="nofollow"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/pauleveritt.wordpress.com/67/"/></a> <a href="http://feeds.wordpress.com/1.0/godelicious/pauleveritt.wordpress.com/67/" rel="nofollow"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/pauleveritt.wordpress.com/67/"/></a> <a href="http://feeds.wordpress.com/1.0/gostumble/pauleveritt.wordpress.com/67/" rel="nofollow"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/pauleveritt.wordpress.com/67/"/></a> <a href="http://feeds.wordpress.com/1.0/godigg/pauleveritt.wordpress.com/67/" rel="nofollow"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/pauleveritt.wordpress.com/67/"/></a> <a href="http://feeds.wordpress.com/1.0/goreddit/pauleveritt.wordpress.com/67/" rel="nofollow"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/pauleveritt.wordpress.com/67/"/></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=pauleveritt.wordpress.com&amp;blog=5206833&amp;post=67&amp;subd=pauleveritt&amp;ref=&amp;feed=1"/></div>
    </content>
    <updated>2010-02-18T14:03:05Z</updated>
    <category term="KARL"/>
    <author>
      <name>Paul Everitt</name>
    </author>
    <source>
      <id>http://pauleveritt.wordpress.com</id>
      <logo>http://www.gravatar.com/blavatar/b4345850285023fbd98c4a40e02f7cbd?s=96&amp;d=http://s.wordpress.com/i/buttonw-com.png</logo>
      <link href="http://pauleveritt.wordpress.com/feed/" rel="self" type="application/atom+xml"/>
      <link href="http://pauleveritt.wordpress.com" rel="alternate" type="text/html"/>
      <link href="http://pauleveritt.wordpress.com/osd.xml" rel="search" type="application/opensearchdescription+xml"/>
      <subtitle>Paul's ramblings about projects and Python/Zope/Plone/Repoze/BFG technologies.</subtitle>
      <title>Chatterbox, Reloaded</title>
      <updated>2010-02-18T14:15:11Z</updated>
    </source>
  </entry>

  <entry xml:lang="en">
    <id>http://blog.repoze.org/PyCon%202010%20talk%3A%20Evolving%20Your%20Framework%20Under%20Fire/</id>
    <link href="http://blog.repoze.org/PyCon%202010%20talk%3A%20Evolving%20Your%20Framework%20Under%20Fire/" rel="alternate" type="text/html"/>
    <title xml:lang="en">PyCon 2010 talk: Evolving Your Framework Under Fire</title>
    <content type="xhtml" xml:lang="en"><div xmlns="http://www.w3.org/1999/xhtml"><p>Tres will be giving a talk at PyCon 2010 in Atlanta this Saturday at 2:15 PM.
The talk, entitled <a class="reference external" href="http://us.pycon.org/2010/conference/schedule/event/94/">Evolving Your Framework Under Fire</a> covers the
evolution of <a class="reference external" href="http://bfg.repoze.org/">BFG</a> as it was updated and extended
to support the needs of <a class="reference external" href="http://karlproject.org">KARL</a>,
a mission-critical knowledge management system commissioned by the
<cite>Open Society Institute </cite>.</p>
<p>The previous version of KARL was built on top of Plone, with more than
four hundred communities and 75,000+ content pages. The application had
evolved over several years, and had become increasingly difficult to
scale and extend. In addition, OSI was actively recruiting participation
in KARL from other, simliar organizations, whose own unique requirements
would have to be folded into the mix.</p>
<p>Over the course of six months, a small team built the new version of
KARL on top of the BFG framework, which we were simultaneously extending
and elaborating to support the needs of KARL. During that period, we
made more than forty releases of BFG, as well as releasing new versions
of many supporting packages. The 1.0 release of BFG followed shortly on
the successful launch of KARL in May, with subsequent versions
continuing to be informed by the needs of OSI and the other KARL users.</p>
<p>This talk discusses the process of evolving the BFG framework, with
particular emphasis on learning from the changes to the assumptions made
by the framework at its inception. We discuss also the tradeoffs in the
choice to include features in the framework versus leaving outside,
either in the application or in supporting libraries. Finally, the talk
proposes some general "lessons learned" which should be useful to Python
programmers building any sort of framework.</p>
<div class="section" id="talk-outline">
<h1>Talk Outline</h1>
<ul class="simple">
<li>BFG's original motivation and design.</li>
<li>Overview of the requirements for KARL</li>
<li>Key changes to the BFG framework during the project:<ul>
<li>adoption of documentation-driven development</li>
<li>replacing a number of the components which BFG initially depended on, with smaller or lighter-weight substitutes;</li>
<li>making other "standard" features (persistence / database integration) optional or replaceable;</li>
<li>removing performance-heavy "do-what-I-mean" features;</li>
<li>forcible converstion of text to unicode at all application boundaries;</li>
<li>adoption of a standard of 100% unit test coverage;</li>
<li>adding "url routing" as an option to "stock" object traversal.</li>
<li>enabling isolation of "customer-specific" policies and features from the core application code.</li>
</ul>
</li>
<li>Issues encountered during this process</li>
<li>State of BFG at OSI's KARL launch</li>
<li>Subsequent evolution of BFG</li>
<li>Lessons learned</li>
</ul>
</div></div>
    </content>
    <updated>2010-02-16T05:00:00Z</updated>
    <author>
      <name>Agendaless</name>
    </author>
    <source>
      <id>http://blog.repoze.org/index.atom</id>
      <link href="http://blog.repoze.org" rel="alternate" type="text/html"/>
      <link href="http://blog.repoze.org/index.atom" rel="self" type="application/atom+xml"/>
      <title xml:lang="en">Repoze Blog RSS Feed</title>
      <updated>2010-03-06T05:00:00Z</updated>
    </source>
  </entry>

  <entry xml:lang="en">
    <id>http://pauleveritt.wordpress.com/?p=65</id>
    <link href="http://pauleveritt.wordpress.com/2010/02/13/karl-news-calendar-formish-customization-admin-daemons-ssd/" rel="alternate" type="text/html"/>
    <title>KARL news: calendar, formish, customization, admin, daemons, SSD</title>
    <summary type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml">This has been the week of major KARL updates.  KARL is the open source collaboration and knowledge system published by the Open Society Institute.  It is an end-user product atop the BFG web framework.
Some recent happenings in KARL-land:

We are wrapping up a major improvement to the calendar tool. We introduced a concept of sub-calendar “layers” [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=pauleveritt.wordpress.com&amp;blog=5206833&amp;post=65&amp;subd=pauleveritt&amp;ref=&amp;feed=1"/></div>
    </summary>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><br/><p>This has been the week of major <a href="http://www.karlproject.org/">KARL</a> updates.  KARL is the open source collaboration and knowledge system published by the <a href="http://www.soros.org/">Open Society Institute</a>.  It is an end-user product atop the BFG web framework.</p>
<p>Some recent happenings in KARL-land:</p>
<ul>
<li>We are wrapping up a major improvement to the calendar tool. We introduced a concept of sub-calendar “layers” that can aggregate events from other communities.  More visibly, we completely re-did the UI with a new Weekly view and lots of Ajax sprinkling.</li>
<li>We also did most of the work to re-implement the entire form system using <a href="http://ish.io/projects/show/formish">io.formish</a>.  (<a href="http://svn.repoze.org/repoze.bfg.formish/trunk/docs/index.rst">repoze.bfg.formish</a> to be more precise.)  Big reduction in code and test code.  Still have a lot to think about on form controller patterns.  Those going to PyCon can hear Chris’s recounting of form controller torture in a panel he’s on about form frameworks.</li>
<li>Along with our friends at Six Feet Up as hosting partners, the KARL team is now operating KARL sites for five organizations.  KARL has a unique approach to customization, the inverse of the traditional Zope approach.  In KARL, a customization package is the starting point, and that pulls in the main software.  Or, doesn’t.  We just rolled out changes to thin out the size of each customization package.</li>
<li>Chris Rossi has been working on a web interfaces to a number of admin activities, including integration with Six Feet Up’s Zenoss monitoring.</li>
<li>KARL has a number of periodic admin jobs, for things such as processing incoming/outgoing mail, pulling in feed content, etc.  To date we had been running these as cron jobs.  However, we had cases where hundreds of crons got piled up.  In the latest updates, we converted these to Supervisor-managed jobs.  Risk involved, so we’ll see how it goes.</li>
<li>And finally, we are going to work with Six Feet Up to install solid-state disks.  Our initial test shows that an SSD alone, with no code refactoring, will completely eliminate our performance concerns on LiveSearch.  As well as benefit other catalog-constrained screens, possibly.  We’ll report back once we live with them for a while.</li>
</ul>
<p>All in all, KARL (like BFG) is humming along nicely.  Just to emphasize: KARL isn’t a framework.  It is an out-of-the-box product with a strong opinion.  By making such a deliberate choice to not boil multiple oceans, KARL gets to be very compact, very fast, and very stable.</p>
<p>That’s the key takeaway for people working on larger projects that have dynamic performance needs.  Unless your needs fit into Product X’s bulls-eye, you’re probably better off not beating Product X into submission.  Instead, we need an approach where assembling your own custom application, leaving out the parts you don’t need, is more feasible.</p>
<p>Not only is this a win for custom apps, IMO it’s actually a win for Product X.  Instead of having reputation beatdown when it doesn’t excel at Every Possible Thing, it can just say: “We’re good at X. If you want X, you want us.”  Then, focus scarce resources and reputation on being the best possible X.</p>
  <a href="http://feeds.wordpress.com/1.0/gocomments/pauleveritt.wordpress.com/65/" rel="nofollow"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/pauleveritt.wordpress.com/65/"/></a> <a href="http://feeds.wordpress.com/1.0/godelicious/pauleveritt.wordpress.com/65/" rel="nofollow"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/pauleveritt.wordpress.com/65/"/></a> <a href="http://feeds.wordpress.com/1.0/gostumble/pauleveritt.wordpress.com/65/" rel="nofollow"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/pauleveritt.wordpress.com/65/"/></a> <a href="http://feeds.wordpress.com/1.0/godigg/pauleveritt.wordpress.com/65/" rel="nofollow"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/pauleveritt.wordpress.com/65/"/></a> <a href="http://feeds.wordpress.com/1.0/goreddit/pauleveritt.wordpress.com/65/" rel="nofollow"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/pauleveritt.wordpress.com/65/"/></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=pauleveritt.wordpress.com&amp;blog=5206833&amp;post=65&amp;subd=pauleveritt&amp;ref=&amp;feed=1"/></div>
    </content>
    <updated>2010-02-13T21:08:41Z</updated>
    <category term="BFG"/>
    <category term="KARL"/>
    <author>
      <name>Paul Everitt</name>
    </author>
    <source>
      <id>http://pauleveritt.wordpress.com</id>
      <logo>http://www.gravatar.com/blavatar/b4345850285023fbd98c4a40e02f7cbd?s=96&amp;d=http://s.wordpress.com/i/buttonw-com.png</logo>
      <link href="http://pauleveritt.wordpress.com/feed/" rel="self" type="application/atom+xml"/>
      <link href="http://pauleveritt.wordpress.com" rel="alternate" type="text/html"/>
      <link href="http://pauleveritt.wordpress.com/osd.xml" rel="search" type="application/opensearchdescription+xml"/>
      <subtitle>Paul's ramblings about projects and Python/Zope/Plone/Repoze/BFG technologies.</subtitle>
      <title>Chatterbox, Reloaded</title>
      <updated>2010-02-18T14:15:11Z</updated>
    </source>
  </entry>

  <entry xml:lang="en">
    <id>http://pauleveritt.wordpress.com/?p=61</id>
    <link href="http://pauleveritt.wordpress.com/2010/02/13/bfg-news-book-1-2/" rel="alternate" type="text/html"/>
    <title>BFG News: Book, 1.2</title>
    <summary type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml">Big new happenings for the BFG web framework.  First, Chris has wrapped up the writing on a BFG book which you can get via Createspace or Amazon.  The book content is also available as open source.  However, buying via Createspace helps the author a bit more, so please feed the animals by grabbing a copy.
Chris [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=pauleveritt.wordpress.com&amp;blog=5206833&amp;post=61&amp;subd=pauleveritt&amp;ref=&amp;feed=1"/></div>
    </summary>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><br/><p>Big new happenings for the <a href="http://bfg.repoze.org/">BFG</a> web framework.  First, Chris has wrapped up the writing on a <a href="http://bfg.repoze.org/book">BFG book</a> which you can get via <a href="https://www.createspace.com/3422488">Createspace</a> or Amazon.  The book content is also available as open source.  However, buying via Createspace helps the author a bit more, so please feed the animals by grabbing a copy.</p>
<p>Chris recently <a href="http://plope.com/Members/chrism/self_publishing">documented</a> his experience writing the book.  I’ll add to it a bit.  Chris worked on this book.  And worked.  And worked hard.  Laboriously, fanatically, during the entire course of creating BFG.  In fact, the docs were released before the software, and every one of his million software releases included doc updates. In double fact, he used the book writing as a reason for improving and refactoring BFG.</p>
<p>If your idea of a good web framework includes one with scrupulous documentation (as well as 100% test coverage) then BFG is the right cultural fit for you.  Chris really is nuts, certifiably.</p>
<p>In more BFG news, Chris released BFG 1.2 recently with a <a href="http://docs.repoze.org/bfg/1.2/whatsnew-1.2.html">What’s New in 1.2</a> document.</p>
<p>The first highlight is an “imperative mode” that let’s you write almost nothing, import almost nothing, and postpone understanding big new concepts, but still get a real application going.  Follow the link and look for the first code example.</p>
<p>The other major highlight, from my perspective, is Jython support.</p>
<p>BFG has been experimenting with alternative approaches to “configuration”.  The imperative mode is part of the result, but the entire <a href="http://docs.repoze.org/bfg/1.2/narr/configuration.html">configuration story</a> is worth looking at.</p>
<p>Congrats, BFG and Chris.  The good story keeps getting better, with more people deploying sites, contributing, and giving tutorials at PyCon.</p>
  <a href="http://feeds.wordpress.com/1.0/gocomments/pauleveritt.wordpress.com/61/" rel="nofollow"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/pauleveritt.wordpress.com/61/"/></a> <a href="http://feeds.wordpress.com/1.0/godelicious/pauleveritt.wordpress.com/61/" rel="nofollow"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/pauleveritt.wordpress.com/61/"/></a> <a href="http://feeds.wordpress.com/1.0/gostumble/pauleveritt.wordpress.com/61/" rel="nofollow"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/pauleveritt.wordpress.com/61/"/></a> <a href="http://feeds.wordpress.com/1.0/godigg/pauleveritt.wordpress.com/61/" rel="nofollow"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/pauleveritt.wordpress.com/61/"/></a> <a href="http://feeds.wordpress.com/1.0/goreddit/pauleveritt.wordpress.com/61/" rel="nofollow"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/pauleveritt.wordpress.com/61/"/></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=pauleveritt.wordpress.com&amp;blog=5206833&amp;post=61&amp;subd=pauleveritt&amp;ref=&amp;feed=1"/></div>
    </content>
    <updated>2010-02-13T20:35:17Z</updated>
    <category term="Uncategorized"/>
    <author>
      <name>Paul Everitt</name>
    </author>
    <source>
      <id>http://pauleveritt.wordpress.com</id>
      <logo>http://www.gravatar.com/blavatar/b4345850285023fbd98c4a40e02f7cbd?s=96&amp;d=http://s.wordpress.com/i/buttonw-com.png</logo>
      <link href="http://pauleveritt.wordpress.com/feed/" rel="self" type="application/atom+xml"/>
      <link href="http://pauleveritt.wordpress.com" rel="alternate" type="text/html"/>
      <link href="http://pauleveritt.wordpress.com/osd.xml" rel="search" type="application/opensearchdescription+xml"/>
      <subtitle>Paul's ramblings about projects and Python/Zope/Plone/Repoze/BFG technologies.</subtitle>
      <title>Chatterbox, Reloaded</title>
      <updated>2010-02-18T14:15:11Z</updated>
    </source>
  </entry>

  <entry>
    <id>http://plope.com/Members/chrism/self_publishing</id>
    <link href="http://plope.com/Members/chrism/self_publishing" rel="alternate" type="text/html"/>
    <title>My Self-Publishing Experiences</title>
    <summary>My experiences self-publishing a technical book.</summary>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>Recently I authored a <a href="http://bfg.repoze.org/book">book about software</a>
.  My <a href="http://agendaless.com">company</a> self-published the book.  I
chose to self-publish the book rather than shop the book around to professional
publishing companies for a number of reasons:</p>
<p>1) Control.  The book contains the entirety of the <a href="http://docs.repoze.org/bfg/current">documentation for a piece of
   open source software</a> .  In my mind, this
   documentation must always be freely available; otherwise the
   platform isn't truly open source.  I neither wanted to offer
   another for-profit company a copyright on the material, nor did I
   want to lose any future flexibility, such as the ability
   to grant copyright to a foundation during a code transfer, etc.
   Retaining maximum control was a non-negotiable requirement.</p>
<p>2) Simplicity.  I didn't need to talk to anyone, or negotiate with
   anyone, or rationalize choices with anyone in order to get this
   book published.  I could just do it.</p>
<p>3) Quality.  I have heard some horror stories about publishers having
   low quality standards when it comes to layout and organization.  I
   felt I could do as good a job, if not a better one, than many
   publishers with respect to book quality and layout.</p>
<p>Now that the book has been published, I think I think the choice to
self-publish was a good one, and I'm extremely comfortable with the
result.</p>
<p>I've never published a book through a traditional publishing house.
But I know a good number of people who have.
Although self-publishing a book is a pain, from what I hear from other
authors who did not self-publish, it's not <em>that</em>
much more of a pain than publishing a book via a professional publishing company.</p>
<p>I chose to use <a href="http://createspace.com">Createspace</a> to help me with
self-publishing.  Createspace has a really good system for document review and
publication.  Basically you fill in a bunch of book info, provide them
two PDFs (one for the cover and one for the actual book content), and
they guide you through the process of publication.  You receive a
proof copy of the printed book before you need to make the book
available to the world.  Their proof and author copy prices are
excellent, their integration with Amazon and other book outlets is
very good, they provide an "eStore" presence for you, they handle
payment processing, and they give generous royalties.</p>
<p>I chose Createspace over <a href="http://lulu.com">Lulu</a> solely because I
thought Createspace would have better
Amazon.com integration than Lulu; Createspace is an Amazon subsidiary.  I have no way of actually knowing this for a
fact, because I've never used Lulu; they may have Amazon.com integration that is just as good.
Subsidiary relationships can be poor indicators: large company organization often means that subsidiaries
are effectively separate companies.  But the book showed up on
Amazon.com fairly quickly, and without any effort on my part, so it appears that Createspace and Amazon.com at least don't have
an <em>adversarial</em> relationship.</p>
<p>After being available for a week, the book has sold exactly 24 copies.
Most of the sales were via the <a href="https://www.createspace.com/3422488">eStore</a> provided by Createspace,
presumably due to my own marketing efforts. This is obviously a modest
number, but because we kept overhead reasonably low, we've almost
broken even on the hard cost of its publication already.  Book sales
alone will never recompense the time that went into writing it, but of
course I never expected them to.  Its availability is more of a
"presence" thing, and as long as we lose no money on it, and people
find the book worth its price, I'm happy.</p>
<p>One thing I didn't expect: it was extremely fun to be able to send out
gift copies of the book to major project contributors (internal and
upstream).  Although it's a poor gift in comparison to the time these
folks have spent making things that are useful to me, being able to
send some physical thing to people you usually communicate almost
purely electronically with is a novelty.  We should all do that more
often.</p>
<p>Some suggestions to potential technical book authors (the "if I had it
to do all over again" list):</p>

<ul>
<li>Don't underestimate the time it will take to do typesetting.<p>  While I wouldn't trade away the flexibility of self-publishing just
  in order to avoid doing my own typesetting, it is an extremely
  time-consuming, tedious effort.</p>
<p>  I used <a href="http://sphinx.pocoo.org">Sphinx</a> to generate LaTeX source.  I
  had to make a number of local modifications to Sphinx (which I later
  "contributed upstream" minimally via a maillist post) to make it
  write LaTeX suitable for a book.  This worked extremely well.  On
  the other hand, I became more familiar with LaTeX than I ever wanted
  to become while doing typestting for the book.  This was no fun, but
  I'm certain it would have been worse if I had used, say, OpenOffice,
  or Word or something.</p>
</li>
<li>Remember that most technical books have an international audience,
  and that shipping cost is a factor.<p>  I didn't really know how this worked when I published my book.  I
  knew enough that I made sure it would get an Amazon.com listing, but
  I really didn't understand that this didn't really mean reduced
  shipping rates for people in Europe.  I just sort of assumed it
  would show up in Amazon's localized sites (like Amazon.co.uk,
  Amazon.fr, etc).  But in order for the book to show up in
  country-specific sites, you need to take explicit steps; it doesn't
  just happen.  When people from Europe buy from Amazon.com as
  opposed to their localized Amazon site, shipping can cost $50, and
  understandably, as great as your book may be, most reasonable people
  just won't pay this much extra.  It will also take a long time to
  arrive.</p>
<p>  I have since taken steps to make sure that the book will show up on
  Amazon's localized sites eventually (it still doesn't yet), but I
  didn't find any way to make sure it all happened as a "big bang"
  where it was available everywhere all at once.  I don't really mind
  that it didn't happen as a big bang, but I would have preferred to
  know this beforehand, so I had a better response than "homina
  homina" when responding to complaints from people about localized
  availability and shipping rates.  My answer is now still lame
  ("please wait"), but at least I have one.</p>
</li>
<li>Secure a set of reviewers before you are ready to publish, and make
  sure you allot enough time for book review.<p>  I wanted this book to come out before <a href="http://us.pycon.org">PyCon</a> .
  By the time I had finalized the book copy and done the typesetting,
  I was in a place where giving reviewers a reasonable amount of time
  to review would have delayed the book publication beyond that time.
  Andrew Sawyers bailed me out by reviewing much of the book before
  publication, but if I hadn't had his help, I would have been out of
  luck.</p>
<p>  On finding reviewers.  Although I did send out a general request for reviewers to a related maillist,
  I wasn't brave enough to email individuals
  asking each if they would do technical book review. 
  I get requests every so often to do technical book review, and I
  almost always have to decline, because the compensation (usually a
  free book) usually can't justify the amount of work to do a good
  review unless the book topic aligns very closely with my own work.
  Due to my own reluctance to review tangential books, and because the
  topic is tangential to most (BFG isn't topping the popularity charts
  yet), I didn't want to put other folks in a place where they felt
  boxed in by such a request.  I also didn't really have a budget to
  offer potential reviewers anything beyond a free book.  I'm not sure
  how I'd do this differently in the future, but the book would only
  have been better with more reviewers.</p>
</li>

</ul>
<p>I'd definitely recommend that potential technical book authors
consider self-publishing rather than licensing their work to a
professional publisher.  There are tradeoffs, of course; if you go
with a publishing house, more copies of your book are likely to be
sold than if you self-publish and therefore also self-market.  But
often it <a href="http://philikon.wordpress.com/2009/12/14/open-content-i-finally-got-it/">just doesn't
matter</a>
; it certainly doesn't to me, anyway.</p>
<p>The availability of good physical-medium self-publishing facilities
like Createspace is maybe a bellwether for the future of book
publishing.  I suspect professional book publishers will need to
specialize even further, and offer better service, licensing terms,
and royalty structures.  I think this will be an overall improvement
for writers and consumers, although it may imply an extremely painful
adjustment for book publishing companies.
</p></div>
    </content>
    <updated>2010-02-12T15:01:01Z</updated>
    <category term="python"/>
    <category term="tech"/>
    <category term="zope"/>
    <author>
      <name>chrism</name>
    </author>
    <source>
      <id>http://plope.com</id>
      <link href="http://plope.com/python.rss" rel="self" type="application/atom+xml"/>
      <link href="http://plope.com" rel="alternate" type="text/html"/>
      <subtitle>Chris McDonough's Python Feed</subtitle>
      <title>Chris McDonough's Python Feed</title>
      <updated>2010-02-12T15:01:01Z</updated>
    </source>
  </entry>

  <entry xml:lang="en">
    <id>http://blog.ianbicking.org/?p=149</id>
    <link href="http://blog.ianbicking.org/2010/02/06/weave-client-side-data/" rel="alternate" type="text/html"/>
    <link href="http://blog.ianbicking.org/2010/02/06/weave-client-side-data/#comments" rel="replies" type="text/html"/>
    <link href="http://blog.ianbicking.org/2010/02/06/weave-client-side-data/feed/atom/" rel="replies" type="application/atom+xml"/>
    <title xml:lang="en">Weave: valuable client-side data</title>
    <summary xml:lang="en">I’ve been looking at Weave some lately.  The large-print summary on the page is Synchronize Your Firefox Experience Across Desktop and Mobile.  Straight forward enough.
Years and years ago I stopped really using bookmarks.  You lose them moving from machine to machine (which Weave could help), but mostly I stopped using them because [...]</summary>
    <content type="xhtml" xml:lang="en"><div xmlns="http://www.w3.org/1999/xhtml"><div class="document">
<p>I’ve been looking at <a class="reference external" href="https://mozillalabs.com/weave/">Weave</a> some lately.  The large-print summary on the page is <em>Synchronize Your Firefox Experience Across Desktop and Mobile</em>.  Straight forward enough.</p>
<p>Years and years ago I stopped really using bookmarks.  You lose them moving from machine to machine (which Weave could help), but mostly I stopped using them because it was too hard to (a) identify interesting content and place it into a taxonomy and (b) predict what I would later be interested in.  If I wanted to refer to something I’d seen before there’s a good chance I wouldn’t have saved it, while my bookmarks would be flooded with things that time would show were of transient interest.</p>
<p>So… synchronizing bookmarks, eh.  Saved form data and logins?  Sure, that’s handy.  It would make browsing on multiple machines <em>nicer</em>.  But it feels more like a handy tweak.</p>
<p>All my <em>really</em> useful data is kept on servers, categorized and protected by a user account.  Why is that?  Well, of course, where else would you keep it?  In cookies?  Ha!</p>
<p>Why not in cookies?  So many reasons… because cookies are opaque and can’t hold much data, can’t be exchanged, and probably worst of all they just disappear randomly.</p>
<p>What if cookies weren’t so impossibly lame for holding important data?  Suddenly sync seems much more interesting.  Instead of storing documents and data on a website, the website could put all that data right into your browser.  And conveniently <a class="reference external" href="http://en.wikipedia.org/wiki/DOM_storage">HTML 5 has an API for that</a>.  Everyone thinks about that API as a way of handling off-line caching, because while it handles many problems with cookies it doesn’t handle the problem of data disappearing as you move between computers and browser.  That’s where Weave synchronization could change things.  I don’t think this technique is something appropriate for every app (maybe not most apps), but it could allow a new class of applications.</p>
<p>Advantages: web development and scaling becomes easy.  If you store data in the browser scaling is almost free; serving static pages is a Solved Problem.  Development is easier because development and deployment of HTML and Javascript is pretty easy.  Forking is easy — just copy all the resources.  So long as you don’t hardcode absolute links into your Javascript, you can even just save from the browser and get a working local copy of the application.</p>
<p>Disadvantages: another silo.  You might complain about Facebook keeping everyone’s data, but the data in Facebook is <em>still</em> more transparent than data held in files or locally with a browser.  Let’s say you create a word processor that uses local storage for all its documents.  If you stored that document online sharing and collaboration would be really easy; but with it stored locally the act of sharing is not as automatic, and collaboration is <em>very hard</em>.  Sure, the "user" is in "control" of their data, but that would be more true on paper than in practice.  Building collaboration on top of local storage is hard, and without that… maybe it’s not that interesting?</p>
<p>Anyway, there is an interesting (but maybe Much Too Hard) problem in there.  (DVCS in the browser?)</p>
<p><strong>Update</strong>: in <a class="reference external" href="http://www.azarask.in/blog/post/you-centric-a-sketch-of-the-future-of-browsers/">this video</a> Aza talks about just what I talk about here.  A few months ago.  The Weave APIs also allude to things like this, including collaboration.  So… they are on it!</p>
</div></div>
    </content>
    <updated>2010-02-10T06:28:29Z</updated>
    <published>2010-02-06T23:03:49Z</published>
    <category scheme="http://blog.ianbicking.org" term="HTML"/>
    <category scheme="http://blog.ianbicking.org" term="Web"/>
    <author>
      <name>Ian Bicking</name>
      <uri>http://blog.ianbicking.org</uri>
    </author>
    <source>
      <id>http://blog.ianbicking.org/feed/atom/</id>
      <link href="http://blog.ianbicking.org" rel="alternate" type="text/html"/>
      <link href="http://blog.ianbicking.org/feed/atom/" rel="self" type="application/atom+xml"/>
      <title xml:lang="en">Ian Bicking: a blog</title>
      <updated>2010-03-06T00:32:29Z</updated>
    </source>
  </entry>

  <entry xml:lang="en">
    <id>http://blog.repoze.org/BFG%201.2%20Final%20Released/</id>
    <link href="http://blog.repoze.org/BFG%201.2%20Final%20Released/" rel="alternate" type="text/html"/>
    <title xml:lang="en">BFG 1.2 Final Released</title>
    <content type="xhtml" xml:lang="en"><div xmlns="http://www.w3.org/1999/xhtml"><p>We're proud to announce the latest major release of the repoze.bfg web
application framework, version 1.2.</p>
<p>It may be installed via:</p>
<blockquote>
easy_install -i <a class="reference external" href="http://dist.repoze.org/bfg/1.2/simple">http://dist.repoze.org/bfg/1.2/simple</a> repoze.bfg</blockquote>
<!-- or via PyPI. -->
<p>The most important feature addition in 1.2 is an "imperative" configuration
mode. This implies:</p>
<ul>
<li><p class="first">A repoze.bfg application can now be contained within a single Python file.</p>
</li>
<li><dl class="first docutils">
<dt>Developers are no longer required to use or understand ZCML to create a</dt>
<dd><p class="first last">repoze.bfg application (ZCML is, however still supported).</p>
</dd>
</dl>
</li>
</ul>
<p>See the "What's New in 1.2" document at
<a class="reference external" href="http://docs.repoze.org/bfg/1.2/whatsnew-1.2.html">http://docs.repoze.org/bfg/1.2/whatsnew-1.2.html</a> for a detailed list of new
features, changes, and backwards incompatibilities.</p>
<p>The docs at <a class="reference external" href="http://docs.repoze.org/bfg/1.2">http://docs.repoze.org/bfg/1.2</a> have been updated.  Additionally, a
printed book which includes the documentation has been published (see
<a class="reference external" href="http://bfg.repoze.org/book">http://bfg.repoze.org/book</a>).  The documentation has been extensively reworked
and restructured for the purposes of printing the book.</p>
<p>The 1.2 version of BFG replaces 1.1 as the "current" version, which means that
the index URL <a class="reference external" href="http://dist.repoze.org/bfg/current/simple">http://dist.repoze.org/bfg/current/simple</a> and the documentation
URL <a class="reference external" href="http://docs.repoze.org/bfg/current">http://docs.repoze.org/bfg/current</a> both now point at the 1.2 versions of
things.  The older 1.1 index is available via
<a class="reference external" href="http://dist.repoze.org/bfg/1.1/simple">http://dist.repoze.org/bfg/1.1/simple</a> and the older 1.1 docs are available via
<a class="reference external" href="http://docs.repoze.org/bfg/1.1">http://docs.repoze.org/bfg/1.1</a>.</p>
<p>Enjoy!</p></div>
    </content>
    <updated>2010-02-10T05:00:00Z</updated>
    <author>
      <name>Agendaless</name>
    </author>
    <source>
      <id>http://blog.repoze.org/index.atom</id>
      <link href="http://blog.repoze.org" rel="alternate" type="text/html"/>
      <link href="http://blog.repoze.org/index.atom" rel="self" type="application/atom+xml"/>
      <title xml:lang="en">Repoze Blog RSS Feed</title>
      <updated>2010-03-06T05:00:00Z</updated>
    </source>
  </entry>

  <entry xml:lang="en">
    <id>http://blog.ianbicking.org/?p=153</id>
    <link href="http://blog.ianbicking.org/2010/02/09/leaving-topp/" rel="alternate" type="text/html"/>
    <link href="http://blog.ianbicking.org/2010/02/09/leaving-topp/#comments" rel="replies" type="text/html"/>
    <link href="http://blog.ianbicking.org/2010/02/09/leaving-topp/feed/atom/" rel="replies" type="application/atom+xml"/>
    <title xml:lang="en">Leaving TOPP</title>
    <summary xml:lang="en">After three and a half years at The Open Planning Project, my time there is done.
For a while TOPP has been trying to find itself, to determine what it is that it can do best, and how to do that.  I think TOPP has finally started really figuring that out, focusing on civic participation, [...]</summary>
    <content type="xhtml" xml:lang="en"><div xmlns="http://www.w3.org/1999/xhtml"><div class="document">
<p>After three and a half years at <a class="reference external" href="http://openplans.org">The Open Planning Project</a>, my time there is done.</p>
<p>For a while TOPP has been trying to find itself, to determine what it is that it can do best, and how to do that.  I think TOPP has finally started really figuring that out, focusing on civic participation, revisiting "planning", and though it’s not fully developed there seems to be a strong potential for TOPP to serve as a point of collaboration for other more ad hoc open source government efforts: government workers and volunteers can provide substantial and well-informed development efforts, but the long-term shepherding of a project is difficult, and TOPP has the potential to provide that kind of long-term neutral guidance.  At the same time, communities of people have been developing around these issues; people have gotten past simply calling for government to be inclusive or transparent and have started to do the real work of making that happen.</p>
<p>But… unfortunately I won’t be able to figure out their next steps with them.  Mark Gorton has been very generous in his support of TOPP, and helped us get started.  But while he has been patient, and even at times seemingly immune from the economic trends… well, he’s not immune, and he has had to cut back his support for TOPP before we were able to become self-sufficient.  And so there have been layoffs, myself among them.</p>
<p>I suspect what I’ll do next will have a very different focus.  This feels a bit weird, a kind of lost identity.  Overall I’m feeling pretty optimistic about finding something new and interesting to do, but I’m still a bit melancholy about leaving things behind.  That TOPP and the people I’ve worked with are far away in New York makes it feel like more of a loss because I don’t know when I’ll be back next.  But onward and upward!  Now to find out what is next…</p>
</div></div>
    </content>
    <updated>2010-02-09T06:05:40Z</updated>
    <published>2010-02-09T06:05:40Z</published>
    <category scheme="http://blog.ianbicking.org" term="Non-technical"/>
    <author>
      <name>Ian Bicking</name>
      <uri>http://blog.ianbicking.org</uri>
    </author>
    <source>
      <id>http://blog.ianbicking.org/feed/atom/</id>
      <link href="http://blog.ianbicking.org" rel="alternate" type="text/html"/>
      <link href="http://blog.ianbicking.org/feed/atom/" rel="self" type="application/atom+xml"/>
      <title xml:lang="en">Ian Bicking: a blog</title>
      <updated>2010-03-06T00:32:29Z</updated>
    </source>
  </entry>

  <entry>
    <id>tag:blogger.com,1999:blog-4258103213764887486.post-6174586922576344652</id>
    <link href="http://www.blogger.com/feeds/4258103213764887486/posts/default/6174586922576344652" rel="edit" type="application/atom+xml"/>
    <link href="http://www.blogger.com/feeds/4258103213764887486/posts/default/6174586922576344652" rel="self" type="application/atom+xml"/>
    <link href="http://artificialcode.blogspot.com/2010/02/funniest-quote-about-python-in-2009.html" rel="alternate" type="text/html"/>
    <title>Funniest Quote About Python in 2009</title>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml">http://www.simple-talk.com/opinion/geek-of-the-week/interview-with-the-scary-dba-–-grant-fritchey/<br/><br/>"What do you see as the future of automating database administration? Will Powershell come to rule all or do you think Python will still have its fans?<br/>GF:<br/>PowerShell is going to take over. Microsoft is positioning it across all of its platforms and its various products such as Exchange and Operations Manager.<br/>While there's always going to be other languages used, like Python or Perl, they're going to be marginalized under a PowerShell juggernaut.<br/>"<br/> Powershell, seriously?<div class="blogger-post-footer"><img alt="" height="1" src="https://blogger.googleusercontent.com/tracker/4258103213764887486-6174586922576344652?l=artificialcode.blogspot.com" width="1"/></div></div>
    </content>
    <updated>2010-02-07T21:38:32Z</updated>
    <published>2010-02-07T21:34:00Z</published>
    <category scheme="http://www.blogger.com/atom/ns#" term="python"/>
    <author>
      <name>Noah Gift</name>
      <email>noreply@blogger.com</email>
      <uri>http://www.blogger.com/profile/13144332122855013229</uri>
    </author>
    <source>
      <id>tag:blogger.com,1999:blog-4258103213764887486</id>
      <author>
        <name>Noah Gift</name>
        <email>noreply@blogger.com</email>
        <uri>http://www.blogger.com/profile/13144332122855013229</uri>
      </author>
      <link href="http://artificialcode.blogspot.com/feeds/posts/default" rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml"/>
      <link href="http://www.blogger.com/feeds/4258103213764887486/posts/default" rel="self" type="application/atom+xml"/>
      <link href="http://artificialcode.blogspot.com/" rel="alternate" type="text/html"/>
      <link href="http://pubsubhubbub.appspot.com/" rel="hub" type="text/html"/>
      <link href="http://www.blogger.com/feeds/4258103213764887486/posts/default?start-index=26&amp;max-results=25" rel="next" type="application/atom+xml"/>
      <subtitle>This is Noah Gift's Coding Blog.  I only talk about coding and technical stuff here, and that is mostly Python, although I will mix in some other languages, and talk about Artificial Intelligence.</subtitle>
      <title>Artificial Code</title>
      <updated>2010-02-07T21:38:32Z</updated>
    </source>
  </entry>

  <entry xml:lang="en">
    <id>http://blog.repoze.org/BFG%20book%20available%20for%20purchase/</id>
    <link href="http://blog.repoze.org/BFG%20book%20available%20for%20purchase/" rel="alternate" type="text/html"/>
    <title xml:lang="en">BFG book available for purchase</title>
    <content type="xhtml" xml:lang="en"><div xmlns="http://www.w3.org/1999/xhtml"><p>The repoze.bfg Web Application Framework, Version 1.2" paperback is now
available for purchase:</p>
<p><a class="reference external" href="https://www.createspace.com/3422488">https://www.createspace.com/3422488</a></p>
<p>This is a high-quality printing of the along with extras such as a foreword
from Paul Everitt, an author introduction, and cool cover artwork from the guys
at Electrosoup (<a class="reference external" href="http://www.electrosoup.co.uk/">http://www.electrosoup.co.uk/</a>).  It is slightly over 500 pages
long.</p>
<p>If you like repoze and BFG, please show your support by buying a copy!</p>
<p>Book abstract:</p>
<p>repoze.bfg is a small, fast, down-to-earth, open source Python web development
framework. It makes real-world web application development and deployment more
fun, more predictable, and more productive.</p>
<p>This book will show you how to develop web applications using repoze.bfg and
Python step-by-step, including:</p>
<ul class="simple">
<li>Using SQLAlchemy and ZODB along with repoze.bfg.</li>
<li>Using built-in templating facilities to render HTML and XML.</li>
<li>Using repoze.bfg security functionality to protect your application.</li>
<li>Exending an existing repoze.bfg application without changing its source code.</li>
<li>Using sessions within repoze.bfg.</li>
<li>Running repoze.bfg under mod_wsgi.</li>
<li>Deploying your repoze.bfg application to Google's App Engine.</li>
</ul>
<p>This book is written by the primary author of repoze.bfg. It has developed
along with framework itself, and therefore contains the most accurate and up to
date information.</p></div>
    </content>
    <updated>2010-02-04T05:00:00Z</updated>
    <author>
      <name>Agendaless</name>
    </author>
    <source>
      <id>http://blog.repoze.org/index.atom</id>
      <link href="http://blog.repoze.org" rel="alternate" type="text/html"/>
      <link href="http://blog.repoze.org/index.atom" rel="self" type="application/atom+xml"/>
      <title xml:lang="en">Repoze Blog RSS Feed</title>
      <updated>2010-03-06T05:00:00Z</updated>
    </source>
  </entry>

  <entry>
    <id>http://plope.com/Members/chrism/bfg_book_available</id>
    <link href="http://plope.com/Members/chrism/bfg_book_available" rel="alternate" type="text/html"/>
    <title>The repoze.bfg Web Application Framework, Version 1.2 Book Published</title>
    <summary>A book about the 1.2 version of the repoze.bfg web  framework has been published.</summary>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p><em>The repoze.bfg Web Application Framework, Version 1.2</em> paperback book has been published and is now 
<a href="https://www.createspace.com/3422488">available for purchase via Createspace</a> .</p>
<p><a href="https://www.createspace.com/3422488"><img src="http://plope.com/misc/bfgbook_thumbnail.jpg"/></a></p>
<p>This is a high-quality printing of the <a href="http://docs.repoze.org/bfg/1.2">BFG docs</a> along with extras such as a foreword 
from Paul Everitt, an author introduction, and nifty cover artwork from the guys 
at <a href="http://www.electrosoup.co.uk">Electrosoup</a> .  It is slightly over 500 pages 
long.</p>
<p>If you like the Repoze project and BFG, please show your support by buying a copy.</p>
<p/><h2>Book abstract</h2><p/>
<p>repoze.bfg is a small, fast, down-to-earth, open source Python web development 
framework. It makes real-world web application development and deployment more 
fun, more predictable, and more productive.</p>
<p>This book will show you how to develop web applications using repoze.bfg and 
Python step-by-step, including:</p>

<ul>
<li>Using SQLAlchemy and ZODB along with repoze.bfg.</li>
<li>Using built-in templating facilities to render HTML and XML.</li>
<li>Using repoze.bfg security functionality to protect your application.</li>
<li>Exending an existing repoze.bfg application without changing its source code.</li>
<li>Using sessions within repoze.bfg.</li>
<li>Running repoze.bfg under mod_wsgi.</li>
<li>Deploying your repoze.bfg application to Google's App Engine.</li>

</ul>
<p>This book is written by the primary author of repoze.bfg. It has developed 
along with framework itself, and therefore contains the most accurate and up to 
date information.</p>
<p/><h2>About the Author</h2><p/>
<p>Chris McDonough is the primary author of the repoze.bfg web application framework.
He is a Python developer and consultant for Agendaless Consulting, a company based in
Fredericksburg, VA, USA. His other major projects include Supervisor, a Python process management system.
</p></div>
    </content>
    <updated>2010-02-03T22:21:17Z</updated>
    <category term="python"/>
    <category term="tech"/>
    <category term="zope"/>
    <author>
      <name>chrism</name>
    </author>
    <source>
      <id>http://plope.com</id>
      <link href="http://plope.com/python.rss" rel="self" type="application/atom+xml"/>
      <link href="http://plope.com" rel="alternate" type="text/html"/>
      <subtitle>Chris McDonough's Python Feed</subtitle>
      <title>Chris McDonough's Python Feed</title>
      <updated>2010-02-12T15:01:01Z</updated>
    </source>
  </entry>

  <entry>
    <id>http://plope.com/Members/chrism/succeeding_poorly</id>
    <link href="http://plope.com/Members/chrism/succeeding_poorly" rel="alternate" type="text/html"/>
    <title>The Curse of Allowing People to Succeed Poorly</title>
    <summary>The punishment for allowing people to succeed poorly?  Death.</summary>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>People <em>hate</em> systems that allow them to succeed poorly.  They hate
such systems even more than systems that don't allow them to succeed
at all.  People will forgive systems that don't allow them to succeed;
they will never forgive a system that allowed them to succeed poorly.</p>
<p>This is because, by allowing a person to succeed poorly, you have
tricked them into believing a problem is solved and that they may move
on to the next problem.  The problem, however, is not solved.  The
problem remains, papered over by something that only makes it appear
solved.  Because the problem was not solved, the implementor will
eventually need to revisit the problem.  Except now instead of just
having one problem to solve, he'll have two: he'll have to re-solve
the original problem, then he'll have to figure out how to make the
code that implemented the previous (poor) solution work on top of new
code for backwards compatibility purposes.</p>
<p>It's hard enough to solve a problem in "green-fields" coding; needing
to carry along the burden of backwards compatibility with older code
and possibly rebasing old code on top of the new solution makes it at
least twice as hard.  Sometimes ten times as hard.</p>
<p>This is why people hate software that allows them to succeed poorly.
It makes 2-10 times as much work for them in the long run.  It would
be far better if the software they chose either a) allowed them to
succeed optimally or b) allowed them to fail very quickly.</p>
<p>The very most potent vitriol is reserved for systems which allow
people to succeed poorly.  Consider the hatred unleashed on public
forums, even today, <em>ten years later</em> for Zope 2 features like TTW
coding, large-ZODB-objects-as-blobs and implicit acquisition.  All of
these technologies provided solutions (albeit not full ones) for real
problems at the time and they became widely used.  Each one of these
things allowed people to do things that were previously very difficult
with very little effort.  But ultimately, solutions based on these
systems needed to be revisited due to performance problems,
testability, and code comprehension.  All have been largely sunsetted,
because it was recognized that the development effort required to
allow people to truly succeed when using them would be enormous.</p>
<p>But still, people <em>actively</em> hate them and will go out of their way to
tell others so (usually in a brutal form like "Zope sucks").  <em>Ten
years later</em>.  Do you see vitriol like this for technologies that
people failed entirely with?  No.  This is because these people
felt fooled and betrayed in the long run.</p>
<p>What's the takeaway?  If you're going to introduce a feature to code
that other people rely on, start by <em>documenting it</em>.  If you cannot
document it adequately, or you find that you may need to spend an
inordinate amount of time creating code that makes the feature not
suck, don't add the feature.  Only add the feature when you can both
document the feature itself <em>and its failure modes</em>.  Be conservative
about what you offer.  You can always add features; you can never take
them away.  If you do add a feature, make sure that it doesn't
pretend to do more than it actually does.  Allow its common usage
to have a "fail quickly" path.
</p></div>
    </content>
    <updated>2010-01-29T16:46:57Z</updated>
    <category term="python"/>
    <category term="tech"/>
    <category term="zope"/>
    <author>
      <name>chrism</name>
    </author>
    <source>
      <id>http://plope.com</id>
      <link href="http://plope.com/python.rss" rel="self" type="application/atom+xml"/>
      <link href="http://plope.com" rel="alternate" type="text/html"/>
      <subtitle>Chris McDonough's Python Feed</subtitle>
      <title>Chris McDonough's Python Feed</title>
      <updated>2010-02-12T15:01:01Z</updated>
    </source>
  </entry>

  <entry xml:lang="en">
    <id>http://blog.repoze.org/A%20Few%20Links.../</id>
    <link href="http://blog.repoze.org/A%20Few%20Links.../" rel="alternate" type="text/html"/>
    <title xml:lang="en">A Few Links...</title>
    <content type="xhtml" xml:lang="en"><div xmlns="http://www.w3.org/1999/xhtml"><p>Darryl Cousins gives us a blog post explaining <a class="reference external" href="http://darrylcousins.blogspot.com/2010/01/repoze-bfg-on-google-app-engine.html">BFG on Google App Engine</a> including test coverage support.</p>
<p>Srikanth Suri gives us a blog post showing how he has <a class="reference external" href="http://srikanth-suri.blogspot.com/2010/01/cataloging-objects-in-bfg.html">integrated BFG with repoze.catalog</a>.</p></div>
    </content>
    <updated>2010-01-29T05:00:00Z</updated>
    <author>
      <name>Agendaless</name>
    </author>
    <source>
      <id>http://blog.repoze.org/index.atom</id>
      <link href="http://blog.repoze.org" rel="alternate" type="text/html"/>
      <link href="http://blog.repoze.org/index.atom" rel="self" type="application/atom+xml"/>
      <title xml:lang="en">Repoze Blog RSS Feed</title>
      <updated>2010-03-06T05:00:00Z</updated>
    </source>
  </entry>

  <entry xml:lang="en">
    <id>http://pauleveritt.wordpress.com/?p=57</id>
    <link href="http://pauleveritt.wordpress.com/2010/01/25/performance-and-memory-usage-for-karl/" rel="alternate" type="text/html"/>
    <title>Performance and memory usage for KARL</title>
    <summary type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml">I’ve enjoyed seeing some writeups on requests/second and memory usage for upcoming versions of Plone.  It’s great to see things trending in that direction.  Hopefully with some tough choices and deprecation, more gains can be made (just my personal opinion.)
I thought I’d give a primitive try at the same numbers for KARL, the collaboration application [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=pauleveritt.wordpress.com&amp;blog=5206833&amp;post=57&amp;subd=pauleveritt&amp;ref=&amp;feed=1"/></div>
    </summary>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><br/><p>I’ve enjoyed seeing some <a href="http://jstahl.org/archives/2010/01/19/plone-4-three-times-faster-than-drupal-joomla-or-wordpress/">writeups</a> on requests/second and memory usage for <a href="http://blog.hannosch.eu/2010/01/plone-4-how-much-faster-is-it.html">upcoming versions</a> of Plone.  It’s great to see things trending in that direction.  Hopefully with some tough choices and deprecation, more gains can be made (just my personal opinion.)</p>
<p>I thought I’d give a primitive try at the same numbers for KARL, the collaboration application atop BFG that we’ve been working on and deploying to customers.</p>
<p>Using the ‘ab -n 100 -c 2′ on my first gen MacBook 2 GHz, 2 Gb of RAM, I leveled off at just over <strong>134 requests per second</strong>.  Memory usage was <strong>31 Mb</strong>.</p>
<p>Obviously it’s not an apples-apples comparison.  The feature set is smaller.  Although we do have cataloging, text search, workflow, security, and the like, there’s a ton of stuff we don’t do.  We’re an end-user application with specific features, versus a framework.</p>
<p>On the other hand, all requests in KARL are authenticated and fully-dynamic.  So the 137 rps above?  That’s our slow number: authenticated, personalized, security-aware, fully dynamic.</p>
<p>For more fun, we recently built an ugly, cheap Core i5 box in the Agendaless office for $600, with 4 Gb of RAM.  In production we deploy under modwsgi, so we fired it up to have 3 processes (for 3 of the four cores).  We also have a script that lets us bulk load 300 sample communities, each containing a bunch of content.</p>
<p>That’s a bit more realistic of a test, since we start paying the price of having content in the catalog.</p>
<p>In that “with content” test, we got 349 requests/second.</p>
<p>Sometime soon we’re going to think a bit harder about a more realistic test.  Pounding the same URL over and over as the same user just doesn’t mean squat.  Well, it’s valuable in so much as it is a veto: if your numbers are pathetically low on the fastest-possible “test”, it’s only going to get worse.  We are slowing building up some Funkload scripts that cover a scenario which includes different users, different activities, and some writes as well as reads.</p>
<p>We need this as we are evaluating various KARL ideas in 2010.  First and foremost, we bought a solid-state disk for the test box.  We had a query (prefix match on text search, where only one letter was entered) which blew up our system previously.  Think, 60+ seconds.  That time fell down to 2 with the SSD.</p>
<p>Next, we’d like to see some before/after on RelStorage using some real-world scenarios.  Finally, I’d like to see some before/after on repoze.pgtextindex, where we swap out just one of our catalog index types (the text one) with transactional text indexing in Postgresql.</p>
  <a href="http://feeds.wordpress.com/1.0/gocomments/pauleveritt.wordpress.com/57/" rel="nofollow"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/pauleveritt.wordpress.com/57/"/></a> <a href="http://feeds.wordpress.com/1.0/godelicious/pauleveritt.wordpress.com/57/" rel="nofollow"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/pauleveritt.wordpress.com/57/"/></a> <a href="http://feeds.wordpress.com/1.0/gostumble/pauleveritt.wordpress.com/57/" rel="nofollow"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/pauleveritt.wordpress.com/57/"/></a> <a href="http://feeds.wordpress.com/1.0/godigg/pauleveritt.wordpress.com/57/" rel="nofollow"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/pauleveritt.wordpress.com/57/"/></a> <a href="http://feeds.wordpress.com/1.0/goreddit/pauleveritt.wordpress.com/57/" rel="nofollow"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/pauleveritt.wordpress.com/57/"/></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=pauleveritt.wordpress.com&amp;blog=5206833&amp;post=57&amp;subd=pauleveritt&amp;ref=&amp;feed=1"/></div>
    </content>
    <updated>2010-01-25T19:11:07Z</updated>
    <category term="BFG"/>
    <category term="KARL"/>
    <author>
      <name>Paul Everitt</name>
    </author>
    <source>
      <id>http://pauleveritt.wordpress.com</id>
      <logo>http://www.gravatar.com/blavatar/b4345850285023fbd98c4a40e02f7cbd?s=96&amp;d=http://s.wordpress.com/i/buttonw-com.png</logo>
      <link href="http://pauleveritt.wordpress.com/feed/" rel="self" type="application/atom+xml"/>
      <link href="http://pauleveritt.wordpress.com" rel="alternate" type="text/html"/>
      <link href="http://pauleveritt.wordpress.com/osd.xml" rel="search" type="application/opensearchdescription+xml"/>
      <subtitle>Paul's ramblings about projects and Python/Zope/Plone/Repoze/BFG technologies.</subtitle>
      <title>Chatterbox, Reloaded</title>
      <updated>2010-02-18T14:15:11Z</updated>
    </source>
  </entry>

  <entry>
    <id>http://plope.com/Members/chrism/zope_view_adapter_ordering</id>
    <link href="http://plope.com/Members/chrism/zope_view_adapter_ordering" rel="alternate" type="text/html"/>
    <title>Zope Views: should have been "request, context"; not "context, request"</title>
    <summary>Zope views should have been defined as accepting (request, context) rather than (context, request).</summary>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>Yawn.  Boring.  I'll post it anyway,
though.</p>
<p>The Zope "multiadapter" machinery lookup algorithm isn't defined or
documented in any sort of human-consumable way anywhere.  So you'll
have to trust me on the following.  It's almost incomprehensible
anyway, so if you have a low tolerance for details, don't bother
trying to understand this.</p>
<p>Zope views are multiadapters on ``(context, request)``.  When you say
please adapt <code>(context, request)</code> to <code>IView</code>, it does more or less
this:</p>

<ul>
<li>Give me every interface provided by <code>context</code>.</li>
<li>From most specific to least specific interface provided by
  <code>context</code>, search the "first" slot in the registry for further
  lookup information.</li>
<li>If something is found in the first slot that is registered for any
  of the interfaces of context, continue on to look for an adapter
  based on the <code>request</code> object.</li>

</ul>
<p>In terms of a registry represented by a dictionary and a pseudocode
implementation of getMultiAdapter, it looks a bit like this:
</p><pre>  def getMultiAdapter(objects, target=Interface):
      num = len(objects)
      info = registry[num][target]
      for object in objects:
          items = providedBy(object)
          for item in items:
             rest = info.get(item)
             if rest is not None:
                break
          if rest is None:
              raise ComponentLookupError
          info = rest
      return info(*objects)
</pre>
<p/>
<p>This isn't quite right, because some backtracking happens when a
secondary lookup fails, and we're disregarding the adapter name, but
for our purposes it's close enough.</p>
<p>Let's also take for granted we have some
interfaces:
</p><pre>  from zope.interface import Interface

  class IRequest(Interface): pass
  class ISpecializedRequest(IRequest): pass
  class IContext(Interface): pass
</pre>
<p/>
<p>In such a setup, when you then do 
this:
</p><pre>  registry = {2:{IView:{IContext:{IRequest:adapter}}}}

  directlyProvides(context, IContext)
  directlyProvides(request, IRequest)

  getMultiAdapter((context, request), IView)
</pre>
<p/>
<p>You will get back the result of "adapter" in our faux registry.  This
is well and good.  However, there is a corner case lurking here that
is not well and good.</p>
<p>For view lookups, I actually think the historical Zope ordering of
<code>(context, request)</code> is not correct.  It should actually likely be
<code>(request, context)</code>.  If you take this to its logical "worldview"
conclusion, I think this means that Zope view class constructors
should have been made to accept <code>(request, context)</code> rather than
<code>(context, request)</code>.</p>
<p>Why?  Well, as a general rule, due to the lookup algorithm above, you
almost always want to create multiadapters with arguments ordered in
such a way that "provides" registration arguments <em>more</em> likely to be
for specific interfaces come before "provides" registration arguments
that are <em>less</em> likely to be for specific interfaces.</p>
<p>View registrations are always made for some very specific request
(e.g. IRequest) interface, but often they are made for a very weakly
binding context interface, sometimes just "Interface".  "Interface" is
implemented by <em>everything</em>.</p>
<p>For example, the <code>(context, request)</code> ordering breaks down a bit when
you have a registry populated as follows:
</p><pre>  registry = {2:
                {IView:
                  {IContext:{IRequest:adapter}},
                  {Interface:{ISpecializedRequest:anotheradapter}},
                }
             }
</pre>
<p/>
<p>And you do 
this:
</p><pre>  directlyProvides(context, IContext)
  directlyProvides(request, ISpecializedRequest)

  getMultiAdapter((context, request), IView)
</pre>
<p/>
<p>You will <em>still</em> get back the result of "adapter" even though it's
likely that you really wanted to get back the result of "anotheradapter".</p>
<p>Why would you expect to get back the result of "anotheradapter"?  It's
an extremely uncommon thing to do to put a specialized interface on
the request and to make registrations for this specialized request
type.  You almost always want to find adapters registered for the
request interface first, even if the registration context interface is
"more binding".
</p></div>
    </content>
    <updated>2010-01-24T17:00:51Z</updated>
    <category term="python"/>
    <category term="tech"/>
    <category term="zope"/>
    <author>
      <name>chrism</name>
    </author>
    <source>
      <id>http://plope.com</id>
      <link href="http://plope.com/python.rss" rel="self" type="application/atom+xml"/>
      <link href="http://plope.com" rel="alternate" type="text/html"/>
      <subtitle>Chris McDonough's Python Feed</subtitle>
      <title>Chris McDonough's Python Feed</title>
      <updated>2010-02-12T15:01:01Z</updated>
    </source>
  </entry>

  <entry xml:lang="en">
    <id>http://blog.repoze.org/Jarn%20Builds%20TribaSpace%20on%20BFG/</id>
    <link href="http://blog.repoze.org/Jarn%20Builds%20TribaSpace%20on%20BFG/" rel="alternate" type="text/html"/>
    <title xml:lang="en">Jarn Builds TribaSpace on BFG</title>
    <content type="xhtml" xml:lang="en"><div xmlns="http://www.w3.org/1999/xhtml"><p><a class="reference external" href="http://jarn.com">Jarn</a> has built <a class="reference external" href="http://tribaspace.com">Tribaspace</a> using BFG and a collection of other technologies.  The site is still in beta, but Tribaspace is a promotion site for fashion-related events.  Looks good. ;-)</p></div>
    </content>
    <updated>2010-01-22T05:00:00Z</updated>
    <author>
      <name>Agendaless</name>
    </author>
    <source>
      <id>http://blog.repoze.org/index.atom</id>
      <link href="http://blog.repoze.org" rel="alternate" type="text/html"/>
      <link href="http://blog.repoze.org/index.atom" rel="self" type="application/atom+xml"/>
      <title xml:lang="en">Repoze Blog RSS Feed</title>
      <updated>2010-03-06T05:00:00Z</updated>
    </source>
  </entry>

  <entry xml:lang="en">
    <id>http://blog.repoze.org/Seantis%20releases%20BFG-based%20invoicing%20application/</id>
    <link href="http://blog.repoze.org/Seantis%20releases%20BFG-based%20invoicing%20application/" rel="alternate" type="text/html"/>
    <title xml:lang="en">Seantis releases BFG-based invoicing application</title>
    <content type="xhtml" xml:lang="en"><div xmlns="http://www.w3.org/1999/xhtml"><p>Fabian Reinhard from Seantis gmbh wrote to let us know that his company
has released a BFG-based invoicing application:</p>
<pre class="literal-block">First, thanks so much for your hard work on repoze!!
We are coming the long way from Zope/Plone and it's just amazing to play
with this new toy!

We just released a small app for invoicing: http://invoice.seantis.ch

Might be useful for other people out there since invoicing seems to be a
quite common use case! :-)
</pre>
<p><a class="reference external" href="http://invoice.seantis.ch">Check it out!</a>  It looks like a really nice application!</p></div>
    </content>
    <updated>2010-01-21T05:00:00Z</updated>
    <author>
      <name>Agendaless</name>
    </author>
    <source>
      <id>http://blog.repoze.org/index.atom</id>
      <link href="http://blog.repoze.org" rel="alternate" type="text/html"/>
      <link href="http://blog.repoze.org/index.atom" rel="self" type="application/atom+xml"/>
      <title xml:lang="en">Repoze Blog RSS Feed</title>
      <updated>2010-03-06T05:00:00Z</updated>
    </source>
  </entry>

  <entry>
    <id>http://plope.com/Members/chrism/extreme_danger</id>
    <link href="http://plope.com/Members/chrism/extreme_danger" rel="alternate" type="text/html"/>
    <title>Extreme Danger</title>
    <summary>Programming extremism is dangerous.</summary>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>Once a programmer latches on to some process or idea that makes him
more sucessful, he tends to treat it like a subroutine, calling in to
it over and over again to get his job done.  It becomes part of his
fundamental toolkit.</p>
<p>However, over time, for some reason, programmers also seem to forget
that the helpful process or idea they found is just a mechanism, and
not some sort of natural law.  As a result, sometimes the helpful
process or concept itself becomes dogma.  Dogma is a form of
extremism: the belief that an idea is superior even when there's scant
proof of its superiority, or when there is existence proof to the
contrary.</p>
<p>Using dogma is almost never useful except in one very specific
circumstance.  Your can use dogma successfully to box someone very
inexperienced into a particular worldview for the purpose of getting output from
them: inexperienced programmers are willing to accept a limited
worldview, filled with all sorts of dogma, because they often lack the
experience to make otherwise reasoned decisions.  Dogma actually helps
inexperienced programmers produce things, because they don't get wrapped around as
many axles when trying to make decisions about how to get something
done: to them, dogma acts as a bridge between a problem and a
solution.  Without the dogma, they might <em>never</em> reach a solution.</p>
<p>But sometimes, it can hurt.  Let's take, for example, treatises on
testing.  I see lots of blog posts with this theme: "test-driven
development helps me, because, at the end of the process, I wind up
with a codebase that has tests."  Such posts might mention other
benefits, such as "test-first" as a design aid, but the central theme
of the blog post usually marvels at the idea that the author can later
refactor his codebase without unintentionally breaking it.  To the
author of the blog post "test-driven-development" <em>is</em> testing; there
is no other kind.  To suggest that you might write tests <em>after</em> you
write a bit of code would be an anathema to such a person, because
they believe that the process of testing simply cannot be accomplished
without test-first.  And it takes a lot of time to convince them otherwise;
time that could have been used to actually do something useful.</p>
<p>Lots of programmers do indeed test-last (or at least
test-during) without any noticeable difference in code quality.  I
personally don't mind if people use test-first (aka test-driven)
development or test-last, as long as they wind up with good tests at the end. 
As long as the design works out OK, and the code is tested,
the path you take to reach "good tests" should be negotiable.
Dictating a particular process to reach that goal is often not helpful.</p>
<p>The same criticism applies to any insistence that some particular
technology or library or approach is always better than another, no
matter what the circumstance.  Questioning a dogma in such
circumstances can be fraught with peril, both interpersonal and
political, but to reach an optimum <em>technical</em> solution, questioning dogma almost
always has to be done.  But sometimes its better to optimize for the
best <em>interpersonal</em> solution rather than the best technical one: "pick
your battles". Deciding when to question dogma and when to
leave well enough alone is an art, I think.</p>
<p>I think the phenomena of dogma might be explained by the nature of the
job. Programmers need to tell a really, really dumb and unforgiving
box "do this, then do this" over and over and over.  It's quite easy
to forget that humans can operate with more incomplete data, and can
produce the same meaning from a set of inputs using radically
different thought processes and activities.
</p></div>
    </content>
    <updated>2010-01-08T15:48:17Z</updated>
    <category term="python"/>
    <category term="tech"/>
    <category term="zope"/>
    <author>
      <name>chrism</name>
    </author>
    <source>
      <id>http://plope.com</id>
      <link href="http://plope.com/python.rss" rel="self" type="application/atom+xml"/>
      <link href="http://plope.com" rel="alternate" type="text/html"/>
      <subtitle>Chris McDonough's Python Feed</subtitle>
      <title>Chris McDonough's Python Feed</title>
      <updated>2010-02-12T15:01:01Z</updated>
    </source>
  </entry>

  <entry>
    <id>http://plope.com/Members/chrism/bfg_platform_support</id>
    <link href="http://plope.com/Members/chrism/bfg_platform_support" rel="alternate" type="text/html"/>
    <title>BFG Platform Support</title>
    <summary>BFG runs on UNIX, Windows, GAE, and Jython now.</summary>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p><a href="http://bfg.repoze.org">BFG</a> platform support is really very good at
this point.  The latest release of BFG (1.2a11) supports the following
platforms:</p>

<ul>
<li>UNIX (CPython)</li>
<li>Windows (CPython)</li>
<li>Google App Engine</li>
<li>Jython</li>

</ul>
<p>I haven't tried it on PyPy.  If someone has the gumption to try it out
and help out a bit when it breaks, I'll try to make it work on PyPy
too.</p>
<p>The reason we can support these platforms: BFG's dependency set is
tiny.  It's reasonably easy to make them all work on arbitrary
platforms.  Less software really is an asset.</p></div>
    </content>
    <updated>2010-01-06T01:45:02Z</updated>
    <category term="python"/>
    <category term="tech"/>
    <category term="zope"/>
    <author>
      <name>chrism</name>
    </author>
    <source>
      <id>http://plope.com</id>
      <link href="http://plope.com/python.rss" rel="self" type="application/atom+xml"/>
      <link href="http://plope.com" rel="alternate" type="text/html"/>
      <subtitle>Chris McDonough's Python Feed</subtitle>
      <title>Chris McDonough's Python Feed</title>
      <updated>2010-02-12T15:01:01Z</updated>
    </source>
  </entry>

  <entry xml:lang="en">
    <id>http://blog.repoze.org/BFG%201.2%20on%20Jython/</id>
    <link href="http://blog.repoze.org/BFG%201.2%20on%20Jython/" rel="alternate" type="text/html"/>
    <title xml:lang="en">BFG 1.2 on Jython</title>
    <content type="xhtml" xml:lang="en"><div xmlns="http://www.w3.org/1999/xhtml"><p>Eduardo Diaz <a class="reference external" href="http://ediaz.me/2010/01/repoze-bfg-on-jython-2-5/">blogs about running repoze.bfg on Jython</a>.  Given Eduardo did a lot of work to get it mostly-running, we'll try to make it a supported platform.</p></div>
    </content>
    <updated>2010-01-05T05:00:00Z</updated>
    <author>
      <name>Agendaless</name>
    </author>
    <source>
      <id>http://blog.repoze.org/index.atom</id>
      <link href="http://blog.repoze.org" rel="alternate" type="text/html"/>
      <link href="http://blog.repoze.org/index.atom" rel="self" type="application/atom+xml"/>
      <title xml:lang="en">Repoze Blog RSS Feed</title>
      <updated>2010-03-06T05:00:00Z</updated>
    </source>
  </entry>

  <entry>
    <id>http://plope.com/Members/chrism/bfg_12_imperative_config</id>
    <link href="http://plope.com/Members/chrism/bfg_12_imperative_config" rel="alternate" type="text/html"/>
    <title>Imperative Configuration in BFG 1.2</title>
    <summary>A short description of the "imperative configuration" mode present in BFG 1.2+.</summary>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>Yesterday I blogged about the <a href="http://www.plope.com/Members/chrism/bfg_view_dispatch">view predicates</a> feature of
<a href="http://bfg.repoze.org">repoze.bfg</a> 1.1 .  BFG 1.1 was released several
months ago, and since that time, we've had a good number of alpha
releases of the subsequent major release, 1.2.  The most recent
version in the 1.2 line as of this writing is 1.2a9.  1.2 final is due
out within the next few weeks.</p>
<p>The most important new feature in the BFG 1.2 line is "imperative
configuration".  "Imperative configuration" is a funny,
loaded term so let's take it one word at a time.</p>
<p>Imperative: this term contrasts a requirement in previous releases
that configuration be at least partially <em>declarative</em>.  In BFG
releases prior to 1.2, it was necessary to have at least two files for
any given application: a Python file representing the code and a
<a href="http://worldcookery.com/files/ploneconf05-five/step2.html">ZCML</a> file.</p>
<p>Configuration: "configuration" in terms of BFG means the stuff that
wires up specific URLs to specific views, or that wires up up event
subscribers to event emissions, etc.  The stuff that turns the BFG
framework into a particular application deployment.</p>
<p>The declarative configuration "story" provided by BFG is stolen almost
entirely from Zope.  The <code>zope.configuration</code> package is used to
process declarations made in ZCML files.  These declarations mutate an
"application registry", adding various registrations as the ZCML files
are processed.  At the end of processing, the application registry
represents all the stuff needed to run a particular application.</p>
<p>In BFG 1.0 and 1.1, you were <em>required</em> to have at least one ZCML file
per application.  This ZCML file, in turn, needed to contain at least
one statement in it: one which kicked off a "scan", which is a process
that scans a package or module for view configuration decorators.
Alternately, you were permitted to disuse view decorators entirely and
configure view mappings via <code>&lt;view&gt;</code> declarations.</p>
<p>The requirement that a ZCML file exist in 1.0 and 1.1 was a holdover from BFG's Zope
heritage.  In BFG 1.2+, it is possible to create an application
<em>entirely</em> in Python without any ZCML (or even any decorators) in
sight.  For example:
</p><pre>   from webob import Response
   from paste.httpserver import serve
   from repoze.bfg.configuration import Configurator

   def hello_world(request):
       return Response('Hello world!')

   def goodbye_world(request):
       return Response('Goodbye world!')

   if __name__ == '__main__':
       config = Configurator()
       config.begin()
       config.add_view(hello_world)
       config.add_view(goodbye_world, name='goodbye')
       config.end()
       app = config.make_wsgi_app()
       serve(app)
</pre>
<p/>
<p>If you put this stuff in a Python file, and invoke it with an
interpreter that has the <code>repoze.bfg</code> software installed, you'll get a
running helloword application.  The <code>add_view</code> method of the
configurator does effectively the same thing as a ZCML <code>&lt;view&gt;</code>
declaration; in fact the ZCML view directive code calls into this method
when a ZCML <code>&lt;view&gt;</code> declaration is found.</p>
<p>While it's sort of neat to be able to run an application as a single
file, it is sort of a "gee whiz" feature that isn't very useful in
practice.  Every sizeable application will eventually need to split
itself across multiple files.  But the act of making this <em>possible</em>
really helped me clean up the code a lot; rather than coding for
configurability via ZCML, and then adding weird sort of stubs for
testability, the Configurator can be used to configure both the
application and <em>test setup</em> for an application in exactly the same
way.  Likewise, lots and lots of code got centralized into the
<code>configuration</code> module (a lot removed from code that drove various
ZCML directives), and we were able to document <a href="http://docs.repoze.org/bfg/1.2/api/configuration.html#repoze.bfg.configuration.Configurator">the resulting
API</a>
much more effectively and cleanly.</p>
<p>The end result?  Well, now, truly, if you don't want to use ZCML, you
needn't.  Ever.  But even so we didn't wind up with a system that
leads you towards making a false choice between "convention over
configuration" and ZCML: both the declarative and the imperative
configuration modes are still extremely explicit (they are really
mirror copies of each other, as the declarative code <em>uses</em> the
imperative API).  The API used by imperative configurators is not "bare" ZCA registrations: it's just more domain specific,
like helper ZCML directives in Zope.  And hopefully we've brought down to earth the kinds
of configuration tasks you can potentially perform, because they're
now all enumerated in the <a href="http://docs.repoze.org/bfg/1.2/api/configuration.html#repoze.bfg.configuration.Configurator">Configurator API documentation</a>
and via various narrative documentation chapters.  All of the older declarative/ZCML
configuration still works as it did in 1.0/1.1, so there's no
backwards compatibility concerns either.  ZCML will always be a
reasonable way to configure a BFG app.</p>
<p>I think 1.2 is the best of the bunch as far as BFG releases go,
because, although BFG still has an obvious Zope heritage, 1.2
unglosses over some of the things that Zope has been glossing over for
a long time, such as the relationship from the code in a ZCML
directive to code that needs to be invoked imperatively.  BFG also
eschews some dogma-driven assumptions Zope has been making for a long
time.  When I say this I am reminded of this passage from the ZCML
chapter of Stephan Richter's <a href="http://wiki.zope.org/zope3/zcml.html">Zope 3 Developer's
Handbook</a> :
</p><pre>  While the developer is certainly the one that writes the initial cut of the 
  configuration, this user is not the real target audience. Once the product
  is written, you would expect a system administrator to interact much more 
  frequently with the configuration, adding and removing functionality or 
  adjust the configuration of the server setup. System administrators are 
  often not developers, so that it would be unfortunate to write the 
  configuration in the programming language, here Python. But an administrator 
  is familiar with configuration scripts, shell code and XML to some extend. 
  Therefore an easy to read syntax that is similar to other configuration 
  files is of advantage.
</pre>
<p/>
<p>I think it's safe to say that this assumption has turned out to be
just false.  Sysadmins never change ZCML files.  I have never, ever,
not once in the last seven years, had a sysadmin with enough context
that allowed him to change a ZCML file in any meaningful way.  Only
developers change ZCML files.  So let's just un-dogma-ify this
assumption, and put programmers back in charge to whatever extent
they'd like to be.  Demystification of this stuff is the only reasonable way
forward, even if it means admitting we made really big design mistakes in the past.</p></div>
    </content>
    <updated>2010-01-01T16:35:07Z</updated>
    <category term="python"/>
    <category term="tech"/>
    <category term="zope"/>
    <author>
      <name>chrism</name>
    </author>
    <source>
      <id>http://plope.com</id>
      <link href="http://plope.com/python.rss" rel="self" type="application/atom+xml"/>
      <link href="http://plope.com" rel="alternate" type="text/html"/>
      <subtitle>Chris McDonough's Python Feed</subtitle>
      <title>Chris McDonough's Python Feed</title>
      <updated>2010-02-12T15:01:01Z</updated>
    </source>
  </entry>

  <entry>
    <id>http://plope.com/Members/chrism/bfg_view_dispatch</id>
    <link href="http://plope.com/Members/chrism/bfg_view_dispatch" rel="alternate" type="text/html"/>
    <title>View Dispatch Is Not An Adapter Lookup</title>
    <summary>The traditional Zope worldview that says that view dispatch is an adapter lookup is not optimal.</summary>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>In a <a href="http://www.plope.com/Members/chrism/repozecast5">podcast</a> we
recorded yesterday, I held forth about the new features of the last
two <a href="http://bfg.repoze.org">repoze.bfg</a> releases.  One of these, new in 1.1, was the idea of
"view predicates".</p>
<p>Now, the idea of a view predicate was not mine, it was Malthe Borch's.
At the time, I was still wrapped up in the Zope-inspired worldview
that a view invocation is (by god) an <em>invocation of a ZCA
multiadapter</em>, QED, full-stop.  Malthe figured out that it is useful
to look outside the idea of adaptation to resolve a request to a view,
and as a result I implemented view lookup in terms of view predicates
in 1.1; 1.0 lacked this feature.  The epiphany is somewhat obvious in
hindsight, but at the time, it was not.  I was well and truly wrapped
around the adaptation axle.</p>
<p>For those who don't know, an "adapter" is a bit of code that converts
a set of input objects <code>[I]</code> to an output object <code>O</code>.  The simplest
physical example of an adapter is the one we know and love: a power
plug adapter.  Maybe one that converts a US-style two-pronged power
plug to a "proper" mains plug like they use in the UK.  Other stilted
and trivial adapter analogies exist, I'll skip them here.  Google for
"Zope adapter".</p>
<p>In Zope (and BFG, and Django) terms, a "view" is a bit of code invoked
as the result of a particular request.  It's called a "controller
action" in other framework religions.</p>
<p>In terms of view dispatch, Zope uses a combination of graph traversal
and an adapter lookup to find a view.  Rather than using some ordered
set of URL match tests like many other web frameworks, Zope encodes
all knowledge about which view should be invoked in all particular
circumstances within a given application as a set of adapter
registrations.  When a request enters the system, traversal is
responsible for finding a "context" object and a "view name".  Using
this context object, this view name, and the request object it does a
"multiadapter" lookup something like this: please find me a view
adapter for this kind of context and this kind of request with this
name.  Ex.: <code>((context, request), view name)</code> -&gt; view object.</p>
<p>While I'm a big fan of this style of dispatch, real-world requirements
stretch its applicability.  It was always pretty odd to need to attach
an interface object to a request in order to convince the view
machinery to do something different in some circumstance; it got truly
weird when Zope started to support persistent registries that allowed
you to make different view registrations in different contexts.
Entire subframeworks of various Zope subsystems and offshoots exist
just to manage the results for adapter and utility lookups related to
requests and contexts.  I fear it may all be for naught.</p>
<p>What Malthe figured out is that view dispatch is not <em>just</em> an adapter
lookup.  While adapter lookup can help speed things up, there's just
not enough value in the adapter lookup machinery to spell all the
query axes in terms of interfaces, as required by zope.component.  For
example, it makes a hell of a lot more sense to register a view
callable that will be invoked in a circumstance like so:
</p><pre>  request.method == 'POST'
  'application/json' in request.accept
</pre>
<p/>
<p>Than it ever would to register something in terms of interfaces, like
Zope makes you do, ala:
</p><pre>  providedBy(request) -&gt; IPostRequest, IAcceptApplicationJSON
</pre>
<p/>
<p>I mean, literally, it's just not really possible to anticipate all the
interfaces you might need to attach to a request in order to provide a
vocabulary that allowed you to compose interfaces in enough
combinations for such a system based on interface lookup to work.
Even if you could, who would understand it after you created it?</p>
<p>With view predicates in BFG 1.1+, it becomes quite easy to register
view callables for very specific circumstances that would be extremely
difficult (or maybe impossible) to spell if you treated view lookup as
only an adaptation problem.  For example, using the <code>containment</code> view
predicate in BFG, you can do this:
</p><pre>  &lt;view
    for=".models.Entry"
    name="edit.html"
    containment=".models.Blog"
    /&gt;
</pre>
<p/>
<p>The <code>containment=".models.Blog"</code> attribute is the important bit.  It
says "only invoke this view when the context object <em>or any of its
parents</em> is a Blog object".  This solves a whole raft of problems for
UI, where you want to use the same kind of object in two places (an
"Entry" object) but you want its edit view to be slightly different in
two different "sections" of a site: maybe one view when we're in the
Blog section, and another when we're in a Calendar section.  This sort
of registration is not possible in bare Zope, and adaptation alone,
at least in the context of using a single adapter registry, cannot do it.</p>
<p>I don't think we can continue to treat view dispatch in the Zope world
as a bare adapter lookup; it's just too limiting.  In BFG 1.1+ we do
not.  Using a pattern much like Zope's we use a multiadapter lookup to
find a "view" object.  However, the view object that is found is often
a "multiview".  A multiview is a collection of views with associated
predicates.  Once a multiview is found and called, it evaluates the
predicates associated with each of its constituent view callables (in
a reasonably easy to understand order) to find the most specific view
callable; then it invokes that to obtain a response. </p>
<p>Essentially we use the adapter lookup machinery <em>only as a speed
enhancement</em> in this circumstance.  The adapter lookup gets us
"in a ballpark" where we can perform fewer predicate evaluations
to find "the best" view callable.  It would be possible to implement
it without doing any adaptation at all, it would just be a lot slower.</p>
<p>Other predicate attributes exist for use in this way: route_name, request_method,
request_param, xhr, accept, header, path_info.  In the very latest release (1.2a9),
there is even a "custom predicate" predicate, which allows you to provide a
callable that returns true or false for an arbitrary circumstance so you
can create your own predicate logic.  These can be combined arbitrarily
to specify an extremely granular set of circumstances without any interface
foolery.</p>
<p>Personally, I think view predicates are a pure win, and I think their existence
demonstrates why bare adaptation is not ideal for view lookup.  I might
even take that a little further: it would also be useful to be able to look up
other things (such as utilities, and other code) using the same set of
predicates.  If this becomes true, I think the adaptation worldview as 
"from interface X to interface Y" as a fundamental assumption begins to look
pretty anemic.</p></div>
    </content>
    <updated>2009-12-31T15:09:10Z</updated>
    <category term="python"/>
    <category term="tech"/>
    <category term="zope"/>
    <author>
      <name>chrism</name>
    </author>
    <source>
      <id>http://plope.com</id>
      <link href="http://plope.com/python.rss" rel="self" type="application/atom+xml"/>
      <link href="http://plope.com" rel="alternate" type="text/html"/>
      <subtitle>Chris McDonough's Python Feed</subtitle>
      <title>Chris McDonough's Python Feed</title>
      <updated>2010-02-12T15:01:01Z</updated>
    </source>
  </entry>

  <entry>
    <id>http://plope.com/Members/chrism/repozecast5</id>
    <link href="http://plope.com/Members/chrism/repozecast5" rel="alternate" type="text/html"/>
    <title>Repozecast #5 Released</title>
    <summary>The repozecast podcast, episode #5.</summary>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>Get it at <a href="http://static.repoze.org/casts/repozecast-5-20091230.mp3">http://static.repoze.org/casts/repozecast-5-20091230.mp3</a></p>
<p>Tres and I talk about BFG, the ZTK, and repoze.who.</p>
<p>Happy holidays!</p></div>
    </content>
    <updated>2009-12-30T23:56:13Z</updated>
    <category term="podcast"/>
    <category term="python"/>
    <category term="tech"/>
    <category term="zope"/>
    <author>
      <name>chrism</name>
    </author>
    <source>
      <id>http://plope.com</id>
      <link href="http://plope.com/python.rss" rel="self" type="application/atom+xml"/>
      <link href="http://plope.com" rel="alternate" type="text/html"/>
      <subtitle>Chris McDonough's Python Feed</subtitle>
      <title>Chris McDonough's Python Feed</title>
      <updated>2010-02-12T15:01:01Z</updated>
    </source>
  </entry>

  <entry xml:lang="en">
    <id>http://blog.repoze.org/Repozecast%205/</id>
    <link href="http://blog.repoze.org/Repozecast%205/" rel="alternate" type="text/html"/>
    <title xml:lang="en">Repozecast 5</title>
    <content type="xhtml" xml:lang="en"><div xmlns="http://www.w3.org/1999/xhtml"><p>Repozecast #5 released</p>
<p><a class="reference external" href="http://static.repoze.org/casts/repozecast-5-20091230.mp3">http://static.repoze.org/casts/repozecast-5-20091230.mp3</a></p>
<p>Repozecast is an every-so-often podcast.  This is the latest one, wherein Tres and I talk about BFG, the ZTK, and repoze.who.</p>
<p>Happy holidays!</p>
<ul class="simple">
<li>Chris</li>
</ul></div>
    </content>
    <updated>2009-12-30T05:00:00Z</updated>
    <author>
      <name>Agendaless</name>
    </author>
    <source>
      <id>http://blog.repoze.org/index.atom</id>
      <link href="http://blog.repoze.org" rel="alternate" type="text/html"/>
      <link href="http://blog.repoze.org/index.atom" rel="self" type="application/atom+xml"/>
      <title xml:lang="en">Repoze Blog RSS Feed</title>
      <updated>2010-03-06T05:00:00Z</updated>
    </source>
  </entry>

  <entry>
    <id>http://plope.com/Members/chrism/2009_meme</id>
    <link href="http://plope.com/Members/chrism/2009_meme" rel="alternate" type="text/html"/>
    <title>2009 Meme</title>
    <summary>Response to the 2009 meme that Tarek started.</summary>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>In response to <a href="http://tarekziade.wordpress.com/2009/12/28/new-years-python-meme/">Tarek's meme</a></p>

<ol>
<li> What’s the coolest Python application, framework or library you
   have discovered in 2009 ?<p>   <a href="http://sphinx.pocoo.org">Sphinx</a>.  Sphinx is really super.  It
   makes writing and publishing technical documentation less painful
   by an order of magnitude than it used to be.  I'm actually not sure
   this wasn't a 2008 discovery, but I really started using it "in
   anger" on my own projects in 2009.</p>
</li>
<li> What new programming technique did you learn in 2009 ?<p>   Testing using statement coverage (via Ned Batchelder's
   <a href="http://nedbatchelder.com/code/coverage/">coverage</a>).  Maintaining
   100% statement coverage gives me a lot more confidence about
   refactoring old code.</p>
</li>
<li> What’s the name of the open source project you contributed the most
   in 2009 ? What did you do ?<p>   <a href="http://repoze.org">Repoze</a> (including <a href="http://bfg.repoze.org">BFG</a>).
   I wrote the lion's share of BFG and contributed to various other
   Repoze-related pieces of software.  I also did a good bit of work
   on <a href="http://karlproject.org/">Karl</a> (a collaboration system based on
   BFG and other Repoze software).  I also did some work on
   Formish/Schemaish, Pylons/Routes, WebOb, and Sphinx.</p>
</li>
<li> What was the Python blog or website you read the most in 2009 ?<p>   Reddit's Python section, and the blog entries tossed at me by
   Planet Python.</p>
</li>
<li> What are the three top things you want to learn in 2010 ?<p>   No idea.  I just take it as it comes.
</p>
</li>

</ol></div>
    </content>
    <updated>2009-12-28T17:54:38Z</updated>
    <category term="python"/>
    <category term="tech"/>
    <category term="zope"/>
    <author>
      <name>chrism</name>
    </author>
    <source>
      <id>http://plope.com</id>
      <link href="http://plope.com/python.rss" rel="self" type="application/atom+xml"/>
      <link href="http://plope.com" rel="alternate" type="text/html"/>
      <subtitle>Chris McDonough's Python Feed</subtitle>
      <title>Chris McDonough's Python Feed</title>
      <updated>2010-02-12T15:01:01Z</updated>
    </source>
  </entry>

  <entry>
    <id>http://plope.com/Members/chrism/documentation_is_the_differentiator</id>
    <link href="http://plope.com/Members/chrism/documentation_is_the_differentiator" rel="alternate" type="text/html"/>
    <title>Documentation is the Differentiator</title>
    <summary>Documentation quality is becoming the differentiator between project success and failure.</summary>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>I think the most important thing we can do in the open source world
(far more important than releasing new cool software) is to improve
the quality of the documentation of existing software.  Software
without documentation is pretty much useless.  Software with bad
documentation is slightly better than useless, but still nearing
uselessness.  Software with some good documentation but which has
incomplete documentation is better than useless, but only for some
period of time: you can't keep telling yourself "I'll do it later" or
outsource the job of documentation to some mythical "community": it's
a chicken and egg scenario.  Writing documentation is part of your job
description as a programmer.</p>
<p>As the general quality of software improves due to widespread use of
good software engineering techniques such as unit and integration
testing, documentation quality is becoming <strong>the</strong> differentiator
between project success and failure.</p>
<p>The most valuable descriptions of highly technical things:</p>

<ul>
<li>get to the point quickly without endless theory or architectural
  navel-gazing.</li>
<li>start with an example.</li>
<li>are written in an informal style.</li>
<li>aren't optimized for brevity, nor are they optimized for
  testability; instead they are optimized for readability and
  imparting knowledge.</li>
<li>can be read more than once; the first time you read one, you may
  gain different knowledge from it than the fifth time, but you
  still gain knowledge.</li>
<li>aren't thrown over the wall as an afterthought, never to be
  consulted or changed again, they evolve over time as the software
  evolves.</li>
<li>are complete</li>
<li>are written using proper spelling and grammar</li>

</ul>
<p>Here are some examples:</p>

<ul>
<li><a href="http://www.xmlrpc.com/spec">The XML-RPC Specification</a></li>
<li><a href="http://www.amk.ca/python/howto/regex/">AMK's Regex Howto</a></li>
<li><a href="http://sphinx.pocoo.org/contents.html">Sphinx Documentation</a></li>
<li><a href="http://djangobook.com/en/1.0/">The Django Book</a></li>
<li><a href="http://oreilly.com/catalog/9780596003302">Unix Power Tools</a></li>

</ul>
<p>If you can create documentation of this quality or better, your project has no
chance but to succeed on some level, even if your code is terrible.</p>
<p>Note also that I think that a choice between good docs and better software
is a false choice.  The act of continually writing documentation <em>always</em> makes software
better, because if it's hard to explain, it's probably not very good.  Complexity
becomes clear very quickly when you need to explain it away; it's usually
easier to change the software to be less complex than it is to document
something complex.  It's frighteningly easy to write undocumentable software.</p></div>
    </content>
    <updated>2009-12-26T00:27:46Z</updated>
    <category term="python"/>
    <category term="supervisor"/>
    <category term="tech"/>
    <category term="zope"/>
    <author>
      <name>chrism</name>
    </author>
    <source>
      <id>http://plope.com</id>
      <link href="http://plope.com/python.rss" rel="self" type="application/atom+xml"/>
      <link href="http://plope.com" rel="alternate" type="text/html"/>
      <subtitle>Chris McDonough's Python Feed</subtitle>
      <title>Chris McDonough's Python Feed</title>
      <updated>2010-02-12T15:01:01Z</updated>
    </source>
  </entry>

  <entry>
    <id>http://plope.com/Members/chrism/service_process_fascination</id>
    <link href="http://plope.com/Members/chrism/service_process_fascination" rel="alternate" type="text/html"/>
    <title>Service Process Fascination</title>
    <summary>Why "service process" fascination is often a symptom of poor design.</summary>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>I have an admission to make.  I not a fan of systems that are composed
of an integration of heterogenous cooperating service processes.</p>
<p>When I say "service", I mean that the task provides some stovepiped
service to a caller (perhaps a "web service" or a database network
API).  When I say "heterogenous", I mean that the process performs
some task that it's "good at", implicitly leaving other processes to
perform other different tasks that they are "good at."</p>
<p>When I say that these service processes are "cooperating", what I
really mean is that some <em>other</em> process integrates the communications
between all these service processes together to form some
end-user-facing system.  A corollary is that the end-user-facing
system probably won't work (at least in any way that is explicable to
the end user himself) if any of the service processes dies or gets
wedged, even if the remainder of the service processes survive.</p>
<p>Such a setup makes sense sometimes.  It makes sense particularly when
each service process is a stable, well-tested, widely-used,
well-supported, well-defined, well-documented subsystem written in a
style or language widely divergent from any other service process.
For example, using a Postgres database as a "service process" in a
system otherwise composed of Python is not often very controversial.</p>
<p>But even when you use a non-controversial "service processes", the
<em>number</em> of service processes in any integration matters.  A lot.
Each service process a system takes on implies the following:</p>

<ul>
<li>Maintenance (e.g. Postgres "vacuum").</li>
<li>Crash monitoring / email notification.</li>
<li>Performance monitoring and amelioration.</li>
<li>Cognitive load related to setup and API.</li>
<li>Code integration.</li>
<li>Build automation.</li>

</ul>
<p>It may be fun to think about tying Postgres, CouchDB, Solr, and some
web service together via a frontend that integrates them all.  Some
folks may consider this highly practical because the result is termed
an integration of "best of breed" components.  The perceived benefit
of such an integration is that the whole becomes better than the
parts.  The assumption is that a system that uses more off-the-shelf
service components and less custom code will be easier to manage,
or it will be faster, or it will be prettier, etc.</p>
<p>My experience says that such an assumption is usually just wrong, and
that it's usually a mistake in any small or moderately-sized system to
rely on more than a single service process when other potentially
useful service processes overlap functionality of the single existing
service process.  When a system doesn't actually strictly <em>need</em> the
functionality of extra processes running, I think a high number of
service processes is symptom of either <em>optimism about other system
capabilities</em> or <em>complexity fascination</em>.</p>
<p>Sometimes the amount of work to add a new service process is actually
a net win, if when you introduce a new service process you remove more
complexity from the system than you add.  But often, for various
reasons, you can't.  Although you've added some amount of complexity
by adding a new service process, but for various practical reasons,
you find yourself unable to retire the code or process that the new
service process was meant to replace, so you don't remove any
complexity from the system.  Instead, you just add some.</p>
<p>Let's take a concrete example.  Let's say you've developed a system
that uses Postgres as a persistence mechanism.  Now let's say you have
a new requirement: you need to add full-text indexing to the system.
Postgres has fairly good full-text indexing capabilities.  But you see
that Solr has some shiny feature that promises to make your life much
better if you'd just be willing to take the time to learn and
integrate it.</p>
<p>I say <strong>don't fall for it</strong>.  Just use the Postgres full-text indexer,
and fill in any missing functionality with custom code.  Your system
will only <em>gain</em> complexity by adding Solr, it's almost guaranteed.
This is because you're <em>still</em> going to need to manage Postgres; you can't replace
it with Solr.  Even though Solr's feature set might be better, and its promises may be shinier,
the full-text indexing service which Postgres offers is probably <em>good
enough</em> unless you're truly reaching to invent requirements.</p>
<p>The addition of a new service process should be a monumental event if
you want your system to be as complexity-free and stable as possible.
Even if it means the system is slightly slower, or some edge
requirement becomes impossible to satisfy, a system that works all the
time, every time, and which people can understand is usually more
valuable than any individual outlying feature.  A system with many
moving parts is just naturally harder to understand and manage than
one with fewer.</p>
<p>It's bad enough to pile on existing "best-of-breed" services to some
integration.  But there is also a degenerate case of adding service
processes: writing service process code which is only useful in the
context of a single integration.  For example, some folks believe that
composing an application out of many highly focused process-bounded
services for <em>every project</em> is a good idea.  It's not as if they're
<em>reusing</em> some existing service process, they're <em>inventing</em> each
service process for purpose of a single integration.  Personally, I
think this is just not sane.  It may be easier to determine
responsibilities by separating services between processes, but I think
mostly this is best used as a mind game.  Once you've figured out the
responsibilities of each subsystem, if the potential that you're going
to document some particular subsystem well enough for other people to
use well is vanishingly small, just put all the subsystems into a
single process.  If it's not documented for use outside of a
particular integration, it doesn't rate being its own service process.</p></div>
    </content>
    <updated>2009-12-23T15:42:58Z</updated>
    <category term="python"/>
    <category term="tech"/>
    <category term="zope"/>
    <author>
      <name>chrism</name>
    </author>
    <source>
      <id>http://plope.com</id>
      <link href="http://plope.com/python.rss" rel="self" type="application/atom+xml"/>
      <link href="http://plope.com" rel="alternate" type="text/html"/>
      <subtitle>Chris McDonough's Python Feed</subtitle>
      <title>Chris McDonough's Python Feed</title>
      <updated>2010-02-12T15:01:01Z</updated>
    </source>
  </entry>

  <entry>
    <id>http://plope.com/Members/chrism/bfg_shouldnthave</id>
    <link href="http://plope.com/Members/chrism/bfg_shouldnthave" rel="alternate" type="text/html"/>
    <title>Absolutely Sure He Shouldn't Have It</title>
    <summary>Indeed, select people probably shouldn't have it (via Chris Rossi).</summary>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><a href="http://verydemotivational.com/2009/12/20/i-want-that/"><img alt="I Want That!" id="_r_a_2888856832" src="http://verydemotivational.com/wp-content/uploads/2009/12/129037495211628031.jpg" title="I Want That!"/></a><br/>see more <a href="http://verydemotivational.com">deMotivational Posters</a></div>
    </content>
    <updated>2009-12-21T12:01:32Z</updated>
    <category term="python"/>
    <category term="supervisor"/>
    <category term="tech"/>
    <category term="zope"/>
    <author>
      <name>chrism</name>
    </author>
    <source>
      <id>http://plope.com</id>
      <link href="http://plope.com/python.rss" rel="self" type="application/atom+xml"/>
      <link href="http://plope.com" rel="alternate" type="text/html"/>
      <subtitle>Chris McDonough's Python Feed</subtitle>
      <title>Chris McDonough's Python Feed</title>
      <updated>2010-02-12T15:01:01Z</updated>
    </source>
  </entry>

  <entry xml:lang="en">
    <id>http://blog.repoze.org/repoze.bfg%201.2a7%20Released/</id>
    <link href="http://blog.repoze.org/repoze.bfg%201.2a7%20Released/" rel="alternate" type="text/html"/>
    <title xml:lang="en">repoze.bfg 1.2a7 Released</title>
    <content type="xhtml" xml:lang="en"><div xmlns="http://www.w3.org/1999/xhtml"><p>Install via:</p>
<pre class="literal-block">$ easy_install -U http://dist.repoze.org/bfg/1.2/simple repoze.bfg
</pre>
<p>The docs at <a class="reference external" href="http://docs.repoze.org/bfg/1.2">http://docs.repoze.org/bfg/1.2</a> have been updated.</p>
<p>The changelog follows:</p>
<div class="section" id="a7-2009-12-20">
<h1>1.2a7 (2009-12-20)</h1>
<div class="section" id="features">
<h2>Features</h2>
<ul class="simple">
<li>Add four new testing-related APIs to the
<tt class="docutils literal"><span class="pre">repoze.bfg.configuration.Configurator</span></tt> class:
<tt class="docutils literal"><span class="pre">testing_securitypolicy</span></tt>, <tt class="docutils literal"><span class="pre">testing_models</span></tt>,
<tt class="docutils literal"><span class="pre">testing_add_subscriber</span></tt>, and <tt class="docutils literal"><span class="pre">testing_add_template</span></tt>.  These
were added in order to provide more direct access to the
functionality of the <tt class="docutils literal"><span class="pre">repoze.bfg.testing</span></tt> APIs named
<tt class="docutils literal"><span class="pre">registerDummySecurityPolicy</span></tt>, <tt class="docutils literal"><span class="pre">registerModels</span></tt>,
<tt class="docutils literal"><span class="pre">registerEventListener</span></tt>, and <tt class="docutils literal"><span class="pre">registerTemplateRenderer</span></tt> when a
configurator is used.  The <tt class="docutils literal"><span class="pre">testing</span></tt> APIs named are nominally
deprecated (although they will likely remain around "forever", as
they are in heavy use in the wild).</li>
<li>Add a new API to the <tt class="docutils literal"><span class="pre">repoze.bfg.configuration.Configurator</span></tt>
class: <tt class="docutils literal"><span class="pre">add_settings</span></tt>.  This API can be used to add "settings"
(information returned within via the
<tt class="docutils literal"><span class="pre">repoze.bfg.settings.get_settings</span></tt> API) after the configurator has
been initially set up.  This is most useful for testing purposes.</li>
<li>Add a <tt class="docutils literal"><span class="pre">custom_predicates</span></tt> argument to the <tt class="docutils literal"><span class="pre">Configurator</span></tt>
<tt class="docutils literal"><span class="pre">add_view</span></tt> method, the <tt class="docutils literal"><span class="pre">bfg_view</span></tt> decorator and the attribute
list of the ZCML <tt class="docutils literal"><span class="pre">view</span></tt> directive.  If <tt class="docutils literal"><span class="pre">custom_predicates</span></tt> is
specified, it must be a sequence of predicate callables (a predicate
callable accepts two arguments: <tt class="docutils literal"><span class="pre">context</span></tt> and <tt class="docutils literal"><span class="pre">request</span></tt> and
returns <tt class="docutils literal"><span class="pre">True</span></tt> or <tt class="docutils literal"><span class="pre">False</span></tt>).  The associated view callable will
only be invoked if all custom predicates return <tt class="docutils literal"><span class="pre">True</span></tt>.  Use one
or more custom predicates when no existing predefined predicate is
useful.  Predefined and custom predicates can be mixed freely.</li>
<li>Add a <tt class="docutils literal"><span class="pre">custom_predicates</span></tt> argument to the <tt class="docutils literal"><span class="pre">Configurator</span></tt>
<tt class="docutils literal"><span class="pre">add_route</span></tt> and the attribute list of the ZCML <tt class="docutils literal"><span class="pre">route</span></tt>
directive.  If <tt class="docutils literal"><span class="pre">custom_predicates</span></tt> is specified, it must be a
sequence of predicate callables (a predicate callable accepts two
arguments: <tt class="docutils literal"><span class="pre">context</span></tt> and <tt class="docutils literal"><span class="pre">request</span></tt> and returns <tt class="docutils literal"><span class="pre">True</span></tt> or
<tt class="docutils literal"><span class="pre">False</span></tt>).  The associated route will match will only be invoked if
all custom predicates return <tt class="docutils literal"><span class="pre">True</span></tt>, else route matching
continues.  Note that the value <tt class="docutils literal"><span class="pre">context</span></tt> will always be <tt class="docutils literal"><span class="pre">None</span></tt>
when passed to a custom route predicate.  Use one or more custom
predicates when no existing predefined predicate is useful.
Predefined and custom predicates can be mixed freely.</li>
</ul>
</div>
<div class="section" id="internal">
<h2>Internal</h2>
<ul class="simple">
<li>Remove the <tt class="docutils literal"><span class="pre">repoze.bfg.testing.registerTraverser</span></tt> function.  This
function was never an API.</li>
</ul>
</div>
<div class="section" id="documenation">
<h2>Documenation</h2>
<ul class="simple">
<li>Doc-deprecated most helper functions in the <tt class="docutils literal"><span class="pre">repoze.bfg.testing</span></tt>
module.  These helper functions likely won't be removed any time
soon, nor will they generate a warning any time soon, due to their
heavy use in the wild, but equivalent behavior exists in methods of
a Configurator.</li>
</ul>
</div>
</div></div>
    </content>
    <updated>2009-12-20T05:00:00Z</updated>
    <author>
      <name>Agendaless</name>
    </author>
    <source>
      <id>http://blog.repoze.org/index.atom</id>
      <link href="http://blog.repoze.org" rel="alternate" type="text/html"/>
      <link href="http://blog.repoze.org/index.atom" rel="self" type="application/atom+xml"/>
      <title xml:lang="en">Repoze Blog RSS Feed</title>
      <updated>2010-03-06T05:00:00Z</updated>
    </source>
  </entry>

  <entry>
    <id>http://plope.com/Members/chrism/depinj</id>
    <link href="http://plope.com/Members/chrism/depinj" rel="alternate" type="text/html"/>
    <title>Unit Test Dependency Injections</title>
    <summary>I'm sure I'm reinventing the wheel on some axis, but as the result of some thought, I've created a small unit testing dependency injection framework.</summary>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>A couple of days ago I posted a <a href="http://www.plope.com/Members/chrism/zca_thoughts_summary">long blog entry</a> about 
how we (or at least I) tend to use the Zope Component Archictecture.  I personally often use the ZCA to introduce
<a href="http://en.wikipedia.org/wiki/Dependency_injection">dependency injection</a> specifically for unit tests.</p>
<p>The types of dependency injection the ZCA allows for can be used far more generally than just for making unit testing
easier.  The ZCA works pretty well generally for unit testing dependency injection patterns.  But in some cases ZCA
assumptions may make the resulting tested code less understandable.  In particular, if you put this code under
test:
</p><pre>  from zope.component import queryUtility
  from zope.interface import implements
  from mypackage.interfaces import ICatalogQuery

  class CatalogQuery(object):
      implements(ICatalogQuery)
      def __call__(self, context, **kw):
          """ Does something complicated """

  query = CatalogQuery()

  def unit_under_test(context):
      query = queryUtility(ICatalogQuery, default=query)
      return query(context, a=1)
</pre>
<p/>
<p>And then in the code doing the testing,
you do this:
</p><pre>  import unittest
  from zope.component import getSiteManager

  class Test(unittest.TestCase):

      def setUp(self):
          sm = getSiteManager()
          sm.__init__()

      def test_it(self):
          from mypackage import unit_under_test
          from zope.component import getUtility
          from mypackage.interfaces import ICatalogQuery

          class DummyQuery(object):
              def __call__(self, *arg, **kw):
                  return [1]

          class DummyContext(object):
              pass

          query = DummyQuery()
          context = DummyContext()

          sm = getSiteManager()
          sm.registerUtility(query, ICatalogQuery)
          self.assertEqual(unit_under_test(context), [1])
</pre>
<p/>
<p>You note above that the code under test uses a utility lookup to obtain the catalog query API.  This is done <em>purely</em>
for testing purposes; not for pluggability purposes.  However, a casual reader of the above code may assume that the "ICatalogQuery"
API is a ZCA "plug point", as advertised by its retrieval as a ZCA "utility".   While it may be useful to have an API definition for 
ICatalogQuery, in most systems such an API is explicitly <strong>not</strong> pluggable.  There's no expectation in most systems with a
low-level API like this that an arbitrary user should be expected to be able to plug in a different implementation of ICatalogQuery
at all.  The getUtility code in the unit under test should not need to exist; it's a misdirection indicating that this
is some sort of plug point that is meant to take alternate implementations.</p>
<p>For testing situations such as this one, I've created a package named <a href="http://docs.repoze.org/depinj">repoze.depinj</a>
(see also <a href="http://svn.repoze.org/repoze.depinj/trunk/">http://svn.repoze.org/repoze.depinj/trunk/</a>).</p>
<p>This package is meant to be used instead of the ZCA for unit testing purposes when there is exactly one implementation
of the dependency being stubbed out, and the code just needs to be able to find an alternate testing implementation
when the system is under test.</p>
<p>Using repoze.depinj, the above code under test
becomes:
</p><pre>  from repoze.depinj import lookup

  class CatalogQuery(object):
      def __call__(self, context, **kw):
          """ Does something complicated """

  query = CatalogQuery()

  def unit_under_test(context):
      query = lookup(query)
      return query(context, a=1)
</pre>
<p/>
<p>And the code doing the testing
becomes:
</p><pre>  import unittest
  from repoze import depinj

  class Test(unittest.TestCase):

      def setUp(self):
          depinj.clear()

      def test_it(self):
          from mypackage import unit_under_test
          from mypackage import query

          class DummyQuery(object):
              def __call__(self, *arg, **kw):
                  return [1]

          class DummyContext(object):
              pass

          dummy_query = DummyQuery()
          context = DummyContext()
          depinj.inject(dummy_query, query)
          self.assertEqual(unit_under_test(context), [1])
</pre>
<p/>
<p>While the code is really no more readable in isolation, we have avoided needing to define an ICatalogQuery Zope
interface for this interaction.  We don't actually use a Zope interface at all.</p>
<p>Note that while we don't <em>need</em> Zope interfaces to document this behavior, we can <em>still</em> document the
CatalogQuery API with a Zope interface if we want to.  But because we wouldn't use that interface as an adapter marker,
it would be impossible for someone to misunderstand as a ZCA plugpoint.</p>
<p>By the way, the answer to "why not monkeypatch instead?" is <a href="http://plope.com/Members/chrism/import_time_side_effects">because I don't own the module-scope codepath</a> .  The answer to "why not supply an optional <code>unit_under_test</code> keyword argument supplying the query implementation?" is because it makes generating documentation from source harder.  It's also kinda fugly and doesn't account for callables that want to accept truly arbitrary <code>**kw</code> args.</p></div>
    </content>
    <updated>2009-12-04T16:06:18Z</updated>
    <category term="python"/>
    <category term="tech"/>
    <category term="zope"/>
    <author>
      <name>chrism</name>
    </author>
    <source>
      <id>http://plope.com</id>
      <link href="http://plope.com/python.rss" rel="self" type="application/atom+xml"/>
      <link href="http://plope.com" rel="alternate" type="text/html"/>
      <subtitle>Chris McDonough's Python Feed</subtitle>
      <title>Chris McDonough's Python Feed</title>
      <updated>2010-02-12T15:01:01Z</updated>
    </source>
  </entry>

  <entry>
    <id>http://plope.com/Members/chrism/zca_thoughts_summary</id>
    <link href="http://plope.com/Members/chrism/zca_thoughts_summary" rel="alternate" type="text/html"/>
    <title>My ZCA Thoughts Summary</title>
    <summary>Lately there's been some conversation on zope-dev about the future of the "zope.component" package, which is the package that provides "the Zope Component Architecture", more or less.  I make some proposals here and take some positions.</summary>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>The Zope community currently asserts that there is a benefit to using
the current set of conventions and APIs that forms the Zope Component
Architecture as a mechanism: use of its mechanisms and concepts can
produce a system of <a href="http://wiki.zope.org/zope3/components.html">higher quality</a> and one which is <a href="http://wiki.zope.org/zope3/ComponentArchitectureOverview">more
understandable</a>
than a system built without these mechanisms and
concepts.</p>
<p>The promised benefits of obeying the conventions and constraints of
the ZCA are:</p>

<ul>
<li>A system based on use of the component architecture machinery is
  "pluggable", meaning that implementations can be swapped out for one
  another as necessary without changing consumer code.</li>
<li>If you've paid enough attention to detail over time that the
  contract spelled by an interface still matches the concrete
  implementations of the interface, the interface forms a natural set
  of obviously-correct documentation for that component.  For a large
  system where there is an existing body of interface documentation,
  it is on average easier for someone new to the system to quickly get
  productive.</li>
<li>The concept of adaptation, where one object can be converted to
  another "type" through introspection of its interfaces, allows the
  average developer to understand the interaction between discrete
  components in a large system more easily than in a comparable system
  which doesn't use adaptation.</li>

</ul>
<p>I hope to explain via this blog entry that the first promise is
completely true, the second is at least half-true, and the third one
is just plain false.</p>
<p>The constraints and conventions required by the ZCA are these:</p>

<ul>
<li>"Interfaces" are type markers that have metadata.</li>
<li>An object may declare that it "implements" one or more interfaces.</li>
<li>An interface may optionally specify a contract: objects which
  implement the interface are presumed to offer this contract.</li>
<li>"Adaptation" is the act of converting an object that implements one
  interface to an object that implements another interface.</li>

</ul>
<p>Let's compare the promises of following these constraints and
conventions to their actual benefits.</p>
<h1>Components as Plugpoints</h1>
<p>  Use of a ZCA "component" as a plugpoint works extremely well.  These
  uses include: testing dependency injection, view overrides, and other extremely high-level
  policy plugpoints.  The ZCA really shines here, as long as you use it in small doses and
  take care to document the resulting system narratively in terms that don't
  necessarily require an understanding of component architecture concepts.</p>
<p>  I am obviously biased, but I believe <a href="http://bfg.repoze.org">repoze.bfg</a> is such a system.
  However, it actually does not use any documented API defined within in the zope.component 
  package itself.  It just uses a ZCA registry as machinery and disuses much of the worldview
  surrounding the traditional definition of adaptation as documented in various
  tutorials about the ZCA.  It doesn't try to use interfaces as documentation, either.
  The API docs are generated from the implementation classes rather than from
  interfaces.  The presence of interfaces at all is largely just an implementation detail.</p>
<h1>Interfaces As Documentation and Component Creation</h1>
<p>  Interfaces can act as great documentation.  If you're conscientious
  about maintaining the interface definition for some implementation
  (or set of implementations), there is incontrovertible benefit to
  interface documentation.</p>
<p>  However, designing a good interface is <em>hard</em>.  Can anyone really be
  expected to sit down and design a formal interface that represents
  the contract for some component before he even codes up the first
  implementation of that component and some tests for it?  No, of
  course not.  Just can't happen, sorry, unless you've done this
  particular thing ten times before.  API design is a highly iterative 
  process: you throw ten revisions of an API away before you get one
  that is mostly right.</p>
<p>  Therefore, you almost never want to promise that a particular
  component even has <em>any</em> interface until you've got that interface
  right in the context of some larger system full of consumers.  Until
  you've got the interface right, the interaction between code and
  components that might implement some notional interface implied by a
  component is just an <em>implementation detail</em>.  It might be an
  important implementation detail, but it's often OK if it stays one
  forever.  <em>Some components don't need their interfaces spelled out
  because they are purely an implementation detail</em>.  If there's only
  one or two consumers of a particular "component", <em>it's probably OK</em>
  for that component to not have a formal interface.  A system that
  has fewer, more meaningful and highly formalized contracts is
  usually easier to understand than a system that has many small
  contracts that all have a high probability of changing radically
  over time, because the overhead of maintaining the interface
  definitions for smaller contracts makes them less likely to be true.
  Wrong definitions are worse than none.</p>
<p>  So here we have this system, the ZCA, that uses interfaces as a
  primary mechanism to perform higher-level operations such as
  adaptation.  You are <em>required</em> to declare an interface for some
  component to use those higher-level operations.  This is required by
  the worldview that states that adaptation is the conversion of an
  object implementing one interface to another, period, full stop.
  Worse, once you define an interface, you are expected to <em>maintain</em> its
  definition over the lifetime of the project; ideally it should never
  fall out of sync with the true interface expected by the consumers
  of an object which implements it.  This is usually unreasonable
  in systems with dozens or hundreds of interface definitions.
  On projects with many contributors over time, and many interfaces, 
  it's not easy to ensure that interface definitions are both
  correct and comprehensive.  You <em>can</em> define an interface as a plain 
  "marker" without any attribute or method definitions.  This essentially 
   means that you promise no contract of an adaptation to this interface.
  But this is frowned  upon in a worldview where the point of adaptation 
  is to convert an object implementing one interface to an object 
  implementing another. It's considered bad form, an "abuse", a cast
  to a void pointer.</p>
<p>  Meanwhile, the adaptation machinery provided by the ZCA is useful in many
  contexts: particularly for dependency injection in unit tests, so
  it's extremely tempting to want to make use of it for this purpose
  alone.  Almost all Zope-related projects use the ZCA for unit
  testing dependency injection.  Defining "interfaces" for all your
  "components" is required there because it's the only way to get what
  you want for testing dependency injection purposes.</p>
<p>  There should actually be very few <em>true</em> plugpoints in any system.
  Far, far, far fewer, by maybe even an order of magnitude, than those
  implied by use of adaptation in the typical Zope-related project.
  Probably nine out of ten uses of adaptation in ZCA-using application source code is
  there <em>only</em> to provide a place to hang some testing dependency
  injection point.  These are <em>extremely hard</em> to tell apart from the
  "real" plugpoints in any given system, because they quack exactly
  like the plugpoint duck.  Another questionable use for an interface
  include using one to look up a "utility" (especially an "unnamed"
  utility) where the utility is something that has an "obvious" API
  such as a dictionary.  Documenting the API of this obvious thing
  in the interface definition is just silly.  Interfaces tend to be added
  to any system of consequence for similarly questionable reasons.</p>
<p>  So now at this point, if you've been following along, we've built a
  system that probably has incomplete documentation for its
  "components", because, really, there aren't any yet.  Or maybe very
  few "true" components.  We're not really smart enough to define any
  "components" yet.  We may <em>never</em> be smart enough to define them
  properly.  Our project just uses adaptation for several discrete
  purposes, none of them <em>actually</em> related to increasing
  comprehensibility or providing plugpoints: we've just hacked in some
  dependency injection points for unit tests that use the adapter
  machinery to good purpose.  But we didn't do this to increase
  comprehensibility; we did it because it makes unit testing easier.
  We've thus effectively misdirected the casual code reader into
  believing that there are lots and lots of "components" with
  well-thought-out "interfaces" when really all we've been trying to
  do is to test the system more easily.  The system is still in major
  flux, and its "interfaces" only represent some half-baked
  transitional state of affairs, probably not even correct.  The contracts aren't truly formalized yet
  at all.  But it looks pretty impressive.</p>
<p>  A developer new to the project needs to be able to detect and
  discount the adaptations in the code done purely for unit testing
  dependency injection and convenience and the adaptations that imply true component
  plugpoints.  That task is understandably difficult because we're
  using the same machinery for entirely different purposes.</p>
<p>  As a result, we've actively subverted the original goal: to make the
  system more understandable.</p>
<h1>Use of Adaptation Makes A System More Understandable</h1>
<p>  The idea that mere <em>use</em> of adaptation as a mechanism to improve
  large system comprehensibility for a new team member is utterly
  ludicrous.  Mere use of the adaptation pattern adds no additional
  comprehensibility whatsoever to any system, small or large.  Seeing
  "getMultiAdapter((foo, bar), IFrobnozz)" in code lends no particular
  insights as to the intent of the developer who wrote it.  I'm <em>not</em>
  talking about syntax here either; the adaptation could be spelled
  "config['frobnozz](foo, bar)" and it would have the same level of
  comprehensibility in isolation.</p>
<p>  Believing that mere <em>use</em> of any particular adaptation syntax in the
  code itself helps a new developer understand the intent of the
  adaptation is a complete fantasy.  The <em>only</em> way to explain the
  intent of any particularly important adaptation is via hand-crafted
  narrative documentation explaining why some particular adaption
  takes place in a particular spot.  The component architecture
  doesn't help at all there; you're on your own.</p>
<p>  Writing software is hard.  Writing software documentation is even
  harder.  But it needs to be done.  No tool is going to remove this
  requirement.  Mere use of adaptation in code is no substitute
  whatsoever for writing high-level design documentation that explains
  how the system components work together.  Using adaptation without
  explaining the "why" just hurts comprehensibility.  Folks who
  pretend that they've made their system comprehensible simply by
  using adaptation are fooling themselves in the same way that folks
  who write doctests but don't test all their code and don't write
  narrative docs have fooled themselves into thinking they've written
  both good tests and good docs.</p>
<p>  Worse, when we do use adaptation without explanation, a new
  developer must first go understand the machinery that implements
  adaptation to get a sense of the intent.  That machinery is not
  particularly well-documented.  There is no explanation of the lookup
  ordering that takes place when components are adapted at all, in
  particular.</p>
<p>  As a result, we've actively subverted the original stated goal: to
  make the system more understandable.</p>
<h1>Conclusions</h1>
<p>  I believe that following the current trajectory of "the ZCA" is
  unwise. I am happy to continue using the "zope.component" package,
  because its machinery works really, really well and it is useful in
  many scenarios, particularly for unit testing dependency injection
  and for building systems that can be considered "pluggable" after
  the fact (systems with additional documentation that explains the
  how and <em>why</em> of each true plugpoint).  However, I no longer buy in 
  to the idea that extremely casual use of the concept of adaptation
  defined formally as converting one interface to another laid on top of 
  this machinery is of any benefit whatsoever when producing a large
  system in isolation.</p>
<p>  I think we can improve this state of affairs via the following:</p>

<ul>
<li>Create a package with <em>only machinery which can be used to
    implement an adaptation pattern</em> in the package.  Document the
    shit out of it, like it was for your grandma.  Don't impose any
    particular "worldview" on consumers of this machinery: in
    particular, do not <em>require</em> the use of Zope interfaces as inputs.
    Maybe provide extra behavior (such as inheritance) when the inputs
    are interfaces, but allow for registration and lookup markers that
    are not interfaces.</li>
<li>Base the API of what is currently zope.component on the machinery
    in the package I've suggested above.  zope.component would be a
    consumer of this package, and would be free to impose the "an
    adaptation is the conversion of one interface to another"
    worldview on <em>its</em> consumers.</li>
<li>Provide some tools that make it easier to do unit testing
    dependency injection without needing to declare formal interfaces
    (this might be the package in the first bullet point).  Or at
    least think up a convention where it's possible for a casual
    source reader to immediately know that some adaptation is present
    only for test dependency purposes, as opposed to a true plugpoint.</li>

</ul>
<p>  I'd be willing to work on projects that go in these directions.  I'm
  not willing to work on projects that take the current zope.component
  and <em>add</em> APIs to it without factoring out the underlying machinery
  bits, though.
</p></div>
    </content>
    <updated>2009-12-03T04:58:30Z</updated>
    <category term="Zope"/>
    <category term="python"/>
    <category term="tech"/>
    <category term="zope"/>
    <author>
      <name>chrism</name>
    </author>
    <source>
      <id>http://plope.com</id>
      <link href="http://plope.com/python.rss" rel="self" type="application/atom+xml"/>
      <link href="http://plope.com" rel="alternate" type="text/html"/>
      <subtitle>Chris McDonough's Python Feed</subtitle>
      <title>Chris McDonough's Python Feed</title>
      <updated>2010-02-12T15:01:01Z</updated>
    </source>
  </entry>

  <entry xml:lang="en">
    <id>http://blog.repoze.org/repoze.bfg%201.2a1%20released/</id>
    <link href="http://blog.repoze.org/repoze.bfg%201.2a1%20released/" rel="alternate" type="text/html"/>
    <title xml:lang="en">repoze.bfg 1.2a1 released</title>
    <content type="xhtml" xml:lang="en"><div xmlns="http://www.w3.org/1999/xhtml"><p>repoze.bfg 1.2a1 is now released.  It can be installed via:</p>
<pre class="literal-block">easy_install -i http://dist.repoze.org/bfg/1.2/simple repoze.bfg
</pre>
<p>Or via PyPI.</p>
<p>Documentation for this release exists at <a class="reference external" href="http://docs.repoze.org/bfg/1.2/">http://docs.repoze.org/bfg/1.2/</a>.</p>
<p>This is a major feature release.  The new features of the release are detailed
in a <a class="reference external" href="http://docs.repoze.org/bfg/1.2/whatsnew-1.2.html">What's New document</a>.</p>
<p>In particular, this release has a new "imperative configuration" mode that
makes it possible to create the simplest repoze.bfg application as a single
Python file.</p></div>
    </content>
    <updated>2009-11-28T05:00:00Z</updated>
    <author>
      <name>Agendaless</name>
    </author>
    <source>
      <id>http://blog.repoze.org/index.atom</id>
      <link href="http://blog.repoze.org" rel="alternate" type="text/html"/>
      <link href="http://blog.repoze.org/index.atom" rel="self" type="application/atom+xml"/>
      <title xml:lang="en">Repoze Blog RSS Feed</title>
      <updated>2010-03-06T05:00:00Z</updated>
    </source>
  </entry>

  <entry>
    <id>http://plope.com/Members/chrism/baby_why_do_you_make_me_hit_you</id>
    <link href="http://plope.com/Members/chrism/baby_why_do_you_make_me_hit_you" rel="alternate" type="text/html"/>
    <title>easy_install, Baby, Why Do You Make Me Hit You?</title>
    <summary>We were getting along so well...</summary>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><img alt="Baby why do you make me hit you?" src="http://plope.com/easyinstall.png"/></div>
    </content>
    <updated>2009-11-10T00:41:15Z</updated>
    <category term="python"/>
    <category term="tech"/>
    <category term="zope"/>
    <author>
      <name>chrism</name>
    </author>
    <source>
      <id>http://plope.com</id>
      <link href="http://plope.com/python.rss" rel="self" type="application/atom+xml"/>
      <link href="http://plope.com" rel="alternate" type="text/html"/>
      <subtitle>Chris McDonough's Python Feed</subtitle>
      <title>Chris McDonough's Python Feed</title>
      <updated>2010-02-03T22:21:17Z</updated>
    </source>
  </entry>

  <entry>
    <id>http://plope.com/Members/chrism/worse_is_better</id>
    <link href="http://plope.com/Members/chrism/worse_is_better" rel="alternate" type="text/html"/>
    <title>Worse Is Better</title>
    <summary>Sometimes you just need to understand that "worse is better" to make it all better.</summary>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p> There's a hand-wringing coversation today on the Python list where
someone suggested making 2.7 "the last Python in the 2.X series",
giving the rationale that people really should be using 3.X and that
dropping maintenance for 2.X will give them a reason to move.</p>
<p>I say hooray!  But not for the reason you think.</p>
<p>Now I'm pretty sure there will be a Python 2.8, 2.9, and 2.10, 2.11
and so on as sure as the sun will rise.  These releases may not be
prepared by the same people who have the responsibility of creating
releases today, but other folks will probably pop up to fill in for
them, even if only unofficially.</p>
<p>But even if there isn't another blessed Python 2 release from the
"core team", that's OK.  Worse is better.</p>
<p>I get the sense that the folks who are currently pushing new Python
releases aren't really that interested in making sure old code runs
"forever".  It was a tipoff when version 3 started out with minor
backwards incompatiblities, of course.  This isn't very surprising.
Preserving backwards compatibility in complex systems is really just
no fun.  It's an ugly, thankless slog.  Your mistakes stare you in the
face daily.  It's a <em>lot</em> more fun to do greenfields projects like
Python 3000.  We all love green-fielding things.  (BTW, I think <a href="http://bit.ly/pep3003">PEP
3003</a> might declare playtime over though).</p>
<p>In the meantime, though, old Python code never dies, and must continue
to run, even when nobody understands it fully any more.  With a Python
2 that is very conservatively maintained (or even <em>un</em>-maintained),
this is won't be much of a problem.  Because there won't be new
features, there just won't be any backwards compatibility problems.
If Python 2.8 was released as just a set of patches that made Python 2
compile against the latest and greatest set of operating system
updates from the major vendors, and had no other changes, fantastic.
For legacy systems I maintain, that's change I can believe in.  Give
me more of that!</p>
<p>I fear that in the actual world, code stability provides more benefit
than new syntactical candy and included batteries and obsessive
reorganization.  It's going to take a <em>long</em> time for people to switch
to Python 3.  You can try to speed up the process by shepherding
people along some decision tree, but they're going to do things at
their own pace no matter what decisions you try to make for them.  You
may <em>want</em> them to arrive at a decision like "I'm going to rewrite
this code I barely understand anymore in a backwards incompatible
variant of the programming language it was originally written in".
That's a reasonable desire.  But if the only other choice you provide
to them other than that one is "maintain the old programming language
version myself", you are only <em>implicitly</em> leaving out the choice "or
just rewrite the system in a different language altogether".  This
implicit choice is often the one people make when they are led along
some artificial decision tree.</p>
<p>If a new version of something is not 100% backwards compatible, I
think you just need to let the old version and the new version compete
on the field of mindshare instead of declaring one the royal blessed
successor to the other, and artificially mandating that releases of
the old version won't be made.  There's no guarantee that today's
Python 2 code will become tomorrow's Python 3 code.  And that's OK.
Python 2 is a fantastic language.
</p></div>
    </content>
    <updated>2009-11-03T21:29:14Z</updated>
    <category term="python"/>
    <category term="tech"/>
    <category term="zope"/>
    <author>
      <name>chrism</name>
    </author>
    <source>
      <id>http://plope.com</id>
      <link href="http://plope.com/python.rss" rel="self" type="application/atom+xml"/>
      <link href="http://plope.com" rel="alternate" type="text/html"/>
      <subtitle>Chris McDonough's Python Feed</subtitle>
      <title>Chris McDonough's Python Feed</title>
      <updated>2010-01-29T16:46:57Z</updated>
    </source>
  </entry>

  <entry xml:lang="en">
    <id>http://pauleveritt.wordpress.com/?p=52</id>
    <link href="http://pauleveritt.wordpress.com/2009/10/30/i-admit-it-deco-looks-pretty-nice/" rel="alternate" type="text/html"/>
    <title>I admit it, Deco looks pretty nice</title>
    <summary type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml">This post has the jaded volume turned to eleven but even so, I’m impressed.
I watched the video of Rob Gietema’s presentation on Deco, the “new way to manage page layout, composite pages and rich content in Plone 4″.  I approach the entire topic with cynicism, dread, and exhaustion on a number of fronts.
Well, color me [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=pauleveritt.wordpress.com&amp;blog=5206833&amp;post=52&amp;subd=pauleveritt&amp;ref=&amp;feed=1"/></div>
    </summary>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><br/><p>This post has the jaded volume <a href="http://www.youtube.com/watch?v=EbVKWCpNFhY">turned to eleven</a> but even so, I’m impressed.</p>
<p>I watched <a href="http://blog.fourdigits.nl/tinymce-and-deco-at-the-plone-conference-2009">the video</a> of <a href="http://blog.fourdigits.nl/robgietema">Rob Gietema’s</a> presentation on <a href="http://code.google.com/p/plone-deco/">Deco</a>, the “new way to manage page layout, composite pages and rich content in Plone 4″.  I approach the entire topic with cynicism, dread, and exhaustion on a number of fronts.</p>
<p>Well, color me intrigued.  I’ll probably clutch tightly to my bitter, curmudgeonly outlook.  But I must confess to being impressed, in a number of ways.  I think they’ve done a good job thinking about the problem.  It looks like they’re going slow and being unafraid to refactor ideas and implementations.  It also has, already, a nice visual appeal along with some clever simplifying assumptions to keep the congitive overload under control.  Finally, this is a hard space to work in, technically, and it seems like they have some mad skillz.</p>
<p>There’s still a lot of challenge ahead.  The biggest is what I view as the chief paradox confronting Plone.  On one hand, a significant portion of people are fed up with how some of the features are implemented.  But on the other hand, they’re burned out by a legacy of undead overhauls and don’t have much patience for revolution.  (Sidebar: my opinion is, I sympathize but The Time Has Come.)</p>
<p>Additionally, while it’s a lot of work to do the product, it’s a lot more work to do the “whole” product: documentation, bug fixing, ongoing compatibility, performance, and other stuff over the long haul.  Letting Deco have a long gestation period <em>outside</em> the core would be advisable.  The more baked it is, the more legitimate it will feel when added to Plone, and the less resistance from the undead-overhaul-worriers.</p>
<p>So good luck Deco.  If even 2/3 of the features are implemented, but implemented superbly over the long haul, then Plone will have something sweet to hang its hat on.  (All of the above applies equally to <a href="http://maurits.vanrees.org/weblog/archive/2009/10/david-glick-building-content-types-with-dexterity/view?set_language=nl">Dexterity</a>, the new content type system.)</p>
  <a href="http://feeds.wordpress.com/1.0/gocomments/pauleveritt.wordpress.com/52/" rel="nofollow"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/pauleveritt.wordpress.com/52/"/></a> <a href="http://feeds.wordpress.com/1.0/godelicious/pauleveritt.wordpress.com/52/" rel="nofollow"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/pauleveritt.wordpress.com/52/"/></a> <a href="http://feeds.wordpress.com/1.0/gostumble/pauleveritt.wordpress.com/52/" rel="nofollow"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/pauleveritt.wordpress.com/52/"/></a> <a href="http://feeds.wordpress.com/1.0/godigg/pauleveritt.wordpress.com/52/" rel="nofollow"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/pauleveritt.wordpress.com/52/"/></a> <a href="http://feeds.wordpress.com/1.0/goreddit/pauleveritt.wordpress.com/52/" rel="nofollow"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/pauleveritt.wordpress.com/52/"/></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=pauleveritt.wordpress.com&amp;blog=5206833&amp;post=52&amp;subd=pauleveritt&amp;ref=&amp;feed=1"/></div>
    </content>
    <updated>2009-10-30T14:09:05Z</updated>
    <category term="Plone"/>
    <author>
      <name>Paul Everitt</name>
    </author>
    <source>
      <id>http://pauleveritt.wordpress.com</id>
      <logo>http://www.gravatar.com/blavatar/b4345850285023fbd98c4a40e02f7cbd?s=96&amp;d=http://s.wordpress.com/i/buttonw-com.png</logo>
      <link href="http://pauleveritt.wordpress.com/feed/" rel="self" type="application/atom+xml"/>
      <link href="http://pauleveritt.wordpress.com" rel="alternate" type="text/html"/>
      <link href="http://pauleveritt.wordpress.com/osd.xml" rel="search" type="application/opensearchdescription+xml"/>
      <subtitle>Paul's ramblings about projects and Python/Zope/Plone/Repoze/BFG technologies.</subtitle>
      <title>Chatterbox, Reloaded</title>
      <updated>2010-02-18T14:15:11Z</updated>
    </source>
  </entry>

  <entry xml:lang="en">
    <id>http://pauleveritt.wordpress.com/?p=48</id>
    <link href="http://pauleveritt.wordpress.com/2009/10/30/congrats-new-plone-foundation-board/" rel="alternate" type="text/html"/>
    <title>Congrats new Plone Foundation board</title>
    <summary type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml">Strong ongoing board of directors and big turnaround on finances make Plone's community-owned non-profit quite a success story.<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=pauleveritt.wordpress.com&amp;blog=5206833&amp;post=48&amp;subd=pauleveritt&amp;ref=&amp;feed=1"/></div>
    </summary>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><br/><p>Per <a href="http://plone.org/foundation/newsitems/plone-foundation-board-election-results-2009">the announcement</a>, congrats to the new board of directors for the Plone Foundation.  I really, really like that lineup of people. It’s amazing, though, that there were at least five others in the election that would also have been strong to have on the board.</p>
<p>A particular thanks to Hanno Schlichting for once again conducting the election.  I have utter confidence in the things he does, be it Plone Foundation process stuff or gradually untangling years of technical cruft as part of his Plone 5 release manager duties.</p>
<p>I saw the minutes of the <a href="http://maurits.vanrees.org/weblog/archive/2009/10/plone-foundation-meeting">Plone Foundation annual member’s meeting</a> (thanks Maurits for the writeup.)  Toby reported that, after spending half of the original CA donation of $100k, the PF in one year has its bank account back to the original amount.  This is primarily due to the <a href="http://plone.org/foundation/newsitems/plone-foundation-launches-sponsorship-program-for-plone-consulting-firms">sponsorship plan</a> that Jon Stahl helped kick off, tied to the excellent work the Plone.net team at Pilot Sytems (plus Reinout, plus others) have done over the years.</p>
<p>The price point for sponsorship makes it easy to get companies in, and the allocation of funds (e.g. release managers, promotion) makes it very easy to justify.  Since the price point is a yearly fee, I suspect that you’ll see another $50k come in during the next half year, meaning…</p>
<p>…the Plone Foundation is a very successful community-managed outfit.  Congrats to the previous board for orchestrating this turnaround on finances, and here’s to a good 2010 for the Plone Foundation.</p>
  <a href="http://feeds.wordpress.com/1.0/gocomments/pauleveritt.wordpress.com/48/" rel="nofollow"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/pauleveritt.wordpress.com/48/"/></a> <a href="http://feeds.wordpress.com/1.0/godelicious/pauleveritt.wordpress.com/48/" rel="nofollow"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/pauleveritt.wordpress.com/48/"/></a> <a href="http://feeds.wordpress.com/1.0/gostumble/pauleveritt.wordpress.com/48/" rel="nofollow"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/pauleveritt.wordpress.com/48/"/></a> <a href="http://feeds.wordpress.com/1.0/godigg/pauleveritt.wordpress.com/48/" rel="nofollow"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/pauleveritt.wordpress.com/48/"/></a> <a href="http://feeds.wordpress.com/1.0/goreddit/pauleveritt.wordpress.com/48/" rel="nofollow"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/pauleveritt.wordpress.com/48/"/></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=pauleveritt.wordpress.com&amp;blog=5206833&amp;post=48&amp;subd=pauleveritt&amp;ref=&amp;feed=1"/></div>
    </content>
    <updated>2009-10-30T13:36:06Z</updated>
    <category term="Plone"/>
    <author>
      <name>Paul Everitt</name>
    </author>
    <source>
      <id>http://pauleveritt.wordpress.com</id>
      <logo>http://www.gravatar.com/blavatar/b4345850285023fbd98c4a40e02f7cbd?s=96&amp;d=http://s.wordpress.com/i/buttonw-com.png</logo>
      <link href="http://pauleveritt.wordpress.com/feed/" rel="self" type="application/atom+xml"/>
      <link href="http://pauleveritt.wordpress.com" rel="alternate" type="text/html"/>
      <link href="http://pauleveritt.wordpress.com/osd.xml" rel="search" type="application/opensearchdescription+xml"/>
      <subtitle>Paul's ramblings about projects and Python/Zope/Plone/Repoze/BFG technologies.</subtitle>
      <title>Chatterbox, Reloaded</title>
      <updated>2010-02-18T14:15:11Z</updated>
    </source>
  </entry>

  <entry>
    <id>http://plope.com/Members/chrism/a_hundred_percent</id>
    <link href="http://plope.com/Members/chrism/a_hundred_percent" rel="alternate" type="text/html"/>
    <title>The Side Effect Benefit of 100% Statement Coverage</title>
    <summary>I've noticed a side-effect benefit of requiring 100% code statement coverage within the open source projects I manage.</summary>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>I don't like reading sanctimonious treatises on testing either.  This
is only partly one of those.</p>
<p>First of all, I hereby to resolve to buy Ned Batchelder a case of his
favorite for all his excellent work on
<a href="http://nedbatchelder.com/code/coverage/">coverage</a> .  This tool
measures statement coverage while some program runs.
<a href="http://somethingaboutorange.com/mrl/projects/nose">nose</a> has helpful
bindings to this tool, which Chris Perkins pointed me at one day, so I
probably owe the nose guys and Chris at least one beer apiece too.</p>
<p>Because statement coverage is so easy to measure using Ned's coverage
tool, and because it integrates so well with unittest via nose, I have
resolved that the open source code I release will all have 100%
statement coverage when its tests are run.</p>
<p>As far as I'm concerned, 100% statement coverage is the "least you can
do" to make sure the code is of a particular quality; it doesn't mean
the code does what it's supposed to, but it does mean that the author
has probably grokked most of the code, and hopefully, by extension,
the problem domain, in order to figure out how to test all of its
statements.</p>
<p>I promised that this wouldn't be entirely cheerleading for testing or
a chiding wag of the finger pointed at people who do not test.  You
can decide for yourself the direct quality benefits of 100% statement
coverage via tests; I can only say it works for me.  Let's instead
consider a big side effect benefit.</p>
<p><strong>With a 100% test coverage invariant, you can reject poor-quality
patches with less subjectivity.</strong></p>
<p>A common sort of patch received by open source project maintainers is
the "paper towel roll" patch.  It's a patch that was coded while its
author looked through a paper towel roll at some very specific bit of
code in your larger system.  The patch is wrong, but its author does
not have enough context to know why: it patches some subsystem in a
way doesn't make any sense when the entirety of the system is
considered.  It works, but applying it as-is would be disastrous on
some level (documentation requirements / conceptual integrity / code
cleanliness, additional unwanted software dependencies, etc).</p>
<p>Paper-towel-roll patches are tricky to deal with as an open source
maintainer.  Do you throw it away?  Do you add the feature implied by
the patch in "the right way"?  How do you deal with the original
submitter?  How pissed off is he going to be if you reject it
out-of-hand without trying to help him implement it in the right way?
Do you even want the feature?  Even if you're +0 or +1 on the feature,
do you have enough time to deal with doing it properly?</p>
<p>One handy attribute of paper-towel-roll patches is this: they usually
come without any tests.  We can turn this obvious deficiency into at
least one immediate advantage if we require 100% statement coverage.</p>
<p>Without a 100% coverage invariant, your only recourse to reject a poor
paper-towel-roll patch will be to say "hey, this patch is pretty
terrible", which is obviously subjective and can lead to pointless,
time-consuming arguments.  It may also require that you explain in
great detail the system from end-to-end to the submitter, just so he
or she will understand why it's a bad patch.  This takes a long time,
and the payoff rate is low, because often the submitter is a
one-timer: he won't be back to submit patch #2.</p>
<p>With the 100% coverage invariant, you can instead use the less
provocative request "this patch doesn't maintain the 100% statement
test coverage invariant, could you fix this?"  The requirement is
unambiguous: either 100% of the statements in the package are executed
when the tests run or they're not.  You can't argue with a percentage.
We've taken the subjectivity out of the initial contact with the patch
submitter.</p>
<p>Insisting that a patch maintains the invariant is usually enough to
scare off extremely casual paper-towel-roll patch submitters who've
submitted something insane which in reality you just don't really want
to even think about.  This ability to reject a patch without wasting
any time is the 99% benefit.  Nobody gets their ego bruised, no time
is wasted, and your code is still of high quality.</p>
<p>But the submitter <em>might</em> have enough tenacity to write the tests
after you ask him to.   This will have one of two outcomes:</p>

<ul>
<li>the act of needing to write the tests will give the patch submitter
  enough context to do it correctly, so the second time around, you
  just will receive a patch that is both correct <em>and</em> has tests.</li>
<li>the patch submitter may come back with an equally awful solution
  that just happens to have 100% statement coverage.</li>

</ul>
<p>This is risky too: he's gone through all the hoop-jumping work and you
still have to have "the talk" with him.  I haven't really figured out
how to deal with this.  On the positive side, though, it does mean
you've identified somebody who has the tenacity to do something right,
and has a high likelihood of submitting more patches in the future.
This is extremely good.</p></div>
    </content>
    <updated>2009-10-21T14:47:14Z</updated>
    <category term="python"/>
    <category term="tech"/>
    <category term="zope"/>
    <author>
      <name>chrism</name>
    </author>
    <source>
      <id>http://plope.com</id>
      <link href="http://plope.com/python.rss" rel="self" type="application/atom+xml"/>
      <link href="http://plope.com" rel="alternate" type="text/html"/>
      <subtitle>Chris McDonough's Python Feed</subtitle>
      <title>Chris McDonough's Python Feed</title>
      <updated>2010-01-24T17:00:51Z</updated>
    </source>
  </entry>

  <entry>
    <id>http://plope.com/Members/chrism/import_time_side_effects</id>
    <link href="http://plope.com/Members/chrism/import_time_side_effects" rel="alternate" type="text/html"/>
    <title>Import Time Side Effects and You</title>
    <summary>Let's learn about import time side effects.</summary>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>I have <a href="http://www.plope.com/Members/chrism/logging_blues">blogged</a>
<a href="http://www.plope.com/Members/chrism/now_not_to_write_python">before</a>
about this topic, but what the hell, I'll do it again.</p>
<p>Lots of people want to "use Python" for everything.  They'd like to
use Python for configuration files, for populating external registries
as the result of some import statement, and other things.  They
inevitably define "use Python" as "put lots of code at module scope in
a Python module". I don't really mind this so much, but please, if you
do, don't make me use the result.  In particular, don't make me use a
framework or library in which this behavior is relied upon.</p>
<p>There are reasons that every credible book about Python, in the first
chapter, when describing an executable Python script, places the
following kind of clause in the script, which allows execution when a
module is a script, but prevents it when it is imported:
</p><pre>  if __name__ == '__main__':
      .. do stuff ..
</pre>
<p/>
<p>Since the script may (at some point) be imported as a module by
another module, and the script author does not want the code inside
the "if" block to be executed at import time (in the case where the
script is imported by another, <code>__name__</code> will not be <code>__main__</code>), it
makes sense to code "defensively" like this.</p>
<p>Many people seem to forget this "my first Python" lesson when
developing larger systems. It's usually insane for the import of a
module to have side effects other than the following:</p>

<ul>
<li>An import of another module or global.</li>
<li>Assignment of a variable name in the module to some constant value.</li>
<li>The addition of a function via a <code>def</code> statement.</li>
<li>The addition of a class via a <code>class</code> statement.</li>
<li>Control flow which may handles conditionals for platform-specific
  handling or failure handling of the above.</li>

</ul>
<p>Any other sort of logic inside the top level execution path of a
Python module (any code that would be executed during "import") should
be regarded with great suspicion and perhaps even loathing.</p>
<p>The codepath represented by top-level statements in modules is owned
by <em>Python</em>, not by you.  Python is in charge of its execution; you
are not.  You can never predict when it will be executed.</p>
<p>Here's an example of such an antipattern (code is at module scope):
</p><pre>   import atexit
   import logging

   def _exit_function():
       logging.info('process shutting down')

   atexit.register(_exit_function)
</pre>
<p/>
<p>This is an example I've taken (in spirit) from a module in the Python
standard library.</p>
<p>First of all, any library code that thinks its smart enough to
register an atexit function is mistaken.  Only an application (and not
a library) can possibly be smart enough to register an atexit
function, because only an application is responsible for controlling
the horizontal and vertical of application startup and shutdown, not
any of the libraries employed by the application.</p>
<p>That's a bit besides the point, though.  The real problem here is that
the code which performs the <code>atexit.register</code> registration executes at
module scope.  This means that when this module is imported, it has
the side effect of registering an atexit function.  But what if this
module just happened to be imported by another "innocently", but its
functionality never used? </p>
<p>It's totally absurd to try to build a system that configures or starts
itself based on import time side effects.  When you build a system
that relies on import time side-effects, you have no control over
<em>when</em> the code gets executed: it might get imported much earlier, or
much later than you expect it to be.  You may not even have any
control over <em>why</em> the code is executed: some code scanner, such as a
testing tool, may import it, and may fail as a result, possibly at
shutdown.</p>
<p>If you do this sort of thing, great.  Just keep it to yourself and
wash your hands afterwards.  And maybe don't do it.  OK.  Just don't
do it; that's the best solution.
</p></div>
    </content>
    <updated>2009-10-19T05:05:46Z</updated>
    <category term="python"/>
    <category term="tech"/>
    <category term="zope"/>
    <author>
      <name>chrism</name>
    </author>
    <source>
      <id>http://plope.com</id>
      <link href="http://plope.com/python.rss" rel="self" type="application/atom+xml"/>
      <link href="http://plope.com" rel="alternate" type="text/html"/>
      <subtitle>Chris McDonough's Python Feed</subtitle>
      <title>Chris McDonough's Python Feed</title>
      <updated>2010-01-08T15:48:17Z</updated>
    </source>
  </entry>

  <entry>
    <id>http://plope.com/smartest_guy_in_the_room</id>
    <link href="http://plope.com/smartest_guy_in_the_room" rel="alternate" type="text/html"/>
    <title>You're the Smartest Guy In The Room</title>
    <summary>.. but please, try to restrain yourself.</summary>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>You are smart.  No one else knows much.  In fact, most people are
pretty stupid.  Everything except what you're doing <em>right now</em> is
stupid.  Django is stupid.  Zope is stupid.  Twisted is stupid.
Setuptools is stupid.  The GIL is stupid.  Pylons is stupid.
TurboGears is stupid.  Guido is stupid.  PJE is stupid.  Ruby on Rails
is a total hack.  And oh my god, all these people in IRC are clearly
mentally challenged.  Why do they keep arguing with you?</p>
<p>I get it: it's not easy being a genius.  So, if you don't mind, I have
a request.  Given that it would certainly not tax you professionally,
because it's all so simple and obvious, do you think that you could
contribute something to Python or some Python-related project that
demonstrates your immense base of knowledge and helps other people?</p>
<p>Ah but wait!  You have.  I've seen that one package you keep talking
about that you wrote and released six months ago.  It has a couple of
users, even.  But look... uh... oh dear.. this is awkward.  I don't
mean to be negative here.  But there's a couple problems.  You may be
a genius, but at 33% test coverage, you better be almost omniscient.
I'm personally not a genius, so I need to rely on something so banal
as package test coverage metrics to make decisions about what to use.</p>
<p>Look.  Let's be frank.  I know you were the smartest guy in your high
school class.  I realize that in your circle of peers, you are the one
who most often actually knows what he's doing.  I get the fact that
you like puzzles, and you're good at solving them.  I realize you
believe you are hot shit, and a few other people might too.</p>
<p>But if I may be so bold, here are some suggestions:</p>

<ul>
<li>Shut the fuck up.  I mean this in the kindest, and gentlest of ways,
  as maybe a friendly uncle might tell you to "shut the fuck up".</li>
<li>Work on your capacity to talk with other people without being a
  complete, utter cock.  We've already adjusted our expectations, with
  you being a programmer and all, we realize you're constitutionally
  straightforward.  But there's a difference between being
  straightforward and being a dick.  Your profession and your history
  as "the smartest guy in the room" doesn't excuse you from displaying
  basic courtesy.</li>
<li>You don't need to prove anything to me or anybody else.  I could
  care less.  It's not always about you.</li>
<li>Write some code that works all the time, every time that lots of
  people find useful.  Maintain that code for 5 years.  At this point,
  you will have something to be proud of.</li>

</ul>
<p>Thank you.
</p></div>
    </content>
    <updated>2009-09-30T05:45:04Z</updated>
    <category term="python"/>
    <category term="tech"/>
    <category term="zope"/>
    <author>
      <name>chrism</name>
    </author>
    <source>
      <id>http://plope.com</id>
      <link href="http://plope.com/python.rss" rel="self" type="application/atom+xml"/>
      <link href="http://plope.com" rel="alternate" type="text/html"/>
      <subtitle>Chris McDonough's Python Feed</subtitle>
      <title>Chris McDonough's Python Feed</title>
      <updated>2010-01-06T01:45:02Z</updated>
    </source>
  </entry>

  <entry xml:lang="en">
    <id>http://blog.ianbicking.org/?p=125</id>
    <link href="http://blog.ianbicking.org/2009/09/10/a-new-self-definition-for-foss/" rel="alternate" type="text/html"/>
    <link href="http://blog.ianbicking.org/2009/09/10/a-new-self-definition-for-foss/#comments" rel="replies" type="text/html"/>
    <link href="http://blog.ianbicking.org/2009/09/10/a-new-self-definition-for-foss/feed/atom/" rel="replies" type="application/atom+xml"/>
    <title xml:lang="en">Toward a new self-definition for open source</title>
    <summary xml:lang="en">This is roughly the speech I gave as a keynote address at DjangoCon 2009 in Portland.
I’ve been programming Python web software for quite a while now.  I considered coming here and talked about WSGI, standards, cross-framework integration, etc., but I decided I wanted to come up here and talk to you as compatriots, as [...]</summary>
    <content type="xhtml" xml:lang="en"><div xmlns="http://www.w3.org/1999/xhtml"><div class="document">
<blockquote><p>
This is roughly the speech I gave as a keynote address at <a class="reference external" href="http://www.djangocon.org/">DjangoCon 2009</a> in Portland.</p></blockquote>
<p>I’ve been programming Python web software for quite a while now.  I considered coming here and talked about WSGI, standards, cross-framework integration, etc., but I decided I wanted to come up here and talk to you as compatriots, as fellow open source programmers.</p>
<p>Over the past year or so I have been thinking a lot about politics.  Not electoral politics per se, or the geopolitical situation, but the question of the meaning of what we are doing.  Maybe it is some sort of programmer midlife crisis: why am I doing what I’m doing, and why does it matter?  And also I have been thinking a lot about open source — what this thing that we’re doing means in the larger context.  Are we just engineers?  Is there some sort of movement?  If so, what is that movement?  Especially as open source has become more popular, the sense of a movement seems to dwindle.  It felt like a movement 10 years ago, but not as much today.  Why should this happen?  Why now, in the midst of success does open source seem less politically relevant than it did 10 years ago?</p>
<p>I’m also speaking somewhat to Django specifically, as I think it is one of the communities with a bit more resistance to the idea of the politics of code.  The Django philosophy is more: the value of this code is the value of what you do with it.  I’m not here to criticize this perspective, but to think about how we can find meaning without relying on the traditional free software ideas.  To see if there’s something here that isn’t described yet.</p>
<p>I’d like to start with a quick history of free and open source software.  My own start was in highschool where I was taking a class in which we all used Emacs.  This was my first introduction to any real sort of programming environment, to Unix, to a text editor that was anything to talk about.  At the time Emacs would say at startup "to learn more about the GNU project hit Control-H Control-P" — because of course you need a keyboard shortcut to get to a philosophy statement about an editor.  So one day I hit Control-H Control-P.  I was expecting to see some sort of About Message, or if you remember the software of the times maybe something about Shareware, or even "if you really like this software, consider giving to the Red Cross."  But instead I came upon the GNU Manifesto.</p>
<div class="section" id="gnu-manifesto">
<h2>GNU Manifesto</h2>
<p>I’d like to read a couple quotes from the <a class="reference external" href="http://www.gnu.org/gnu/manifesto.html">GNU Manifesto</a>.  There are more <a class="reference external" href="http://www.gnu.org/gnu/thegnuproject.html">modern descriptions of GNU</a>, but this is one of the first documents describing the project and its mission, written by Richard Stallman.  Let me quote the section "Why I Must Write GNU":</p>
<blockquote>
<p>"I consider that the golden rule requires that if I like a program I must share it with other people who like it. Software sellers want to divide the users and conquer them, making each user agree not to share with others. I refuse to break solidarity with other users in this way. [it continues...]</p>
<p>"So that I can continue to use computers without dishonor, I have decided to put together a sufficient body of free software so that I will be able to get along without any software that is not free."</p>
<p>[later it goes on...]</p>
<p>"The fundamental act of friendship among programmers is the sharing of programs; marketing arrangements now typically used essentially forbid programmers to treat others as friends. The purchaser of software must choose between friendship and obeying the law. Naturally, many decide that friendship is more important. But those who believe in law often do not feel at ease with either choice. They become cynical and think that programming is just a way of making money."</p>
</blockquote>
<p>When I read this statement I was immediate head-over-heels in love with this concept.  As a teenager, thinking about programming, thinking about the world, having a statement that was so intellectually aggressive was exciting.  It didn’t ask: "how wrong is piracy really", or "why are our kids doing this", but it asked "is piracy a moral imperative" — that’s the kind of aggressive question that feels revolutionary and passionate.</p>
<p>Let me go over one of the lines that I think exemplifies this:</p>
<blockquote><p>
"I consider that the golden rule requires that if I like a program I must share it with other people who like it."</p></blockquote>
<p>It wasn’t saying: what are we not allowed to do, nor did it talk about some kind of societal injustice.  It didn’t talk about the meaning of actions or their long-term effects.  Instead it asked: what must we do, not as a society, not in service of some end, but what are we called upon to do as an <em>individual</em>, <em>right now</em>, in service of the people we call friends.  It didn’t allude to any sociological explanation, natural selection, economics; there is just the golden rule, the most basic tenant of moral thought.</p>
</div>
<div class="section" id="free-software-vs-open-source">
<h2>Free Software vs. Open Source</h2>
<p>When I first encountered free software, I suppose about 15 years ago, this was during one of the more difficult periods of its evolution.  It was past the initial excitement, the initial optimism that the project would take only a couple years to reach parity with closed-source Unix, it was before it was clear how the project would move forward.  Linux was young and seemed to be largely off the radar of Richard Stallman and other GNU advocates, and they were struggling to fill in final key pieces, things like a kernel, widgets, and they hadn’t even thought about entirely new things like browsers.</p>
<p>The message that came through from that period is not the message I wish came through.  The message I wish came through was that message from the GNU Manifesto, that spirit of a new sense of duty and ability.  When people talk about Richard Stallman and the Free Software Foundation and the GNU Project, they’ll often point to the GNU General Public License as the most important contribution — the GPL.  I’m sure you all know something about it.  Of course the core concept there is the idea of copyleft.  Not only will the software be open, but it’s takes the implied perspective that the principles of freedom are rights — that unfortunately the world is not wise enough to see that use, distribution, and modification are rights; but the GPL still asserts that these <em>are</em> your rights.  When you become one of us, when you participate in the freedoms this license grants you, when you use the GPL, there is encoded in the license a support for this sense of the natural right of free software.  We, GNU, can’t encode that for the world, but for the software that we write these rights are inalienable.</p>
<p>But as I said those were difficult times.  There was a great deal of pressure.  People were trying to understand what open source meant. People still struggle with questions: how would an economy function, how would a programmer get a job, if this is as successful as people hoped will we all just be out of jobs?  Other questions were: who will write the software that no one wants to write?  How can I, embedded in a situation where I can’t actually use only free software — remember at this time there was no way to use completely free software — how can I assert a duty to do something that is not possible?  How can I be useful unless I interface with all these proprietary things?  If I deal with companies which aren’t comfortable with open source software, then what?  After all, open source seemed only barely plausible at this time.  It was not an easy argument to make.</p>
<p>And all this was before the term "open source" really took hold as a distinct idea.  That itself is an interesting story.  There was a time during this marketing period when there arose a kind of terminology divide — free software vs. open source software.  The terminology divide was that the "free" in free software implied you couldn’t charge anything, that made people think about price, might even imply cheapness.  Open source directly refers to programming, uses the feel-good term "open", and doesn’t sound too revolutionary.  But besides that there was also a substantial philosophical difference about the value of the software itself.</p>
<p>So there was a difference in how things were going to be pitched, but also a difference in what people thought the general value of this project was.  From GNU and Richard Stallman there was the notion that this was right because it was right; it was a moral imperative.  The virtue of what we build is in its freedom; if it is also technically superior then that’s great, but it is not how we should judge our success.  We were giving people self-determination: programmer self-determination, user self-determination… on the open source side the argument was that this is a good way to create software.  Programmers working together can do better work.  With many eyes all bugs are shallow.  All working together, we’ll work faster, you get the benefit of free contributions from all sorts of people.  People were clamouring to get all these proprietary companies with failing software products to open source their software; miracles will occur!  What you thought was useless will regain value!  You’ll reattain relevance!</p>
<p>The open source and free software philosophical divide: on one side practical concerns, on the other moral.  And this is what I want to talk about later: can we find a moral argument for these practical concerns?</p>
<p>The basic free/open disagreement continues in debates over licenses: the GPL vs. the BSD and other permissive licenses.  If you read the <a class="reference external" href="http://www.gnu.org/copyleft/gpl.html">GPL</a> it talks a great deal about philosophy; if you read the <a class="reference external" href="http://www.opensource.org/licenses/bsd-license.html">BSD license</a> it’s really just some disclaimers and basic instructions, and the one line: "Redistribution and use in source and binary forms, with or without modification, are permitted."  It doesn’t say why you’ve received this software, or any philosophy about rights and freedoms, or even encourage you to use the same license on your own software.  An engineer’s license.</p>
<p>So these two licenses in many ways became a focus and definition of free and open source software.  If you look at the <a class="reference external" href="http://www.opensource.org/">Open Source Initiative</a>, which has served to define what "open source" means, it is basically just a <a class="reference external" href="http://www.opensource.org/licenses/alphabetical">list of approved licenses</a>.  If you use one of those licenses, the software is open source, if not then it is closed.</p>
<p>I think this is disappointing, because licenses are just law, and law is not very interesting.  A law tells you what you shouldn’t do, it doesn’t tell you what you should do.  When both sides are talking about freedom, the licenses just define freedom as the lack of certain restrictions.  Take away those restrictions and voila, you are free… as though we are all just bundles of freedom waiting to be released.</p>
</div>
<div class="section" id="self-definitions">
<h2>Self-Definitions</h2>
<p>With licenses we have a negative definition of our community.  Either license you choose, the license feels like a reaction against closed source software.  If you can imagine a world in which there was no copyright, where our platforms were all setup to distribute source code in modifiable forms, where everything was open and everything was free, then none of these licenses would matter.  No one would be compelled to create the GPL in such a world; we wouldn’t advocate for copyright just so we can secure people’s freedoms.  In that kind of world all this licensing disappears.  And this isn’t even so weird a world.  You can pretend there’s no copyright now.  Maybe you have to reverse-engineer some stuff.  There’s lots of places in the world where no one really gives a damn about copyright.  But those places don’t feel open source to me, they don’t feel that more free.  We aren’t made unfree just by legal restrictions; freedom is something we have to actively grasp.</p>
<p>I don’t think what we do is predicated on copyright.  Indeed, many projects are comfortable with an entirely confused copyright ownership.  This causes very few problems.  A focus on licensing makes us into a reaction against proprietary software, where we allow proprietary software and its makers to define what it means to be <em>us</em>.</p>
<p>This concerns me because it isn’t just about formal definitions and terminology.  When I say <em>what do I do</em>, I say I am an open source programmer.  That’s not just an attribute, like saying that my hair is brown.  Open source is a way in which I see myself, a way I think about my craft, my profession, and a way I justify the work I put out to the world: that it aligns with these values.  So it’s very important to me what these values are.  And it’s frustrating to see open source defined in reaction to closed source software, because personally I don’t care about closed source software that much.</p>
<p>I never really cared much about fighting Microsoft, and I certainly don’t care now.  I see myself as a builder; this is what always drew me towards programming.  The desire to build new things.  This is our privilege as programmers, that we always have the opportunity to build new things.  If we’re asked to do something again and again and again, you always have the power to do it in a more abstract way, to generalize it away, until you can start to ignore the requests and move on to another problem.  This is something unique thing to computer programming.  These are the kind of unique attributes that make us different as a profession and as a craft than just about anything I can think of.</p>
<p>So I’m frustrated.  Here we are stuck in this notion of a license as a self-definition.  I want to find a new self-definition, a new idea of what makes us us.</p>
</div>
<div class="section" id="what-makes-us-us">
<h2>What Makes Us Us</h2>
<p>So… what makes us us?</p>
<p>I was saying about Django, the community is not particularly enthusiastic about philosophy.  Or maybe I should say, Django’s philosophy is: the value of the code is the thing you do with it.  These abstract discussions about architecture, reuse, big plans… instead, Django as a community encourages you to keep your head in the code, think about what you want to do, and then do it.  Don’t shave yaks.</p>
<p>But I’m not here to tell you to get philosophical about freedom, or to berate you for a functional definition of value.  I’d like to look at this community for what it is, and ask: what is the value system here?  Maybe it isn’t described, but I also don’t think it is therefore absent.</p>
<p>So… when I say I identify as an open source programmer, what is it that I am identifying as?</p>
<p>I don’t believe licensing makes something truly open source.  There was this clamour in the past to get companies to open source their products.  This has stopped, because all the software that got open source sucked.  It’s just not very interesting to have a closed source program get open sourced.  It doesn’t help anyone, because the way closed source software is created in a very different way than open source software.  The result is a software base that just does not engage people in a way to make it a valid piece of software for further development.  At least not unless you have something peculiar going on… an economic force like you had behind Mozilla that could push things forward even in the midst of all the problems that project had.  One might even ask, is Mozilla still suffering from that proprietary background, when something like KHTML or WebKit which came from a truly open source background, and has been a more successful basis for collaboration and new work.</p>
<p>So whatever it is that makes something open source, it’s not just licensing.  Given a codebase, we can’t necessarily expect that someone going to care about it and love it and make it successful.  A lot of people have described what makes a successful open source codebase; I’d like to talk some about what the communities look like.</p>
<hr class="docutils"/>
<p>Open source works as a fairly loose federation of people together.  Everyone involved is involved as an individual.  Companies seldom participate directly in open source.  Companies might use open source, they might sponsor people to work on open source projects, they might ask an employee to act as a liason.  But it’s not cool to submit a bug as a company.  You submit it as yourself.  If someone asks a question, you answer as yourself.  You don’t join a mailing list under the company’s name.  And even when you put a company name on a product, it’s hard to relate to the product as a <em>project</em> without some sense of authorship, of the underlying individual.</p>
<hr class="docutils"/>
<p>There’s also very little money being moved about.  There’s not a lot of commercial contracts.  You might get software, you might get bug fixes, you might get reputation, but there’s seldom any formal way setup to introduce commerce into the community.  How many projects let you pay to escalate a bug?  Even if everyone involved might like that, it’s just not there.</p>
<hr class="docutils"/>
<p>But I want to get back to individuals.  How things are created is not that someone determines a set of priorities, lays them out, then people work on implementation based on those priorities.  That of course is how things typically work at a company, as an employee.  But open source software and open source projects are created because an individual looks at the world and sees an opportunity to create something they think should exist.  Maybe it resolves a tension they’ve felt in their work, maybe it allows that person to respond to the priorities from above better, but the decision to implement lies primarily with the implementor.  When someone makes a decision to move a product from simply private code — regardless of the license — to being a real open source project, that decision is almost always driven by the programmer.</p>
<hr class="docutils"/>
<p>Underneath most open source work there is a passion for the craft itself.  This is what leads to a certain kind of quality that is not the norm in closed source software.  It’s not necessarily less bugs or more features, but a pride in the expression itself.  A sense of aesthetic that applies to even the individual lines of software, not just to the functionality produced.  This kind of aesthetic defies scheduling and relies on personal motivation.</p>
<p>As open source programmers we are not first concerned with how a task fits into institutions, how a task can be directed by a hierarchy or an authority, or even how the task can be directed by economics.  The tasks that we take on are motivated by aesthetic, by personal excitement and drive.</p>
<hr class="docutils"/>
<p>We are also in a profession where there is little stasis.  If you can create something once, you can create it a thousand times, through iteration or abstraction.  You can constantly make your own effort obsolete.  A good programmer is always trying to work themselves out of a job.</p>
<p>Djangocon didn’t exist a couple years ago.  Django didn’t exist only a few years ago.  And I don’t think there’s anyone here who thinks that, having found Django, they’ve reached some terminal point.  It’s hardly even a point to pause.  There’s a constant churn, a constant push forward that we’re all participating in.</p>
<p>As a result it’s demanded of us that we have a tight feedback cycle, that education is not a formal affair but a constant process in our own work.  There’s a constant churn, and a professional sense we’re kind of like fruit flies.  A generation of knowledge and practice is short enough that the evolution is rapid and visible.  You don’t have to be particularly old or even thoughtful to see the changes.  You can look back even on your own work and on communities to see changes over the course of a couple years, to see changes and shifts and a maturing of the work and the community.</p>
<hr class="docutils"/>
<p>Another attribute of open source: our communities are ad hoc and temporary.  We do not overvalue these communities and institutions; we regularly migrate, split, recombine, and we constantly rewrite.  There is both an arrogance and a humility to this.  We are arrogant to think This Time Will Be Different.  But we are humble enough to know that last time wasn’t different either.  There will always be a next thing, another technique, another vision.</p>
<p>Because of the ad hoc nature of the communities, we don’t have long collective plans.  The ad hoc community may be the intersection of different <em>personal</em> long range plans, a time when different visions somehow coincide in a similar implementation.  Or perhaps it’s just serendipity, or leadership.  But we make each decision anew.  I believe this protects us from being misled by sunk costs.  The idea of a sunk cost is that when you make an investment, you’ve put in effort, that effort is gone.  Just because you’ve put in effort doesn’t mean you’ve received value, or that the path of investment remains valid.  But as humans we are highly reluctant to let go of a plan that we’ve invested in.  We have a hard time recognizing sunk costs.</p>
<p>I believe in our developer community we approach our work with sufficient humility that we can see our work as simply a sunk cost.  Our effort does not entitle us to any particular success, so we can choose new directions with more rationality than an institution.  Though it can also be argued that we are too quick to dismiss past investments; there is a youthfulness even to our oldest members.</p>
<hr class="docutils"/>
<p>We do not have hierachies with decision makers above implementors.  Some people have veto power (a BDFL), but no one has <em>executive</em> power.  A decision only is valid paired with an implementation.  You cannot decide something based on information you <em>wish</em> was true; you cannot decide on something then blame the implementors for getting it wrong.  We are in this sense vertically integrated, decision and implementation are combined.  The result may be success or failure, commitment or abandonment, but the hierarchy is flat and the feedback loop is very tight.  And if an individual feels stymied, there is always another community to join or create.</p>
<p>Though this is only a start, it’s these attributes that I would prefer define us, not licenses.</p>
<p>I also would like that this could be a model for how other work should be done.</p>
</div>
<div class="section" id="why-us">
<h2>Why Us?</h2>
<p>Why would we, as programmers, be unique or worthy of emulation?  I mentioned before that we constantly work ourselves out of our job.  We also create the tools we use to do the work.  We define the structure of our communities.  We’re consistently finding novel ways to use the internet build those communities.  It’s not that we as a group are somehow uniquely wise, or some Greatest Generation, but we have become distinctly self-empowered.  There is a uniqueness to us.  It might be a coincidence of history, but it is there.</p>
<p>A question I might then ask: is there a political meaning to this?  This is the form our craft takes, but does that mean anything?  We work with computers, someone else might work with their hands, an artist considers color, a salesperson learns how to put on a good smile.</p>
<p>I haven’t quite figured this out yet, but I think there’s something in this.  Over the years I’ve found myself looking at politics in a increasingly technocratic lens; more so than as a liberal, conservative, or radical.  That is, instead of looking at the world and seeing what’s wrong about it, and explaining it in terms of a class struggle, a cultural conflict, in terms of advocacy or invented enemies or allies, I see a system that just works how it works.  It’s more like gears than like a war.  The gears turn and sometimes we don’t like what results, but it’s not malice.</p>
<p>But I also don’t think we are slaves to the technical functioning of the system.  None of us are inevitably caught up in some statistical outcome of markets, or condemned by money in politics or advertising.  At any time we can say Here Is What I Believe, and it is as powerful as any of those other things; we’re too quick to look at the people who aren’t asserting a belief, who aren’t asserting their own potential for self-empowerment and direction, and we ignore everyone who is aware and concerned and attempting self-determination.  We are at danger of ignoring the great potential around us.</p>
<p>It is in this sense that I wonder not just how we can spread the idea of freedom through licensing, which has inspired the free culture movement, but also how we can spread this idea and practice of individual action, of combining decision and implementation, and of constant ad hoc collaboration.</p>
<p>I’m not just thinking of politics directly, but of professional lives as well.  Right now we’re talking about healthcare.  It’s a very political issue, and yet healthcare is ultimately a profession, a job, an action.  How we work on that, collaboratively or not, is as political as any aspect of the system.</p>
<p>One anecdote that made me think about this, is a task I had that involved putting authentication in front of a mailing list.  The mailing list happened to be for wound, ostomy, and continence nurses, and in the process of the job I read a bunch of their emails from the archives.  As wound nurses they spent a lot of time asking about specific questions — maybe a wound that wouldn’t heal, they kept draining the puss and it discharge kept reappearing, and did anyone have ideas of the next technique to try?</p>
<p>Reading a few of these I could tell this was a profession where you needed a strong stomach.  But the whole interaction, the way they described problems, the way people came back with answers, it felt very familiar to me.  It was the same kind of discussions I could imagine having about Linux administration or debugging.  And the goals were similar.  No one was making money, there wasn’t really reputation on the line, it was just people who wanted to help their patients and who wanted to help each other.</p>
<p>So that mailing list was great, but it’s unfortunately not that common.  And if nurses were open to that kind of collaboration, doctors don’t seem nearly as ready.  And there’s a lot of professions where there’s not even that thoughtfulness.  I believe in any profession there’s the ability to do it well or not; there’s nothing so rote or well understood that there’s no room for improvement.  It doesn’t have to be fancy technology, it can just be a technique, a way of managing work; all things worth doing have some way of improving, by bringing in this same sense of collaboration and individual action and thoughtfulness, all things can be implemented better than they are now.  What I’m describing isn’t a fancy new website for professionals, but about people look at their own work differently; the technology is not the hard part.</p>
</div>
<div class="section" id="the-political">
<h2>The Political</h2>
<p>Changing how people look at their work I think is political.  It involves individual empowerment.  It can mean economic change.  I also think it deemphasizes competition.  When I think about Pylons, or Django, or TurboGears, or WSGI, there’s competition, but it’s also collegial.  There’s not really that much of a sense of survival.  We aren’t carving out territories, we’re just finding paths to some unknown end.  If something else wins out, well, we’re all just along for the ride.  In the end it is inevitable that something else other than what <em>any</em> of us are working on will win out over what any of us are doing.  Just like everyone eventually loses their job at least to death or retirement.  There’s no permanency.  But if we can be individually more productive, it doesn’t have to mean we’ve put someone else out.  It <em>could</em> mean we all, all of society, all of humanity, just do <em>more</em>.  Why do we have to set ourselves against the Chinese, or Europe against the U.S.?  Why do we have to set ourselves one economy against another?</p>
<p>Or consider government itself: we’re obsessed with our elected officials, but of course government is far larger than just the elected officials.  The U.S. Federal Government alone has 1.8 million employees.  We constantly threaten to institute accountability, meaning that we’ll poke and prod government workers from the outside and expect better outcomes.  That we expect anything to come of this is absurd, but somehow accountability has become an easy alternative to constructive suggestions for improvement.</p>
<p>But why shouldn’t we expect that government workers <em>want</em> to do better?  I believe in fact those people doing the work are especially well equiped to figure out <em>how</em> to do better.  But it’s not automatic.  They aren’t empowered in a system that is so exceptionally hierarchical.  Lately we’ve seen lots of efforts to ask the public how to do government work better, but we’ve seen nothing asking <em>government</em> how to do government work better.</p>
<p>These are the kinds of things I’d like to see us all think about more: open source has done incredible things, has inspired new ideas, about more than just software and engineering, but I think we have yet more things to give.</p>
<p>Thank you for your time.</p>
</div>
</div></div>
    </content>
    <updated>2009-09-11T00:09:11Z</updated>
    <published>2009-09-11T00:09:11Z</published>
    <category scheme="http://blog.ianbicking.org" term="Licensing"/>
    <category scheme="http://blog.ianbicking.org" term="Politics"/>
    <category scheme="http://blog.ianbicking.org" term="Programming"/>
    <author>
      <name>Ian Bicking</name>
      <uri>http://blog.ianbicking.org</uri>
    </author>
    <source>
      <id>http://blog.ianbicking.org/feed/atom/</id>
      <link href="http://blog.ianbicking.org" rel="alternate" type="text/html"/>
      <link href="http://blog.ianbicking.org/feed/atom/" rel="self" type="application/atom+xml"/>
      <title xml:lang="en">Ian Bicking: a blog</title>
      <updated>2010-03-06T00:32:29Z</updated>
    </source>
  </entry>

  <entry xml:lang="en">
    <id>http://blog.repoze.org/2009/09/09/newbfgsite-20090909</id>
    <link href="http://blog.repoze.org/newbfgsite-20090909.html" rel="alternate" type="text/html"/>
    <title xml:lang="en">New bfg.repoze.org Website</title>
    <content type="xhtml" xml:lang="en"><div xmlns="http://www.w3.org/1999/xhtml"><p> Thanks to <a href="http://www.electrosoup.co.uk/">ElectroSoup</a>,
the <a href="http://bfg.repoze.org">BFG website</a> has a new design.
The design is excellent; ElectroSoup does fantastic work should you
need some design help.
</p></div>
    </content>
    <updated>2009-09-09T19:52:23Z</updated>
    <published>2009-09-09T19:52:23Z</published>
    <source>
      <id>http://blog.repoze.org/index.atom</id>
      <author>
        <name>The Repoze Team</name>
        <email>repoze-dev@lists.repoze.org</email>
        <uri>http://blog.repoze.org/index.atom</uri>
      </author>
      <link href="http://blog.repoze.org" rel="alternate" type="text/html"/>
      <link href="http://blog.repoze.org/index.atom" rel="self" type="application/atom+xml"/>
      <rights xml:lang="en">Copyright 2007 Agendaless Consulting, Inc.</rights>
      <subtitle xml:lang="en">Notes on the Repoze platform</subtitle>
      <title xml:lang="en">Repoze Notes</title>
      <updated>2009-09-09T19:52:23Z</updated>
    </source>
  </entry>

  <entry>
    <id>http://plope.com/Members/chrism/compiling_24_snowleopard</id>
    <link href="http://plope.com/Members/chrism/compiling_24_snowleopard" rel="alternate" type="text/html"/>
    <title>Compiling Python 2.4 on A 32-Bit Mac with Snow Leopard</title>
    <summary>Python 2.4 on a 32-bit Mac using Snow Leopard without a buildout.</summary>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>Florian Schulze has created a <a href="http://svn.plone.org/svn/collective/buildout/python/">buildout</a> that compiles Python 2.4, 2.5, and 2.6 on Snow Leopard.  By habit, I generally compile my Python interpreters "by hand" so I have a clue what's going on.  I really just looked at Florian's buildout to see what it did and did that by hand.</p>
<p>Here's what I had to do to get Python 2.4 compiled on a fresh Snow Leopard install (not an upgrade) on a <em>32-bit Mac Book Pro</em> (a Core Duo, not a Core 2 Duo; those have other issues).:</p>

<ul>
<li>Install <a href="http://www.finkproject.org/">Fink</a></li>
<li>Install the readline5-dev library using "fink install" (for readline support in Python).  If you don't compile against a "real" readline, Python will probably compile 
   but it will probably buserror in an interactive shell or you'll not have any readline support in the interactive shell.</li>
<li>Download <a href="http://www.python.org/ftp/python/2.4.6/Python-2.4.6.tgz">Python 2.4.6</a></li>
<li>Apply Florian's <a href="http://svn.plone.org/svn/collective/buildout/python/src/python-2.4-darwin-10.6.patch">patch</a> to the unpacked source of
   the Python 2.4.6 tarball.  Note that things mostly sorta work without this patch, but (in particular) <a href="http://supervisord.org">supervisor</a> won't
   run without this patch (can't import the "resource" module and other POSIX-related things).</li>
<li>Use the following command to configure Python 2.4:
<pre>    CC="gcc -I/sw/include -L/sw/lib" ./configure MACOSX_DEPLOYMENT_TARGET=10.6 --disable-tk --prefix=$HOME/opt/Python-2.4.6
</pre>
</li>
<li>Use the following command to install Python 2.4:
<pre>    CC="gcc -I/sw/include -L/sw/lib" MACOSX_DEPLOYMENT_TARGET=10.6 make install
</pre>
</li>

</ul></div>
    </content>
    <updated>2009-09-05T17:15:27Z</updated>
    <category term="python"/>
    <category term="tech"/>
    <category term="zope"/>
    <author>
      <name>chrism</name>
    </author>
    <source>
      <id>http://plope.com</id>
      <link href="http://plope.com/python.rss" rel="self" type="application/atom+xml"/>
      <link href="http://plope.com" rel="alternate" type="text/html"/>
      <subtitle>Chris McDonough's Python Feed</subtitle>
      <title>Chris McDonough's Python Feed</title>
      <updated>2010-01-01T16:35:07Z</updated>
    </source>
  </entry>

  <entry>
    <id>http://plope.com/Members/chrism/2009dcsprint</id>
    <link href="http://plope.com/Members/chrism/2009dcsprint" rel="alternate" type="text/html"/>
    <title>2009 DC CMS Sprint</title>
    <summary>Sprint report for the "CMS DC" sprint in Arlington VA.</summary>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>From August 21 - August 24 in Arlington Virginia, 12 people collected
for a sprint, nomimally on the topic of creating a new "CMS" (content
management system).</p>
<p>Chris Shenton was nice enough to lend his home office for the
occasion.  In attendance were Chris Shenton, Reed O'Brien, Tres
Seaver, Chris McDonough, Malthe Borch, Carlos de la Guardia, Hanno
Schlichting, Robert Marianski, Nathaniel Wingfield, Kapil
Thangavelu, and Alex Clark.</p>
<p>On the first day, Friday, we had a long discussion about the
components that might make up a not-very-simple CMS.  We decided that
the most important top-level components were:</p>

<ul>
<li>A "content repository"</li>
<li>A workflow system</li>
<li>An indexing system</li>
<li>Observability (events)</li>

</ul>
<p>We spent a good long while talking about the plus's and minuses of
various content repository implementations.  We defined a content
repository as "the place where content goes", separate from any retail
application which uses it.  We finally decided that to get everyone's
buyin that content repositories would be effectively "stupid", managed
by a top-level "content manager" node that would handle indexing.</p>
<p>Lots of whiteboarding happened on this day.</p>
<p>On the second day, Malthe and Robert worked on a blog application that
used "repoze.filecat" as a backend.  Carlos and Chris M. and several
other folks helped create a ZODB implementation of a content
repository and manager system that had the (very temporary) name of
"plite".  </p>
<p>On the third day of the sprint, Malthe and Robert had finished their
blog application, which used files on the filesytem to represent
assets.  Chris and Carlos and others had made a content system using
plite that was able to add files and page objects.</p>
<p>Things sort of trailed off at this point, as we weren't really able to
create an application that used the concepts we had come up with.  Any
application we could create in the time allotted seemed too simple to
effectively use a content repository.  So we sort of worked on
infrastructure and drank beer (a keg had been strategically placed for
the occasion).  Malthe added a "static" directive to repoze.bfg.</p>
<p>Things we did well:</p>

<ul>
<li>Discuss and agree on components.</li>
<li>Had fun.</li>

</ul>
<p>Things we didn't do so well:</p>

<ul>
<li>Concentrate on coming up with any demonstration of the technology
  components we had dreamed up.</li>

</ul>
<p>In future sprints, I suspect I'd like someone to come armed with an
implementation of some of the components we dreamed up, with some idea
about how to wire them up into a sample app that would be useful to
lots of folks.  We sort of bit off more than we could effectively chew
by not having a more focused task at hand.  But we had fun all the
same.  This is truly a huge task, so I wasn't particularly surprised
(or even disappointed) that we didn't walk away with any truly
useful software.</p>
<p>Many thanks to all who participated!  Many thanks also to Chris'
significant other, Irene, who put up with geeks in her basement and
even fed us.</p>
<p>Pictures of the event are <a href="http://static.repoze.org/2009sprint/">here</a> .</p></div>
    </content>
    <updated>2009-08-30T18:45:51Z</updated>
    <category term="python"/>
    <category term="tech"/>
    <category term="zope"/>
    <author>
      <name>chrism</name>
    </author>
    <source>
      <id>http://plope.com</id>
      <link href="http://plope.com/python.rss" rel="self" type="application/atom+xml"/>
      <link href="http://plope.com" rel="alternate" type="text/html"/>
      <subtitle>Chris McDonough's Python Feed</subtitle>
      <title>Chris McDonough's Python Feed</title>
      <updated>2009-12-31T15:09:10Z</updated>
    </source>
  </entry>

  <entry>
    <id>tag:blogger.com,1999:blog-4258103213764887486.post-5889480383255330781</id>
    <link href="http://www.blogger.com/feeds/4258103213764887486/posts/default/5889480383255330781" rel="edit" type="application/atom+xml"/>
    <link href="http://www.blogger.com/feeds/4258103213764887486/posts/default/5889480383255330781" rel="self" type="application/atom+xml"/>
    <link href="http://artificialcode.blogspot.com/2009/08/10-ways-to-let-people-know-your-bad.html" rel="alternate" type="text/html"/>
    <title>10 Ways To Let People Know You're A Bad Python Programmer</title>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><span style="font-weight: bold;">1. Write "God" functions</span><br/><br/>These functions often stretch well over several hundred lines of code, and often have some form of action in the title, like "doMyStuff", or "doComplicatedSequence".  Also, make sure you name the God functions or methods in camel case, so it is very clear you never bothered to read the <a href="http://www.python.org/dev/peps/pep-0008/">Python Style Guide:  PEP 8</a>.  <br/><br/>Extra Credit:<br/><br/>*  Add huge blocks of commented code and mix them in the middle.<br/>*  Add comments in the doc string or anywhere, that say, this is "magic", or "bad" and needs to be rewritten.<br/><br/><span style="font-weight: bold;">2.  Never return anything in a function, especially not some type of value that could demonstrate your function succeeded or failed.</span><br/><br/>This makes your code almost impossible to test and makes it clear you think programming is "magic".  After all, who cares if a function does what you wanted?<br/><br/><span style="font-weight: bold;">3.  Never write a test...EVER.  </span><br/><br/>Claim testing is impossible where you work because it is different.  Make up excuses like, "I am used to other people testing my code" (This one sounds especially good if your a former .NET developer.)  If you really want to go all the way, don't even bother looking up <a href="http://docs.python.org/library/unittest.html">how to write a unit test</a>.  Convince yourself it is impossibly complicated and not worthwhile and that people won't notice.<br/><br/><span style="font-weight: bold;">4.  Call Perl from Python</span><br/><br/>This is an oldie but a goodie, but a lot of bad programmers don't realize they can make their Python code even worse, if they embed a bunch of untested, legacy, Perl code in it.  There is a <a href="http://search.cpan.org/~gaas/pyperl-1.0/perlmodule.pod">Perl/Python module</a> that makes this a snap.  <br/><br/>Extra Credit:<br/><br/>*  Call a nest of Perl regular expressions from Python instead of doing a doing something like:<br/><pre><br/><code><br/>if "string" in variable:<br/></code></pre><br/><br/>* Brag that you called Perl from Python because it was "quicker" to experienced Python programmers.<br/><br/><span style="font-weight: bold;">5.  Screw Control Flow</span><br/><br/>If you can write a few statements, then mix in some functions, then maybe define a class, then write more statements, you have "screwed" Control Flow successfully.  Something like below is a good starting point:<br/><br/><br/><pre><br/><code><br/>#!/usr/bin/env python<br/>print "My Script is running"<br/>import os<br/>if os.path.exists("/tmp"):<br/>    def myfunc():<br/>        x = 4<br/>        return x<br/>class Foo(object):<br/>    y = 1<br/><br/>f = Foo()<br/>print f.y + myfunc()<br/></code></pre><br/><br/><br/><br/><br/><span style="font-weight: bold;">6.  Abuse conditional logic to the point that you double or even triple an "unmaintainable" Cyclomatic Complexity Score of 50.<br/></span><br/>Nothing says I suck at Python better, then writing nested if/else statements from here to the moon.  How you can tell you sucked enough?  Easy, just run the cyclomatic complexity metric from <a href="http://sourceforge.net/projects/pymetrics/">PyMetrics</a>, and if your function or method doesn't yet rate a 50, which is basically unmaintainable/untestable code, then keep trying!  If you can double or even triple that to say 100 or 150, you will put the capital "S" in Suck!<br/><br/><br/><span style="font-weight: bold;">7.  Use sleep statements like Holy Water.</span><br/><br/>If you write something sketchy and want some extra "luck", then sprinkle in a few time.sleep statements. If you use them randomly and arbitrarily it will get the point across in short order, that you don't know what the hell that piece of code does and you're just guessing!  Awesome!<br/><br/><span style="font-weight: bold;">8.  Initiate the same logic more then once, "just to be sure".</span><br/><br/>Often when you're writing some really crappy code, you're lucky if you know what it is doing.  If you can write a function that does something that makes you feel emotionally safe and then call it for luck a few times...bingo...you win!<br/>Something like this is always a gold standard:<br/><br/><pre><br/><code><br/>count = 0<br/>for i in range(5):<br/>    if os.path.exists("/tmp"):<br/>        print "bingo"<br/><br/>def foo():<br/>    print "stuff"<br/><br/>if os.path.exists("/tmp"):<br/>    import sys<br/>    sys.exit(1)<br/><br/><br/></code></pre><br/><br/><br/><span style="font-weight: bold;">9.  Write Library Code that does a sys.exit(0) on an exception.<br/></span><br/>If you can write an API that catches all exceptions and then does a silent sys.exit(0), you will really piss someone off that uses you're code and demonstrate you're a hack.<br/><br/>Something like this is a good start:<br/><br/><pre><br/><code><br/><br/>def api_entry_point():<br/>    try:<br/>        obj.method()<br/>    except:<br/>       #lets not bother the developer with this exception.  He should quit out immediately!<br/>       import sys<br/>       sys.exit(0)<br/></code></pre><br/><br/><br/><span style="font-weight: bold;">10.  Reimplement the Python Standard Library in every piece of code you write.<br/></span><br/>Show you really don't give a rat's ass about learning the language.  Reimplement arg parsing,<br/>config parsing, the subprocess module and more. <br/><br/><span style="font-weight: bold;">Summary</span><br/><br/>If you can do just a couple of these things in every piece of code you write, you are well on your way to writing bad python code!  Stay tuned for part II.<div class="blogger-post-footer"><img alt="" height="1" src="https://blogger.googleusercontent.com/tracker/4258103213764887486-5889480383255330781?l=artificialcode.blogspot.com" width="1"/></div></div>
    </content>
    <updated>2009-08-26T16:20:07Z</updated>
    <published>2009-08-26T04:37:00Z</published>
    <category scheme="http://www.blogger.com/atom/ns#" term="bad"/>
    <category scheme="http://www.blogger.com/atom/ns#" term="python"/>
    <category scheme="http://www.blogger.com/atom/ns#" term="how-to"/>
    <author>
      <name>Noah Gift</name>
      <email>noreply@blogger.com</email>
      <uri>http://www.blogger.com/profile/13144332122855013229</uri>
    </author>
    <source>
      <id>tag:blogger.com,1999:blog-4258103213764887486</id>
      <author>
        <name>Noah Gift</name>
        <email>noreply@blogger.com</email>
        <uri>http://www.blogger.com/profile/13144332122855013229</uri>
      </author>
      <link href="http://artificialcode.blogspot.com/feeds/posts/default" rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml"/>
      <link href="http://www.blogger.com/feeds/4258103213764887486/posts/default" rel="self" type="application/atom+xml"/>
      <link href="http://artificialcode.blogspot.com/" rel="alternate" type="text/html"/>
      <link href="http://pubsubhubbub.appspot.com/" rel="hub" type="text/html"/>
      <link href="http://www.blogger.com/feeds/4258103213764887486/posts/default?start-index=26&amp;max-results=25" rel="next" type="application/atom+xml"/>
      <subtitle>This is Noah Gift's Coding Blog.  I only talk about coding and technical stuff here, and that is mostly Python, although I will mix in some other languages, and talk about Artificial Intelligence.</subtitle>
      <title>Artificial Code</title>
      <updated>2010-02-07T21:38:32Z</updated>
    </source>
  </entry>

  <entry>
    <id>tag:blogger.com,1999:blog-4258103213764887486.post-5317906843721693397</id>
    <link href="http://www.blogger.com/feeds/4258103213764887486/posts/default/5317906843721693397" rel="edit" type="application/atom+xml"/>
    <link href="http://www.blogger.com/feeds/4258103213764887486/posts/default/5317906843721693397" rel="self" type="application/atom+xml"/>
    <link href="http://artificialcode.blogspot.com/2009/08/adapt-is-now-using-bobo.html" rel="alternate" type="text/html"/>
    <title>Adapt Is Now Using Bobo</title>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml">The <a href="http://bitbucket.org/noahgift/adapt/src/tip/v2/">trunk version</a> of <a href="http://pypi.python.org/pypi/Adapt/0.1">Adapt</a>, a commandline tool/logic router to WSGI web app framework I am developing is now using <a href="http://bobo.digicool.com/">Bobo</a> for the abstraction piece on top of <a href="http://pythonpaste.org/webob/">WebOb</a>.<br/><br/>If you haven't checked out Bobo or WebOb and you develop Python web apps, your missing out.  Wow, great stuff Jim and Ian!<div class="blogger-post-footer"><img alt="" height="1" src="https://blogger.googleusercontent.com/tracker/4258103213764887486-5317906843721693397?l=artificialcode.blogspot.com" width="1"/></div></div>
    </content>
    <updated>2009-08-20T06:51:44Z</updated>
    <published>2009-08-20T06:45:00Z</published>
    <category scheme="http://www.blogger.com/atom/ns#" term="WSGI"/>
    <category scheme="http://www.blogger.com/atom/ns#" term="adapt"/>
    <category scheme="http://www.blogger.com/atom/ns#" term="Bobo"/>
    <category scheme="http://www.blogger.com/atom/ns#" term="WebOb"/>
    <author>
      <name>Noah Gift</name>
      <email>noreply@blogger.com</email>
      <uri>http://www.blogger.com/profile/13144332122855013229</uri>
    </author>
    <source>
      <id>tag:blogger.com,1999:blog-4258103213764887486</id>
      <author>
        <name>Noah Gift</name>
        <email>noreply@blogger.com</email>
        <uri>http://www.blogger.com/profile/13144332122855013229</uri>
      </author>
      <link href="http://artificialcode.blogspot.com/feeds/posts/default" rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml"/>
      <link href="http://www.blogger.com/feeds/4258103213764887486/posts/default" rel="self" type="application/atom+xml"/>
      <link href="http://artificialcode.blogspot.com/" rel="alternate" type="text/html"/>
      <link href="http://pubsubhubbub.appspot.com/" rel="hub" type="text/html"/>
      <link href="http://www.blogger.com/feeds/4258103213764887486/posts/default?start-index=26&amp;max-results=25" rel="next" type="application/atom+xml"/>
      <subtitle>This is Noah Gift's Coding Blog.  I only talk about coding and technical stuff here, and that is mostly Python, although I will mix in some other languages, and talk about Artificial Intelligence.</subtitle>
      <title>Artificial Code</title>
      <updated>2010-02-07T21:38:32Z</updated>
    </source>
  </entry>

  <entry>
    <id>http://www.palladion.com/home/tseaver/obzervationz/2009/unit_testing_redux-20090802</id>
    <link href="http://www.palladion.com/home/tseaver/obzervationz/2009/unit_testing_redux-20090802" rel="alternate" type="text/html"/>
    <title>Unit Testing Redux</title>
    <summary>Following up to an earlier post on effective unit testing:  most people are trying too hard.</summary>
    <updated>2009-08-02T20:48:01Z</updated>
    <author>
      <name>tseaver</name>
    </author>
    <source>
      <id>http://www.palladion.com/blog</id>
      <link href="http://www.palladion.com/blog" rel="alternate" type="text/html"/>
      <link href="http://www.palladion.com/blog/RSS" rel="self" type="application/rdf+xml"/>
      <title>Palladion Software Blog</title>
      <updated>2010-03-10T17:15:10Z</updated>
    </source>
  </entry>

  <entry xml:lang="en">
    <id>http://pauleveritt.wordpress.com/?p=45</id>
    <link href="http://pauleveritt.wordpress.com/2009/07/22/why-does-planet-python-bork-my-wordpress-links/" rel="alternate" type="text/html"/>
    <title>Why does Planet Python bork my WordPress links?</title>
    <summary type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml">Dear Lazyweb,
Marius (and others) reported that Planet Python screws up the links on my articles.  Instead of a full link to the article, it instead does a href="".  Looking at my RSS feed, I see that it correctly has link&gt;http://pauleveritt.wordpress.com/2009/07/15/kudos-to-malthe-for-chameleon/ in the item entries.  My feed URL passes the validator test as well.
As you [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=pauleveritt.wordpress.com&amp;blog=5206833&amp;post=45&amp;subd=pauleveritt&amp;ref=&amp;feed=1"/></div>
    </summary>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><br/><p>Dear Lazyweb,</p>
<p>Marius (and others) <a href="http://pauleveritt.wordpress.com/2009/07/14/ternary-like-operation-in-zpt/#comment-41">reported</a> that <a href="http://planet.python.org/">Planet Python</a> screws up the links on my articles.  Instead of a full link to the article, it instead does <code>a href=""</code>.  Looking at <a href="http://pauleveritt.wordpress.com/feed/">my RSS feed</a>, I see that it correctly has <code>link&gt;http://pauleveritt.wordpress.com/2009/07/15/kudos-to-malthe-for-chameleon/</code> in the <code>item</code> entries.  My feed URL passes the validator test as well.</p>
<p>As you well know, Lazyweb, I switched to WordPress (hosted!) so I wouldn’t have to think, as I’m not very good at that particular trait.  Any ideas on the cause of this?</p>
  <a href="http://feeds.wordpress.com/1.0/gocomments/pauleveritt.wordpress.com/45/" rel="nofollow"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/pauleveritt.wordpress.com/45/"/></a> <a href="http://feeds.wordpress.com/1.0/godelicious/pauleveritt.wordpress.com/45/" rel="nofollow"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/pauleveritt.wordpress.com/45/"/></a> <a href="http://feeds.wordpress.com/1.0/gostumble/pauleveritt.wordpress.com/45/" rel="nofollow"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/pauleveritt.wordpress.com/45/"/></a> <a href="http://feeds.wordpress.com/1.0/godigg/pauleveritt.wordpress.com/45/" rel="nofollow"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/pauleveritt.wordpress.com/45/"/></a> <a href="http://feeds.wordpress.com/1.0/goreddit/pauleveritt.wordpress.com/45/" rel="nofollow"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/pauleveritt.wordpress.com/45/"/></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=pauleveritt.wordpress.com&amp;blog=5206833&amp;post=45&amp;subd=pauleveritt&amp;ref=&amp;feed=1"/></div>
    </content>
    <updated>2009-07-22T14:56:40Z</updated>
    <category term="Uncategorized"/>
    <author>
      <name>Paul Everitt</name>
    </author>
    <source>
      <id>http://pauleveritt.wordpress.com</id>
      <logo>http://www.gravatar.com/blavatar/b4345850285023fbd98c4a40e02f7cbd?s=96&amp;d=http://s.wordpress.com/i/buttonw-com.png</logo>
      <link href="http://pauleveritt.wordpress.com/feed/" rel="self" type="application/atom+xml"/>
      <link href="http://pauleveritt.wordpress.com" rel="alternate" type="text/html"/>
      <link href="http://pauleveritt.wordpress.com/osd.xml" rel="search" type="application/opensearchdescription+xml"/>
      <subtitle>Paul's ramblings about projects and Python/Zope/Plone/Repoze/BFG technologies.</subtitle>
      <title>Chatterbox, Reloaded</title>
      <updated>2010-02-18T14:15:11Z</updated>
    </source>
  </entry>

  <entry xml:lang="en">
    <id>http://pauleveritt.wordpress.com/?p=42</id>
    <link href="http://pauleveritt.wordpress.com/2009/07/21/early-impressions-on-modwsgi-in-production/" rel="alternate" type="text/html"/>
    <title>Early impressions on modwsgi in production</title>
    <summary type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml">At the end of May we made the KARL cutover from KARL2 to KARL3.  We have now had almost 8 weeks in production, so we can form impressions about some of the decisions.
For example, we’re using modwsgi as a WSGI server.  In a way, this was a surprising decision.  Chris and I were both a [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=pauleveritt.wordpress.com&amp;blog=5206833&amp;post=42&amp;subd=pauleveritt&amp;ref=&amp;feed=1"/></div>
    </summary>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><br/><p>At the end of May we made the <a href="http://www.karlproject.org/">KARL</a> cutover from KARL2 to KARL3.  We have now had almost 8 weeks in production, so we can form impressions about some of the decisions.</p>
<p>For example, we’re using <a href="http://code.google.com/p/modwsgi/">modwsgi</a> as a WSGI server.  In a way, this was a surprising decision.  Chris and I were both a bit skeptical about whether it was a risk worth taking, as we hadn’t used it “in anger” beyond the repoze.org site.  As somewhat a throwaway test, I set it up on the test site we used for OSI to do the user acceptance testing for the 15 or so milestone deliverables on KARL, but with the idea that it wasn’t a permanent decision.</p>
<p>By the time we setup the deployment server, we had months of living with modwsgi under our belt, somewhat by accident.  Far more important, we added <a href="http://shane.willowrise.com/">Shane Hathaway</a> to the project.  Like Chris Rossi, Shane has been a boon for KARL in many ways.  In this case, Shane had <a href="http://shane.willowrise.com/archives/the-fastest-wsgi-server-for-zope/">experience with modwsgi</a> and said he would make sure we could stand behind it.</p>
<p>So we put it into production.  We’re running on an 8-core box setup as a Xen server, with the OSI instance getting 3 CPUs.  We started with modwsgi setup to run 2 BFG application processes (and thus ZEO clients), each with 2 threads.  modwsgi gave us some simplification: we didn’t need Apache/mod_proxy + BFG/Paster, with the latter managed by supervisor, possibly with a load balancer in between.  Instead, we let modwsgi in daemon mode handle that.</p>
<p>We also found that we could upgrade the software on the server, send a -GRACEFUL restart to Apache, and have a zero-downtime update to the server.  Which was nice.</p>
<p>Later, though, we found a really useful benefit to having modwsgi in the equation.  We then found that our LiveSearch implementation (and another part of the application) were slower (up to a second for a request) than other parts.  So we put in an Apache alias that matched on those URL types and sent them to a separately-configured BFG instance we call the “ghetto”.  This instance is primarily for catalog requests, so we changed the ZEO cache to be *very* high, but we also flush from the cache on each request any object that isn’t in the catalog.  This has been a boon.</p>
<p>I have an interest in looking later at some more options we gain from modwsgi.  For example, file delivery using <a href="http://www.python.org/dev/peps/pep-0333/#optional-platform-specific-file-handling">wsgi.file_wrapper</a> (which modwsgi <a href="http://code.google.com/p/modwsgi/issues/detail?id=132">fixed</a> its implementation <a href="http://groups.google.com/group/modwsgi/browse_frm/thread/e7111816e70d236a">bugs</a> in later releases.)  Also, modwsgi has some facilities for setting limits on the life of a request.</p>
<p>Still, regarding just the basics, we haven’t had much of a hitch at all.  So far, so good.</p>
  <a href="http://feeds.wordpress.com/1.0/gocomments/pauleveritt.wordpress.com/42/" rel="nofollow"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/pauleveritt.wordpress.com/42/"/></a> <a href="http://feeds.wordpress.com/1.0/godelicious/pauleveritt.wordpress.com/42/" rel="nofollow"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/pauleveritt.wordpress.com/42/"/></a> <a href="http://feeds.wordpress.com/1.0/gostumble/pauleveritt.wordpress.com/42/" rel="nofollow"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/pauleveritt.wordpress.com/42/"/></a> <a href="http://feeds.wordpress.com/1.0/godigg/pauleveritt.wordpress.com/42/" rel="nofollow"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/pauleveritt.wordpress.com/42/"/></a> <a href="http://feeds.wordpress.com/1.0/goreddit/pauleveritt.wordpress.com/42/" rel="nofollow"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/pauleveritt.wordpress.com/42/"/></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=pauleveritt.wordpress.com&amp;blog=5206833&amp;post=42&amp;subd=pauleveritt&amp;ref=&amp;feed=1"/></div>
    </content>
    <updated>2009-07-21T15:59:36Z</updated>
    <category term="KARL"/>
    <category term="WSGI"/>
    <author>
      <name>Paul Everitt</name>
    </author>
    <source>
      <id>http://pauleveritt.wordpress.com</id>
      <logo>http://www.gravatar.com/blavatar/b4345850285023fbd98c4a40e02f7cbd?s=96&amp;d=http://s.wordpress.com/i/buttonw-com.png</logo>
      <link href="http://pauleveritt.wordpress.com/feed/" rel="self" type="application/atom+xml"/>
      <link href="http://pauleveritt.wordpress.com" rel="alternate" type="text/html"/>
      <link href="http://pauleveritt.wordpress.com/osd.xml" rel="search" type="application/opensearchdescription+xml"/>
      <subtitle>Paul's ramblings about projects and Python/Zope/Plone/Repoze/BFG technologies.</subtitle>
      <title>Chatterbox, Reloaded</title>
      <updated>2010-02-18T14:15:11Z</updated>
    </source>
  </entry>

  <entry xml:lang="en">
    <id>http://pauleveritt.wordpress.com/?p=39</id>
    <link href="http://pauleveritt.wordpress.com/2009/07/21/belated-happy-first-birthday-bfg/" rel="alternate" type="text/html"/>
    <title>Belated happy first birthday, BFG</title>
    <summary type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml">While I was on vacation, Chris McDonough wrapped up work on BFG 1.0.  The BFG elevator speech hits the nail on the head:
BFG is a “pay only for what you eat” Python web framework. You can get started easily and learn new concepts as you go, and only if you need them. It’s simple, well [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=pauleveritt.wordpress.com&amp;blog=5206833&amp;post=39&amp;subd=pauleveritt&amp;ref=&amp;feed=1"/></div>
    </summary>
    <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><br/><p>While I was on vacation, Chris McDonough <a href="http://plope.com/Members/chrism/repoze-bfg-1.0">wrapped up</a> work on <a href="http://bfg.repoze.org/">BFG</a> 1.0.  The BFG elevator speech hits the nail on the head:</p>
<div style="margin-left: 2em; font-style: italic;">BFG is a “pay only for what you eat” Python web framework. You can get started easily and learn new concepts as you go, and only if you need them. It’s simple, well tested, well documented, and fast.</div>
<p>I’ve used BFG on <a href="http://www.karlproject.org/">KARL</a> for the last 9 or so months and have found almost everything about it to be a relief.  With this 1.0 release, BFG has achieved a sweet spot of stability and maturity combined with ongoing vitality. While BFG is particularly attractive to Zope developers looking for a modern alternative, it is also attractive more generally to Python web developers.  It’s hard to imagine there still being unmet needs, but BFG stands out for people who take the points in the elevator speech above seriously.</p>
<p>All of this due to the massive effort Chris put into it.  Not just making it, but mega-documenting it, 100% coverage on tests, answering questions, sample applications, keeping everything up to date on every change, etc.  There are quite a few people participating in BFG, but these efforts are generously given because Chris is there to integrate them.</p>
<p>So congrats Chris, and thanks.</p>
  <a href="http://feeds.wordpress.com/1.0/gocomments/pauleveritt.wordpress.com/39/" rel="nofollow"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/pauleveritt.wordpress.com/39/"/></a> <a href="http://feeds.wordpress.com/1.0/godelicious/pauleveritt.wordpress.com/39/" rel="nofollow"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/pauleveritt.wordpress.com/39/"/></a> <a href="http://feeds.wordpress.com/1.0/gostumble/pauleveritt.wordpress.com/39/" rel="nofollow"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/pauleveritt.wordpress.com/39/"/></a> <a href="http://feeds.wordpress.com/1.0/godigg/pauleveritt.wordpress.com/39/" rel="nofollow"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/pauleveritt.wordpress.com/39/"/></a> <a href="http://feeds.wordpress.com/1.0/goreddit/pauleveritt.wordpress.com/39/" rel="nofollow"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/pauleveritt.wordpress.com/39/"/></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=pauleveritt.wordpress.com&amp;blog=5206833&amp;post=39&amp;subd=pauleveritt&amp;ref=&amp;feed=1"/></div>
    </content>
    <updated>2009-07-21T15:07:50Z</updated>
    <category term="BFG"/>
    <category term="WSGI"/>
    <author>
      <name>Paul Everitt</name>
    </author>
    <source>
      <id>http://pauleveritt.wordpress.com</id>
      <logo>http://www.gravatar.com/blavatar/b4345850285023fbd98c4a40e02f7cbd?s=96&amp;d=http://s.wordpress.com/i/buttonw-com.png</logo>
      <link href="http://pauleveritt.wordpress.com/feed/" rel="self" type="application/atom+xml"/>
      <link href="http://pauleveritt.wordpress.com" rel="alternate" type="text/html"/>
      <link href="http://pauleveritt.wordpress.com/osd.xml" rel="search" type="application/opensearchdescription+xml"/>
      <subtitle>Paul's ramblings about projects and Python/Zope/Plone/Repoze/BFG technologies.</subtitle>
      <title>Chatterbox, Reloaded</title>
      <updated>2010-02-18T14:15:11Z</updated>
    </source>
  </entry>

  <entry xml:lang="en">
    <id>http://blog.repoze.org/2009/07/15/feneric-urispace_dvselect_and_plone_oh_my-20090715</id>
    <link href="http://blog.repoze.org/feneric-urispace_dvselect_and_plone_oh_my-20090715.html" rel="alternate" type="text/html"/>
    <title xml:lang="en">repoze.urispace, repoze.dvselect, and Plone, oh my!</title>
    <content type="xhtml" xml:lang="en"><div xmlns="http://www.w3.org/1999/xhtml"><p> After being the guinea pig to iron out bugs and documentation issues
for the pairing of <a href="http://packages.python.org/repoze.urispace"><code>repoze.urispace</code></a> and
<a href="http://packages.python.org/repoze.dvselect"><code>repoze.dvselect</code></a>, Eric Brown went above and beyond the
call of duty by
<a href="http://feneric.blogspot.com/2009/07/repoze-zope-plone-urispace-and.html">writing up how to use the pair to theme multiple Plone sites using
Deliverance.</a> </p></div>
    </content>
    <updated>2009-07-15T23:16:42Z</updated>
    <published>2009-07-15T23:16:42Z</published>
    <source>
      <id>http://blog.repoze.org/index.atom</id>
      <author>
        <name>The Repoze Team</name>
        <email>repoze-dev@lists.repoze.org</email>
        <uri>http://blog.repoze.org/index.atom</uri>
      </author>
      <link href="http://blog.repoze.org" rel="alternate" type="text/html"/>
      <link href="http://blog.repoze.org/index.atom" rel="self" type="application/atom+xml"/>
      <rights xml:lang="en">Copyright 2007 Agendaless Consulting, Inc.</rights>
      <subtitle xml:lang="en">Notes on the Repoze platform</subtitle>
      <title xml:lang="en">Repoze Notes</title>
      <updated>2009-09-09T19:52:23Z</updated>
    </source>
  </entry>
</feed>
