<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	>

<channel>
	<title>Ian Bicking: a blog</title>
	<atom:link href="http://blog.ianbicking.org/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.ianbicking.org</link>
	<description></description>
	<pubDate>Sat, 13 Mar 2010 00:15:22 +0000</pubDate>
	<generator>http://wordpress.org/?v=2.7</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>What Does A WebOb App Look Like?</title>
		<link>http://blog.ianbicking.org/2010/03/12/a-webob-app-example/</link>
		<comments>http://blog.ianbicking.org/2010/03/12/a-webob-app-example/#comments</comments>
		<pubDate>Fri, 12 Mar 2010 23:50:30 +0000</pubDate>
		<dc:creator>Ian Bicking</dc:creator>
		
		<category><![CDATA[Programming]]></category>

		<category><![CDATA[Python]]></category>

		<category><![CDATA[Web]]></category>

		<guid isPermaLink="false">http://blog.ianbicking.org/?p=192</guid>
		<description><![CDATA[
Lately I&#8217;ve been writing code using WebOb and just a few other small libraries.  It&#8217;s not entirely obvious what this looks like, so I thought I&#8217;d give a simple example.
I make each application a class.  Instances of the class are &#34;configured applications&#34;.  So it looks a little like this (for an application [...]]]></description>
			<content:encoded><![CDATA[<div class="document">
<p>Lately I&#8217;ve been writing code using WebOb and just a few other small libraries.  It&#8217;s not entirely obvious what this looks like, so I thought I&#8217;d give a simple example.</p>
<p>I make each application a class.  Instances of the class are &quot;configured applications&quot;.  So it looks a little like this (for an application that takes one configuration parameter, <tt class="docutils literal"><span class="pre">file_path</span></tt>):</p>
<pre class="literal-block">
class Application(object):
    def __init__(self, file_path):
        self.file_path = file_path
</pre>
<p>Then the app needs to be a WSGI app, because that&#8217;s how I roll.  I use <a class="reference external" href="http://pythonpaste.org/webob/modules/dec.html">webob.dec</a>:</p>
<pre class="literal-block">
from webob.dec import wsgify
from webob import exc
from webob import Response

class Application(object):
    def __init__(self, file_path):
        self.file_path = file_path
    &#64;wsgify
    def __call__(self, req):
        return Response('Hi!')
</pre>
<p>Somewhere separate from the application you actually instantiate <tt class="docutils literal"><span class="pre">Application</span></tt>.  You can use <a class="reference external" href="http://pythonpaste.org/deploy/">Paste Deploy</a> for that, configure it yourself, or just do something ad hoc (a lot of mod_wsgi <tt class="docutils literal"><span class="pre">.wsgi</span></tt> files are like this, basically).</p>
<p>I use <a class="reference external" href="http://pythonpaste.org/webob/reference.html#exceptions">webob.exc</a> for things like <tt class="docutils literal"><span class="pre">exc.HTTPNotFound()</span></tt>.  You can raise that as an exception, but I mostly just return the object (to the same effect).</p>
<p>Now you have Hello World.  I then sometimes do something terrible, I start handling URLs like this:</p>
<pre class="literal-block">
&#64;wsgify
def __call__(self, req):
    if req.path_info == '/':
        return self.index(req)
    elif req.path_info.startswith('/view/'):
        return self.view(req)
    return exc.HTTPNotFound()
</pre>
<p>This is lazy and a very bad idea.  So you want a dispatcher.  There are several (e.g., <a class="reference external" href="http://pypi.python.org/pypi/selector/">selector</a>).  I&#8217;ll use <a class="reference external" href="http://routes.groovie.org">Routes</a> here&#8230; the latest release makes it a bit easier (though it could still be streamlined a bit).  Here&#8217;s a pattern I think makes sense:</p>
<pre class="literal-block">
from routes import Mapper

class Application(object):
    map = Mapper()
    map.connect('index', '/', method='index')
    map.connect('view', '/view/{item}', method='view')

    def __init__(self, file_path):
        self.file_path = file_path

    &#64;wsgify
    def __call__(self, req):
        results = self.map.routematch(environ=req.environ)
        if not results:
            return exc.HTTPNotFound()
        match, route = results
        link = URLGenerator(self.map, req.environ)
        req.urlvars = ((), match)
        kwargs = match.copy()
        method = kwargs.pop('method')
        req.link = link
        return getattr(self, method)(req, **kwargs)

    def index(self, req):
        ...
    def view(self, req, item):
        ...
</pre>
<p>Another way you might do it is to skip the class, which means skipping a clear place for configuration.  I don&#8217;t like that, but if you don&#8217;t care about that, then it looks like this:</p>
<pre class="literal-block">
def index(self, req):
    ...
def view(self, req, item):
    ...

map = Mapper()
map.connect('index', '/', view=index)
map.connect('view', '/view/{item}', view=view)

&#64;wsgify
def application(req):
    results = map.routematch(environ=req.environ)
    if not results:
        return exc.HTTPNotFound()
    match, route = results
    link = URLGenerator(map, req.environ)
    req.urlvars = ((), match)
    kwargs = match.copy()
    view = kwargs.pop('view')
    req.link = link
    return view(req, **kwargs)
</pre>
<p>Then <tt class="docutils literal"><span class="pre">application</span></tt> is pretty much boilerplate.  You could put configuration in the request if you wanted, or use some other technique (like <a class="reference external" href="http://pypi.python.org/pypi/Contextual">Contextual</a>).</p>
<p>I talked some with <a class="reference external" href="http://be.groovie.org/">Ben Bangert</a> about what he&#8217;s trying with these patterns, and he&#8217;s doing something reminiscent of Pylons controllers (but without the rest of Pylons) and it looks more like this (with my own adaptations):</p>
<pre class="literal-block">
class BaseController(object):
    special_vars = ['controller', 'action']

    def __init__(self, request, link, **config):
        self.request = request
        self.link = link
        for name, value in config.items():
            setattr(self, name, value)

    def __call__(self):
        action = self.request.urlvars.get('action', 'index')
        if hasattr(self, '__before__'):
            self.__before__()
        kwargs = req.urlsvars.copy()
        for attr in self.special_vars
            if attr in kwargs:
                del kwargs[attr]
        return getattr(self, action)(**kwargs)

class Index(BaseController):
    def index(self):
        ...
    def view(self, item):
        ...

class Application(object):
    map = Mapper()
    map.connect('index', '/', controller=Index)
    map.connect('view', '/view/{item}', controller=Index,     action='view')

    def __init__(self, **config):
        self.config = config

    &#64;wsgify
    def __call__(self, req):
        results = self.map.routematch(environ=req.environ)
        if not results:
            return exc.HTTPNotFound()
        match, route = results
        link = URLGenerator(self.map, req.environ)
        req.urlvars = ((), match)
        controller = match['controller'](req, link, **self.config)
        return controller()
</pre>
<p>That&#8217;s a lot of code blocks, but they all really say the same thing ;)  I think writing apps with almost-no-framework like this is pretty doable, so if you have something small you should give it a go.  I think it&#8217;s especially appropriate for applications that are an API (not a &quot;web site&quot;).</p>
</div>
]]></content:encoded>
			<wfw:commentRss>http://blog.ianbicking.org/2010/03/12/a-webob-app-example/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Configuration management: push vs. pull</title>
		<link>http://blog.ianbicking.org/2010/03/10/configuration-management-push-vs-pull/</link>
		<comments>http://blog.ianbicking.org/2010/03/10/configuration-management-push-vs-pull/#comments</comments>
		<pubDate>Thu, 11 Mar 2010 01:45:02 +0000</pubDate>
		<dc:creator>Ian Bicking</dc:creator>
		
		<category><![CDATA[Programming]]></category>

		<category><![CDATA[Silver Lining]]></category>

		<category><![CDATA[puppet configuration "configuration management"]]></category>

		<guid isPermaLink="false">http://blog.ianbicking.org/?p=180</guid>
		<description><![CDATA[
Since I&#8217;ve been thinking about deployment I&#8217;ve been thinking a lot more about what &#34;configuration management&#34; means, how it should work, what it should do.
I guess my quick summary of configuration management is that it is setting up a server correctly.  &#34;Correct&#34; is an ambiguous term, but given that there are so many to [...]]]></description>
			<content:encoded><![CDATA[<div class="document">
<p>Since I&#8217;ve been thinking about <a class="reference external" href="http://blog.ianbicking.org/category/silverlining">deployment</a> I&#8217;ve been thinking a lot more about what &quot;configuration management&quot; means, how it should work, what it should do.</p>
<p>I guess my quick summary of configuration management is that it is <em>setting up a server correctly</em>.  &quot;Correct&quot; is an ambiguous term, but given that there are so many to configuration management the solutions are also ambiguous.</p>
<p><a class="reference external" href="http://cloudsilverlining.org">Silver Lining</a> includes configuration management of a sort.  It is very simple.  Right now it is simply a bunch of files to rsync over, and one shell script (you can see the <a class="reference external" href="http://bitbucket.org/ianb/silverlining/src/tip/silverlining/server-files/serverroot/">files here</a> and the <a class="reference external" href="http://bitbucket.org/ianb/silverlining/src/tip/silverlining/server-files/update-server-script.sh">script here</a> &#8212; at least until I move them and those links start 404ing).  Also each &quot;service&quot; (e.g., a database) has a simple setup script.  I&#8217;m sure this system will become more complicated over time, but it&#8217;s <strong>really</strong> simple right now, and I like that.</p>
<p>The other system I&#8217;ve been asked about the most about lately is <a class="reference external" href="http://reductivelabs.com/products/puppet/">Puppet</a>.  Puppet is a <em>real</em> configuration management system.  The driving forces are very different: I&#8217;m just trying to get a system set up that is in all ways <em>acceptable</em> for web application deployment.  I want <em>one</em> system set up for <em>one</em> kind of task; I am completely focused on that end, and I care about means only insofar as I don&#8217;t want to get distracted by those means.  Puppet is for people who care about the means, not just the ends.  People who want things to work in a particular <em>way</em>; I only care that they <em>work</em>.</p>
<p>That&#8217;s the big difference between Puppet and Silver Lining.  The smaller difference (that I want to talk about) is &quot;push&quot; vs. &quot;pull&quot;.  <a class="reference external" href="http://agiletesting.blogspot.com/2010/03/automated-deployment-systems-push-vs.html">Grig wrote up some notes on two approaches</a>.  Silver Lining uses a &quot;push&quot; system (though calling it a &quot;system&quot; is kind of overselling what it does) while Puppet is &quot;pull&quot;.  Basically Silver Lining runs these commands (from your personal computer):</p>
<pre class="literal-block">
$ rsync -r &lt;silverlining&gt;/server-files/serverroot/ root&#64;server:/
$ ssh root&#64;server &quot;$(cat &lt;silverlining&gt;/server-files/update-server-script.sh)&quot;
</pre>
<p>This is what happens when you run <tt class="docutils literal"><span class="pre">silver</span> <span class="pre">setup-node</span> <span class="pre">server</span></tt>: it pushes a bunch of files over to the server, and runs a shell script.  If you update either of the files or the shell script you run <tt class="docutils literal"><span class="pre">silver</span> <span class="pre">setup-node</span></tt> again to update the server.  This is &quot;push&quot; because everything is initiated by the &quot;master&quot; (in this case, the developer&#8217;s personal computer).</p>
<p>Puppet uses a pull model.  In this model there is a daemon running on every machine, and these machines call in to the master to see if there&#8217;s any new instructions for them.  If there are, the daemon applies those instructions to the machine it is running on.</p>
<p>Grig identifies two big advantages to this pull model:</p>
<ol class="arabic simple">
<li>When a new server comes up it can get instructions from the master and start doing things.  You can&#8217;t push instructions to a server that isn&#8217;t there, and the server itself is most aware of when it is ready to do stuff.</li>
<li>If a lot of servers come up, they can all do the setup work on their own, they only have to ask the master what to do.</li>
</ol>
<p>But&#8230; I don&#8217;t buy either justification.</p>
<p>First: servers don&#8217;t just <em>do</em> things when they start up.  To get this to work you have to create custom images with Puppet installed, and configured to know where the master is, and either the image or the master needs some indication of <em>what kind</em> of server you intended to create.  All this is to avoid polling a server to see when it comes online.  Polling a server is lame (and is the best Silver Lining can do right now), but avoiding polling can be done with something a lot simpler than a complete change from push to pull.</p>
<p>Second: there&#8217;s nothing unscalable about push.  Look at those commands: one <tt class="docutils literal"><span class="pre">rsync</span></tt> and one <tt class="docutils literal"><span class="pre">ssh</span></tt>.  The first is pretty darn cheap, and the second is cheap on the master and expensive on the remote machine (since it is doing things like installing stuff).  You need to do it on lots of machines?  Then fork a bunch of processes to run those two commands.  This is not complicated stuff.</p>
<p>It is <em>possible</em> to write a push system that is hard to scale, if the master is doing lots of work.  But just don&#8217;t do that.  Upload your setup code to the remote server/slave and <em>run it there</em>.  Problem fixed!</p>
<p>What are the advantages of push?</p>
<ol class="arabic simple">
<li>Easy to bootstrap.  A bare server can be setup with push, no customization needed.  Any customization is another kind of configuration, and configuration should be automated, and&#8230; well, this is why it&#8217;s a bootstrap problem.</li>
<li>Errors are synchronous: if your setup code doesn&#8217;t work, your push system will get the error back, you don&#8217;t need some fancy monitor and you don&#8217;t need to check any logs.  Weird behavior is also synchronous; can&#8217;t tell why servers are doing something?  Run the commands and watch the output.</li>
<li>Development is sensible: if you have a change to your setup scripts, you can try it out from your machine.  You don&#8217;t need to do anything exceptional, your machine doesn&#8217;t have to accept connections from the slave, you don&#8217;t need special instructions to keep the slave from setting itself up as a production machine, there&#8217;s no daemon that might need modifications&#8230; none of that.  You change the code, you run it, it works.</li>
<li>It&#8217;s just so damn simple.  If you don&#8217;t start thinking about push and pull and other design choices, it simply becomes: do the obvious and easy thing.</li>
</ol>
<p>In conclusion: push is sensible, pull is needless complexity.</p>
</div>
]]></content:encoded>
			<wfw:commentRss>http://blog.ianbicking.org/2010/03/10/configuration-management-push-vs-pull/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Joining Mozilla</title>
		<link>http://blog.ianbicking.org/2010/03/10/joining-mozilla/</link>
		<comments>http://blog.ianbicking.org/2010/03/10/joining-mozilla/#comments</comments>
		<pubDate>Wed, 10 Mar 2010 23:46:40 +0000</pubDate>
		<dc:creator>Ian Bicking</dc:creator>
		
		<category><![CDATA[Mozilla]]></category>

		<category><![CDATA[Non-technical]]></category>

		<category><![CDATA[Programming]]></category>

		<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://blog.ianbicking.org/?p=185</guid>
		<description><![CDATA[
As of last week, I am now an employee of Mozilla!  Thanks to everyone who helped me out during my job search.
I&#8217;ll be working both with the Mozilla Web Development (webdev) team, and Mozilla Labs.
The first thing I&#8217;ll be working on is deployment.  In part because I&#8217;ve been thinking about deployment lately, in [...]]]></description>
			<content:encoded><![CDATA[<div class="document">
<p>As of last week, I am now an employee of Mozilla!  Thanks to everyone who helped me out during my job search.</p>
<p>I&#8217;ll be working both with the Mozilla <a class="reference external" href="http://blog.mozilla.com/webdev/">Web Development (webdev)</a> team, and <a class="reference external" href="https://mozillalabs.com/">Mozilla Labs</a>.</p>
<p>The first thing I&#8217;ll be working on is deployment.  In part because I&#8217;ve been <a class="reference external" href="http://blog.ianbicking.org/category/silverlining/">thinking about deployment lately</a>, in part because streamlining deployment is just generally enabling of other work (and a personal itch to be scratched), and because I think there is the possibility to fit this work into Mozilla&#8217;s <a class="reference external" href="http://www.mozilla.org/causes/">general mission</a>, specifically <em>Empowering people to do new and unanticipated things on the web</em>.  I think the way I&#8217;m approaching deployment has real potential to combine the discipline and benefits of good development practices with an accessible process that is more <em>democratic</em> and less <em>professionalized</em>.  This is some of what <a class="reference external" href="http://blog.ianbicking.org/2008/01/12/what-php-deployment-gets-right/">PHP has provided</a> over the years (and I think it&#8217;s been a genuinely positive influence on the web as a result); I&#8217;d like to see the same kind of easy entry using other platforms.  I&#8217;m hoping <a class="reference external" href="http://cloudsilverlining.org">Silver Lining</a> will fit both Mozilla&#8217;s application deployment needs, as well as serving a general purpose.</p>
<p>Once I <em>finish</em> deployment and can move on (oh fuck what am I getting myself into) I&#8217;ll also be working with the <a class="reference external" href="http://blog.mozilla.com/webdev">web development group</a> who has adopted Python for many of their new projects (e.g., <a class="reference external" href="http://github.com/jbalogh/zamboni">Zamboni</a>, a rewrite of the <a class="reference external" href="https://addons.mozilla.org/">addons.mozilla.org</a> site), and with Mozilla Labs on <a class="reference external" href="http://mozillalabs.com/weave/">Weave</a> or some of their other projects.</p>
<p>In addition my own <a class="reference external" href="http://ianbicking.appspot.com/projects">Python open source work</a> is in line with Mozilla&#8217;s mission and I will be able to continue spending time on those projects, as well as entirely new projects.</p>
<p>I&#8217;m pretty excited about this &#8212; it feels like there&#8217;s a really good match with Mozilla and what I&#8217;m good at, and what I care about, and <em>how</em> I care about it.</p>
</div>
]]></content:encoded>
			<wfw:commentRss>http://blog.ianbicking.org/2010/03/10/joining-mozilla/feed/</wfw:commentRss>
		</item>
		<item>
		<title>toppcloud renamed to Silver Lining</title>
		<link>http://blog.ianbicking.org/2010/03/03/toppcloud-renamed-to-silver-lining/</link>
		<comments>http://blog.ianbicking.org/2010/03/03/toppcloud-renamed-to-silver-lining/#comments</comments>
		<pubDate>Thu, 04 Mar 2010 02:18:30 +0000</pubDate>
		<dc:creator>Ian Bicking</dc:creator>
		
		<category><![CDATA[Packaging]]></category>

		<category><![CDATA[Programming]]></category>

		<category><![CDATA[Python]]></category>

		<category><![CDATA[Silver Lining]]></category>

		<category><![CDATA[Web]]></category>

		<guid isPermaLink="false">http://blog.ianbicking.org/?p=168</guid>
		<description><![CDATA[
After some pondering at PyCon, I decided on a new name for toppcloud: Silver Lining.  I&#8217;ll credit a mysterious commenter &#34;david&#34; with the name idea.  The command line is simply silver &#8212; silver update has a nice ring to it.
There&#8217;s a new site: cloudsilverlining.org; not notably different than the old site, just a [...]]]></description>
			<content:encoded><![CDATA[<div class="document">
<p>After some pondering at PyCon, I decided on a new name for toppcloud: <strong>Silver Lining</strong>.  I&#8217;ll credit a mysterious commenter &quot;david&quot; with the name idea.  The command line is simply <tt class="docutils literal"><span class="pre">silver</span></tt> &#8212; <tt class="docutils literal"><span class="pre">silver</span> <span class="pre">update</span></tt> has a nice ring to it.</p>
<p>There&#8217;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&#8217;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&#8217;d be nice/clever if it could.)</p>
</div>
]]></content:encoded>
			<wfw:commentRss>http://blog.ianbicking.org/2010/03/03/toppcloud-renamed-to-silver-lining/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Throw out your frameworks! (forms included)</title>
		<link>http://blog.ianbicking.org/2010/03/01/throw-out-your-frameworks-forms-included/</link>
		<comments>http://blog.ianbicking.org/2010/03/01/throw-out-your-frameworks-forms-included/#comments</comments>
		<pubDate>Mon, 01 Mar 2010 06:29:04 +0000</pubDate>
		<dc:creator>Ian Bicking</dc:creator>
		
		<category><![CDATA[HTML]]></category>

		<category><![CDATA[Programming]]></category>

		<category><![CDATA[Python]]></category>

		<category><![CDATA[Web]]></category>

		<guid isPermaLink="false">http://blog.ianbicking.org/?p=164</guid>
		<description><![CDATA[
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&#8217;s writeup about dynamic Django form generation I felt a desire to respond.  I didn&#8217;t see the form panel at [...]]]></description>
			<content:encoded><![CDATA[<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&#8217;s writeup about dynamic Django form generation</a> I felt a desire to respond.  I didn&#8217;t see the form panel at PyCon (I intended to but I hardly saw <em>any</em> talks at PyCon, and yet still didn&#8217;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&#8217;s description</a>; but basically it&#8217;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&#8217;t skipping anything, but I&#8217;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

&#64;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 &quot;form generation&quot;:
    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&#8217;ve just manually handled validation here.  I don&#8217;t feel like doing it with FormEncode.  Manual validation isn&#8217;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&#8217;t do better than hand-written validation code: it&#8217;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&#8217;m using <a class="reference external" href="http://pythonpaste.org/tempita/">Tempita</a>, but it really doesn&#8217;t matter.  The template looks like this:</p>
<pre class="literal-block">
&lt;form action=&quot;{{action}}&quot; method=&quot;POST&quot;&gt;
New Username: &lt;input type=&quot;text&quot; name=&quot;username&quot;&gt;&lt;br /&gt;
Password: &lt;input type=&quot;password&quot; name=&quot;password&quot;&gt;&lt;br /&gt;
Repeat Password:
  &lt;input type=&quot;password&quot; name=&quot;password_confirm&quot;&gt;&lt;br /&gt;
{{for question in questions}}
  {{question}}: &lt;input type=&quot;text&quot; name=&quot;{{question}}&quot;&gt;&lt;br /&gt;
{{endfor}}
&lt;input type=&quot;submit&quot;&gt;
&lt;/form&gt;
</pre>
<p>Note that the only &quot;logic&quot; here is to render the form to include fields for all the questions.  Obviously this produces an ugly form, but it&#8217;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&#8217;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&#8217;t need a template at all if it wasn&#8217;t for the dynamicism.  Everything else is added when the form is &quot;filled&quot;:</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&#8217;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&#8217;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&#8217; stupid!)  If at all possible, dodging complexity is far better than cleverly responding to complexity.</p>
</div>
]]></content:encoded>
			<wfw:commentRss>http://blog.ianbicking.org/2010/03/01/throw-out-your-frameworks-forms-included/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Why toppcloud (Silver Lining) will not be agnostic</title>
		<link>http://blog.ianbicking.org/2010/02/10/why-toppcloud-not-agnostic/</link>
		<comments>http://blog.ianbicking.org/2010/02/10/why-toppcloud-not-agnostic/#comments</comments>
		<pubDate>Wed, 10 Feb 2010 06:41:45 +0000</pubDate>
		<dc:creator>Ian Bicking</dc:creator>
		
		<category><![CDATA[Programming]]></category>

		<category><![CDATA[Python]]></category>

		<category><![CDATA[Silver Lining]]></category>

		<category><![CDATA[Web]]></category>

		<guid isPermaLink="false">http://blog.ianbicking.org/?p=158</guid>
		<description><![CDATA[
I haven&#8217;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 &#8212; and this is not unexpected &#8212; I have already gotten several requests about making it more agnostic with respect to&#8230; stuff. [...]]]></description>
			<content:encoded><![CDATA[<div class="document">
<p>I haven&#8217;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 &#8212; and this is not unexpected &#8212; I have already gotten several requests about making it more agnostic with respect to&#8230; 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 &quot;opinionated&quot; tool; toppcloud is not actually very opinionated.  It&#8217;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&#8217;t know <em>quite</em> why mod_wsgi has this particular problem (when other WSGI servers that I&#8217;ve used haven&#8217;t), but the fix isn&#8217;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&#8217;s also a Python bug.  But it doesn&#8217;t really matter.  When a bug exists it &quot;belongs&quot; to everyone who encounters it.</p>
<p>toppcloud is not intended to be a transparent system.  When it&#8217;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 &quot;somewhere else&quot; in the system.  Or, if you don&#8217;t define these problems as someone else&#8217;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&#8217;s problem may introduce a new problem in someone else&#8217;s stack.  Some fixes aren&#8217;t even clear.  toppcloud has Varnish in place, so it&#8217;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&#8217;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&#8217;d much rather have a system that is inflexible than one that doesn&#8217;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&#8217;m going to change the name of toppcloud</a>, so ideas are welcome!</p>
</div>
]]></content:encoded>
			<wfw:commentRss>http://blog.ianbicking.org/2010/02/10/why-toppcloud-not-agnostic/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Leaving TOPP</title>
		<link>http://blog.ianbicking.org/2010/02/09/leaving-topp/</link>
		<comments>http://blog.ianbicking.org/2010/02/09/leaving-topp/#comments</comments>
		<pubDate>Tue, 09 Feb 2010 06:05:40 +0000</pubDate>
		<dc:creator>Ian Bicking</dc:creator>
		
		<category><![CDATA[Non-technical]]></category>

		<guid isPermaLink="false">http://blog.ianbicking.org/?p=153</guid>
		<description><![CDATA[
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, [...]]]></description>
			<content:encoded><![CDATA[<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 &quot;planning&quot;, and though it&#8217;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&#8230; unfortunately I won&#8217;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&#8230; well, he&#8217;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&#8217;ll do next will have a very different focus.  This feels a bit weird, a kind of lost identity.  Overall I&#8217;m feeling pretty optimistic about finding something new and interesting to do, but I&#8217;m still a bit melancholy about leaving things behind.  That TOPP and the people I&#8217;ve worked with are far away in New York makes it feel like more of a loss because I don&#8217;t know when I&#8217;ll be back next.  But onward and upward!  Now to find out what is next&#8230;</p>
</div>
]]></content:encoded>
			<wfw:commentRss>http://blog.ianbicking.org/2010/02/09/leaving-topp/feed/</wfw:commentRss>
		</item>
		<item>
		<title>Weave: valuable client-side data</title>
		<link>http://blog.ianbicking.org/2010/02/06/weave-client-side-data/</link>
		<comments>http://blog.ianbicking.org/2010/02/06/weave-client-side-data/#comments</comments>
		<pubDate>Sat, 06 Feb 2010 23:03:49 +0000</pubDate>
		<dc:creator>Ian Bicking</dc:creator>
		
		<category><![CDATA[HTML]]></category>

		<category><![CDATA[Web]]></category>

		<guid isPermaLink="false">http://blog.ianbicking.org/?p=149</guid>
		<description><![CDATA[
I&#8217;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 [...]]]></description>
			<content:encoded><![CDATA[<div class="document">
<p>I&#8217;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&#8217;d seen before there&#8217;s a good chance I wouldn&#8217;t have saved it, while my bookmarks would be flooded with things that time would show were of transient interest.</p>
<p>So&#8230; synchronizing bookmarks, eh.  Saved form data and logins?  Sure, that&#8217;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&#8230; because cookies are opaque and can&#8217;t hold much data, can&#8217;t be exchanged, and probably worst of all they just disappear randomly.</p>
<p>What if cookies weren&#8217;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&#8217;t handle the problem of data disappearing as you move between computers and browser.  That&#8217;s where Weave synchronization could change things.  I don&#8217;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 &#8212; just copy all the resources.  So long as you don&#8217;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&#8217;s data, but the data in Facebook is <em>still</em> more transparent than data held in files or locally with a browser.  Let&#8217;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 &quot;user&quot; is in &quot;control&quot; 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&#8230; maybe it&#8217;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&#8230; they are on it!</p>
</div>
]]></content:encoded>
			<wfw:commentRss>http://blog.ianbicking.org/2010/02/06/weave-client-side-data/feed/</wfw:commentRss>
		</item>
		<item>
		<title>toppcloud (Silver Lining) and Django</title>
		<link>http://blog.ianbicking.org/2010/02/05/toppcloud-and-django/</link>
		<comments>http://blog.ianbicking.org/2010/02/05/toppcloud-and-django/#comments</comments>
		<pubDate>Fri, 05 Feb 2010 08:50:58 +0000</pubDate>
		<dc:creator>Ian Bicking</dc:creator>
		
		<category><![CDATA[Programming]]></category>

		<category><![CDATA[Python]]></category>

		<category><![CDATA[Silver Lining]]></category>

		<category><![CDATA[Web]]></category>

		<guid isPermaLink="false">http://blog.ianbicking.org/?p=143</guid>
		<description><![CDATA[
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&#8217;ll drop them here too&#8230;

Creating a Layout
First thing you have to do (after installing toppcloud of course) is create an environment for your new application.  [...]]]></description>
			<content:encoded><![CDATA[<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&#8217;ll drop them here too&#8230;</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&#8217;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&#8217;ll use the username <tt class="docutils literal"><span class="pre">USER</span></tt>).</p>
<p>We&#8217;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 &quot;syntax: glob
bin/python*
bin/activate
bin/activate_this.py
bin/pip
bin/easy_install*
&quot; &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&#8217;ll install Django:</p>
<pre class="literal-block">
$ source bin/activate
$ pip install Django
</pre>
<p>Then we&#8217;ll set up a standard Django site:</p>
<pre class="literal-block">
$ cd src/sampleapp
$ django-admin.py sampleapp
</pre>
<p>Also we&#8217;d like to be able to import this file.  It&#8217;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&#8217;t create that itself.  Instead we&#8217;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 &quot;../../src/sampleapp&quot; &gt; lib/python/sampleapp.pth
</pre>
<p>Also there&#8217;s the tricky <tt class="docutils literal"><span class="pre">$DJANGO_SETTINGS_MODULE</span></tt> that you might have had problems with before.  We&#8217;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 &quot;import os
os.environ['DJANGO_SETTINGS_MODULE'] = 'sampleapp.settings'
&quot; &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&#8217;t work <em>quite</em> how we&#8217;d like.  Instead we&#8217;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__ == &quot;__main__&quot;:
    execute_manager(settings)
' &gt; bin/manage.py
$ chmod +x bin/manage.py
</pre>
<p>Now, if you were just using plain Django you&#8217;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&#8217;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&#8217;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 &quot;root&quot; of your application, and named <tt class="docutils literal"><span class="pre">app.ini</span></tt>, but it&#8217;s good to keep it in version control, so we set it up with a symlink.</p>
<p>It also refers to a &quot;runner&quot;, which is the Python file that loads up the WSGI application.  This looks about the same for any Django application, and we&#8217;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&#8217;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 &quot;available&quot; 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&#8217;ll need to change <tt class="docutils literal"><span class="pre">settings.py</span></tt> to use the new database configuration.  Here&#8217;s the lines that you&#8217;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&#8217;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&#8217;t do anything.  Let&#8217;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> &#8212; we&#8217;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">&#8217;sampleapp.polls&#8217;</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">&#8216;django.contrib.admin&#8217;</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&#8217;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">&#8216;/admin-media&#8217;</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#&#64;$&#64;#JFAS#&#64;'
</pre>
<p>With this:</p>
<pre class="literal-block">
from tcsupport.secret import get_secret
SECRET_KEY = get_secret()
</pre>
<p>Then you don&#8217;t have to worry about checking a secret into version control.</p>
<p>You still don&#8217;t really have an application, but the rest is mere &quot;programming&quot; so have at it!</p>
</div>
</div>
]]></content:encoded>
			<wfw:commentRss>http://blog.ianbicking.org/2010/02/05/toppcloud-and-django/feed/</wfw:commentRss>
		</item>
		<item>
		<title>A new way to deploy web applications</title>
		<link>http://blog.ianbicking.org/2010/01/29/new-way-to-deploy-web-apps/</link>
		<comments>http://blog.ianbicking.org/2010/01/29/new-way-to-deploy-web-apps/#comments</comments>
		<pubDate>Fri, 29 Jan 2010 20:21:57 +0000</pubDate>
		<dc:creator>Ian Bicking</dc:creator>
		
		<category><![CDATA[Packaging]]></category>

		<category><![CDATA[Programming]]></category>

		<category><![CDATA[Python]]></category>

		<category><![CDATA[Silver Lining]]></category>

		<category><![CDATA[Web]]></category>

		<guid isPermaLink="false">http://blog.ianbicking.org/?p=132</guid>
		<description><![CDATA[
Deployment is one of the things I like least about development, and yet without deployment the development doesn&#8217;t really matter.
I&#8217;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 &#34;scaling&#34;, [...]]]></description>
			<content:encoded><![CDATA[<div class="document">
<p>Deployment is one of the things I like least about development, and yet without deployment the development doesn&#8217;t really matter.</p>
<p>I&#8217;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 &quot;scaling&quot;, 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&#8217;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&#8230; 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&#8217;t hit some wall later.  And frankly working around the platform is tiring and not very rewarding.</p>
<hr class="docutils" />
<p>So&#8230; App Engine seemed neat, but I couldn&#8217;t use it, and deployment was still a problem.</p>
<p>What I like about App Engine: an application is just files.  There&#8217;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 &quot;the cloud&quot;.  It took me a while to get a handle on what &quot;cloud computing&quot; really means.  What I learned: don&#8217;t overthink it.  It&#8217;s not magic.  It&#8217;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&#8217;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&#8217;t need a pool of ready servers because the cloud service basically manages that pool of ready servers for you.</p>
<p>Without &quot;cloud computing&quot; 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&#8217;t know what exactly I wanted to do to start, and I&#8217;m not completely sure where I&#8217;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 &quot;application&quot; (let&#8217;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&#8217;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&#8217;ll get those configuration-related environmental variables.  This means your application configuration is always present, your services always available.  It&#8217;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&#8217;s an implementation detail you can actually <em>look</em> at and change (by changing toppcloud), but it&#8217;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 &quot;cloud&quot; part actually ends.  If you want to install a bare Ubuntu onto an existing physical machine that&#8217;s fine too &#8212; after <tt class="docutils literal"><span class="pre">toppcloud</span> <span class="pre">create-node</span></tt> the &quot;cloud&quot; part of the process is pretty much done.  Just don&#8217;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">&#8211;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&#8217;s a few other things &#8212; stuff to manage the servers and change around hostnames or the active version of applications.  It&#8217;s growing to fit a variety of workflows, but I don&#8217;t think its growth is unbounded.</p>
<hr class="docutils" />
<p>So&#8230; this is what toppcloud.  From the outside it doen&#8217;t do a lot.  From the inside it&#8217;s not actually that complicated either.  I&#8217;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&#8217;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&#8217;t care.</li>
<li>There is no option for the way your application is run &#8212; there&#8217;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 &#8212; but we shouldn&#8217;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&#8217;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&#8217;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 &quot;building&quot; 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&#8217;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&#8217;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&#8217;ve seen in a lot of &quot;cloud&quot; tools) this encorporates both the development environment and production environment; but unlike some developer-oriented systems this does not try to normalize everyone&#8217;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&#8217;s not all constraints.  Toppcloud is solidly web framework neutral.  It&#8217;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 &quot;scalable systems&quot;; 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&#8217;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&#8217;ve made a lot of sideways attacks on deployment, and a few direct attacks&#8230; 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&#8230;</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&#8217;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&#8217;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&#8217;d like to help that happen.  But I can&#8217;t do that by bootstrapping it through unending support, because I&#8217;m not good at it and I&#8217;m not consistent and it&#8217;s unrealistic and unsustainable.  This is not a open source dead drop.  But it&#8217;s also not My Future; I&#8217;m not going to build a company around it, and I&#8217;m not going to use all my free time supporting it.  It&#8217;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>
]]></content:encoded>
			<wfw:commentRss>http://blog.ianbicking.org/2010/01/29/new-way-to-deploy-web-apps/feed/</wfw:commentRss>
		</item>
	</channel>
</rss>

<!-- Dynamic Page Served (once) in 3.873 seconds -->
<!-- Cached page served by WP-Cache -->
