<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss'><id>tag:blogger.com,1999:blog-5733547231775030285</id><updated>2010-03-12T04:25:36.561+11:00</updated><title type='text'>Mere Code</title><subtitle type='html'>Hacking, Software Collaboration, Testing and Diverse Other Topics of General Interest to the Practicing Programmer</subtitle><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5733547231775030285/posts/default'/><link rel='alternate' type='text/html' href='http://code.mumak.net/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><link rel='next' type='application/atom+xml' href='http://www.blogger.com/feeds/5733547231775030285/posts/default?start-index=26&amp;max-results=25'/><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://code.mumak.net/atom.xml'/><author><name>jml</name><uri>http://www.blogger.com/profile/11400080716012026985</uri><email>noreply@blogger.com</email></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>120</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-5733547231775030285.post-7176896161811557970</id><published>2010-03-12T04:17:00.002+11:00</published><updated>2010-03-12T04:25:36.577+11:00</updated><title type='text'>Have you tried lptools?</title><content type='html'>Have you tried &lt;a href="https://edge.launchpad.net/lptools"&gt;lptools&lt;/a&gt;?&lt;br /&gt;&lt;br /&gt;It's not at all officially associated with the Launchpad project, of course, but it's got a few nice things that you might want to look at, including:&lt;div&gt;&lt;ul&gt;&lt;li&gt;a milestone manipulator&lt;/li&gt;&lt;li&gt;a code review notifier, and&lt;/li&gt;&lt;li&gt;a milestone to iCal exporter&lt;/li&gt;&lt;/ul&gt;One of these days, I'd like for there to be an official, awesome Launchpad command-line client. As it is, I'm happy with the world of people making extensions to meet their needs.&lt;br /&gt;&lt;br /&gt;For other extensions, check out the &lt;a href="https://launchpad.net/lpx"&gt;lpx project&lt;/a&gt; or our &lt;a href="http://help.launchpad.net/Clients"&gt;list of clients&lt;/a&gt;.&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5733547231775030285-7176896161811557970?l=code.mumak.net' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/5733547231775030285/7176896161811557970/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=5733547231775030285&amp;postID=7176896161811557970' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5733547231775030285/posts/default/7176896161811557970'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5733547231775030285/posts/default/7176896161811557970'/><link rel='alternate' type='text/html' href='http://code.mumak.net/2010/03/have-you-tried-lptools.html' title='Have you tried lptools?'/><author><name>jml</name><uri>http://www.blogger.com/profile/11400080716012026985</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='06159200095703820658'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5733547231775030285.post-4852477932475774813</id><published>2010-03-11T05:54:00.002+11:00</published><updated>2010-03-11T05:59:39.227+11:00</updated><title type='text'>launchpadlib powerup</title><content type='html'>In my last post, I &lt;a href="http://code.mumak.net/2010/03/get-started-with-launchpadlib.html"&gt;introduced launchpadlib&lt;/a&gt; and demonstrated a very simple script that uses it. In this post, I'd like to build on that a bit and show you how to do something actually interesting.&lt;br /&gt;&lt;br /&gt;In particular, I want to show you how to search for bugs, teach you a bit about Launchpad's internal data model and help you help yourself when it comes to figuring out Launchpad APIs.&lt;br /&gt;&lt;br /&gt;The script at &lt;a href="https://code.edge.launchpad.net/~jml/+junk/bugstats"&gt;lp:~jml/+junk/bugstats&lt;/a&gt; is designed to tell you how good you are at filing bugs. It uses a very simple metric: out of the bugs that you've filed, how many actually have been fixed.&lt;pre&gt;$ ./bugstats.py ubuntu jml&lt;br /&gt;jml is 22.22% successful on bugs in Ubuntu&lt;br /&gt;$ ./bugstats.py launchpad-code jml&lt;br /&gt;jml is 47.63% successful on bugs in Launchpad Code&lt;/pre&gt;To do that, we need to:&lt;ol&gt;&lt;li&gt;get the "project" and person referred to on the command line&lt;/li&gt;&lt;li&gt;search for all fixed bugs filed by that person&lt;/li&gt;&lt;li&gt;search for all bugs in total by that same person&lt;/li&gt;&lt;li&gt;count them both&lt;/li&gt;&lt;li&gt;divide them&lt;/li&gt;&lt;li&gt;print them!&lt;/li&gt;&lt;/ol&gt;I say "project", but I really should say "pillar", which is the Launchpad technical term for a project (e.g. "bzr"), distribution (e.g. "ubuntu") or project group (e.g. "gnome"). A pillar is anything in first part of Launchpad URL that isn't a person.&lt;br /&gt;&lt;br /&gt;We get the pillar and person like this:&lt;pre&gt;   pillar = launchpad.projects[pillar_name]&lt;br /&gt;  reporter = launchpad.people[reporter_name]&lt;/pre&gt;Pretty easy, huh? Now, how do we search for bug tasks?&lt;br /&gt;&lt;br /&gt;The first port of call is to go to the &lt;a href="https://launchpad.net/+apidoc"&gt;Launchpad API reference&lt;/a&gt; page. I'm going to look for the string 'reporter', since that's the one thing I definitely know I want to find.&lt;br /&gt;&lt;br /&gt;Eventually, I found the &lt;code&gt;searchTasks&lt;/code&gt; method (named operation) that's on pillars and takes a &lt;code&gt;bug_reporter&lt;/code&gt; parameter and a &lt;code&gt;status&lt;/code&gt; parameter. It returns a collection of &lt;code&gt;bug_tasks&lt;/code&gt;, which are the objects that represent the rows in the table you see at the top of a bug page.&lt;br /&gt;&lt;br /&gt;I can find the bugtasks for the bugs I've reported that have been fixed by doing:&lt;pre&gt;   fixed_bugtasks = pillar.searchTasks(&lt;br /&gt;      bug_reporter=reporter, status=['Fix Released'])&lt;/pre&gt;It took me a while to figure out exactly how to spell "Fix Released". I ended up using trial and error.&lt;br /&gt;&lt;br /&gt;Similarly, I can all the bugtasks for bugs I've filed by doing:&lt;pre&gt;   total_bugtasks = pillar.searchTasks(&lt;br /&gt;      bug_reporter=reporter,&lt;br /&gt;      status=[&lt;br /&gt;          "New",&lt;br /&gt;          "Incomplete",&lt;br /&gt;          "Invalid",&lt;br /&gt;          "Won't Fix",&lt;br /&gt;          "Confirmed",&lt;br /&gt;          "Triaged",&lt;br /&gt;          "In Progress",&lt;br /&gt;          "Fix Committed",&lt;br /&gt;          'Fix Released'])&lt;/pre&gt;I cheated a bit for that one and looked at the launchpad code to get a list of all bug statusus. The default for &lt;code&gt;searchTasks&lt;/code&gt; is to only return open bugs.&lt;br /&gt;&lt;br /&gt;Once we've got the collections of bug tasks, we need to get their counts. In an ideal world, it would be &lt;code&gt;len(total_bugtasks)&lt;/code&gt;, but sadly &lt;a href="https://bugs.edge.launchpad.net/launchpadlib/+bug/274074"&gt;bug 274074&lt;/a&gt; means that &lt;code&gt;len&lt;/code&gt; is really, really slow here.&lt;br /&gt;&lt;br /&gt;Instead, I wrote this helper function:&lt;pre&gt;def length(collection):&lt;br /&gt;  # XXX: Workaround bug 274074. Thanks wgrant.&lt;br /&gt;  return int(collection._wadl_resource.representation['total_size'])&lt;/pre&gt;With that, I can calculate &amp;amp; print my success rate at filing bugs:&lt;pre&gt;   percentage = 100.0 * length(fixed_bugtasks) / length(total_bugtasks)&lt;br /&gt;  print "%s is %.2f%% successful on bugs in %s" % (&lt;br /&gt;      reporter.display_name, percentage, pillar.display_name)&lt;/pre&gt;Next up on the API, I'll talk about some of the gotchas and what you can do about them.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5733547231775030285-4852477932475774813?l=code.mumak.net' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/5733547231775030285/4852477932475774813/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=5733547231775030285&amp;postID=4852477932475774813' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5733547231775030285/posts/default/4852477932475774813'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5733547231775030285/posts/default/4852477932475774813'/><link rel='alternate' type='text/html' href='http://code.mumak.net/2010/03/launchpadlib-powerup.html' title='launchpadlib powerup'/><author><name>jml</name><uri>http://www.blogger.com/profile/11400080716012026985</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='06159200095703820658'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5733547231775030285.post-6198000166834539317</id><published>2010-03-10T00:34:00.003+11:00</published><updated>2010-03-10T21:43:38.322+11:00</updated><title type='text'>Get started with launchpadlib</title><content type='html'>In my spare time, I sometimes talk to people about how they can get started with launchpadlib hacking.&lt;br /&gt;&lt;br /&gt;launchpadlib is the Python client-side library that talks to Launchpad's own &lt;a href="http://en.wikipedia.org/wiki/Representational_State_Transfer"&gt;REST&lt;/a&gt; API. It turns out that customize scripted control of a &lt;a href="https://launchpad.net/"&gt;bug-tracker-code-hosting-translation-distribution-building-cross-project-collaboration thing&lt;/a&gt; is actually quite handy.&lt;br /&gt;&lt;br /&gt;If you want to get started hacking with launchpadlib, and you have Ubuntu, then install 'python-launchpadlib' now. I'm pretty sure you can also get it from PyPI.&lt;br /&gt;&lt;br /&gt;You can check that it works by running:&lt;span class="Apple-style-span"   style="font-family:monospace;font-size:100%;"&gt;&lt;span class="Apple-style-span"  style=" white-space: pre;font-size:13px;"&gt;&lt;span class="Apple-style-span"   style="font-family:Georgia, serif;font-size:130%;"&gt;&lt;span class="Apple-style-span"  style=" white-space: normal;font-size:14px;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;pre&gt;$ python&lt;br /&gt;&gt;&gt;&gt; import launchpadlib&lt;br /&gt;&gt;&gt;&gt; launchpadlib.__version__&lt;br /&gt;'1.5.1'&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;I'll be assuming you're running 1.5.1 or later.&lt;br /&gt;&lt;br /&gt;I've written a very simple launchpadlib application that you can get with 'bzr branch lp:~jml/+junk/bugstats'. Each revision shows a meaningful launchpadlib script. You can get at the old revisions with 'bzr revert -r1' or 'bzr revert -r2' or '-r3'.&lt;br /&gt;&lt;br /&gt;Here's what the simplest launchpadlib script that I could think of looks like:&lt;br /&gt;&lt;pre&gt;import os&lt;br /&gt;import sys&lt;br /&gt;from launchpadlib.launchpad import Launchpad, STAGING_SERVICE_ROOT&lt;br /&gt;&lt;br /&gt;APP_NAME = 'jml-bug-stats'&lt;br /&gt;CACHE_DIR = os.path.expanduser('~/.launchpadlib/cache')&lt;br /&gt;SERVICE_ROOT = STAGING_SERVICE_ROOT&lt;br /&gt;&lt;br /&gt;launchpad = Launchpad.login_with(APP_NAME, SERVICE_ROOT, CACHE_DIR)&lt;br /&gt;print launchpad.bugs[1].title&lt;br /&gt;&lt;/pre&gt;(Adapted from r2 of the above branch).&lt;br /&gt;&lt;br /&gt;A few points.&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;We use &lt;code&gt;STAGING_SERVICE_ROOT&lt;/code&gt;, which means that we're pointing&lt;br /&gt;at &lt;a href="https://staging.launchpad.net/"&gt;Launchpad's staging service&lt;/a&gt;,&lt;br /&gt;just in case we screw up any data.&lt;/li&gt;&lt;br /&gt;&lt;li&gt;We give the application a name, when you run the application, launchpadlib&lt;br /&gt;opens up a browser window letting &lt;i&gt;you&lt;/i&gt; decide how far the application&lt;br /&gt;can act on &lt;i&gt;your&lt;/i&gt; behalf.&lt;/li&gt;&lt;li&gt;We provide a cache directory. Credentials, among other things, get stored&lt;br /&gt;here.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;We then login and get an object that represents a Launchpad instance&lt;/li&gt;&lt;li&gt;Once we've got it, we look at the collection of bugs, get Bug #1 and then&lt;br /&gt;print the title&lt;/li&gt;&lt;/ul&gt;Very simple. To learn how to write this application, I looked at the main &lt;a href="https://help.launchpad.net/API"&gt;Launchpad API help&lt;/a&gt; page, the&lt;br /&gt;&lt;a href="https://help.launchpad.net/API/Examples"&gt;examples&lt;/a&gt; page and the &lt;a href="https://staging.launchpad.net/+apidoc"&gt;reference documentation&lt;/a&gt;. You'll notice that I had to translate the reference documentation from REST-speak into Python-speak.&lt;br /&gt;&lt;br /&gt;Already you have enough to go exploring with the Launchpad API and think of cool things to do. A bunch of people are already doing &lt;a href="https://help.launchpad.net/Clients"&gt;cool stuff&lt;/a&gt; and there are many &lt;a href="https://help.launchpad.net/API/Uses"&gt;projects that use launchpadlib&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Next up, I hope to show you some more complex things you can do with the API.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5733547231775030285-6198000166834539317?l=code.mumak.net' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/5733547231775030285/6198000166834539317/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=5733547231775030285&amp;postID=6198000166834539317' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5733547231775030285/posts/default/6198000166834539317'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5733547231775030285/posts/default/6198000166834539317'/><link rel='alternate' type='text/html' href='http://code.mumak.net/2010/03/get-started-with-launchpadlib.html' title='Get started with launchpadlib'/><author><name>jml</name><uri>http://www.blogger.com/profile/11400080716012026985</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='06159200095703820658'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5733547231775030285.post-3149808529693543409</id><published>2010-03-08T23:25:00.002+11:00</published><updated>2010-03-08T23:27:54.177+11:00</updated><title type='text'>Monitor &amp; keyboard</title><content type='html'>I want to get a shiny new monitor and keyboard. The monitor is for coding, writing docs, answering emails and watching films. The keyboard is for same. They'll both plug into my Thinkpad X200 for now.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I'm tempted to get an Apple Cinema Display (but at such cost!). I don't know what keyboard I want. I think that the DAS keyboard I have isn't it.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Thoughts?&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5733547231775030285-3149808529693543409?l=code.mumak.net' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/5733547231775030285/3149808529693543409/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=5733547231775030285&amp;postID=3149808529693543409' title='12 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5733547231775030285/posts/default/3149808529693543409'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5733547231775030285/posts/default/3149808529693543409'/><link rel='alternate' type='text/html' href='http://code.mumak.net/2010/03/monitor-keyboard.html' title='Monitor &amp; keyboard'/><author><name>jml</name><uri>http://www.blogger.com/profile/11400080716012026985</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='06159200095703820658'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>12</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5733547231775030285.post-325373824797303769</id><published>2010-03-03T20:54:00.002+11:00</published><updated>2010-03-03T20:59:13.720+11:00</updated><title type='text'>Back from PyCon</title><content type='html'>I had a great time at PyCon 2010. The best part was definitely the &lt;a href="http://labs.twistedmatrix.com/2010/03/pycon-2010-sprint-report.html"&gt;Twisted sprint&lt;/a&gt;, which gave me a long overdue opportunity to do some actual coding.&lt;br /&gt;&lt;br /&gt;Well, actually, I ended up spending a lot of the time organizing a release and writing &lt;a href="http://twistedmatrix.com/trac/wiki/ReleaseProcess"&gt;process documents&lt;/a&gt;, so I didn't escape management as much as I would have liked.&lt;br /&gt;&lt;br /&gt;Now I'm back, planning on doing the &lt;a href="http://twistedmatrix.com/trac/ticket/4290"&gt;Twisted 10.0 release&lt;/a&gt; and working with &lt;a href="http://launchpad.net/~didrocks"&gt;didrocks&lt;/a&gt; to get better &lt;a href="http://help.launchpad.net/API"&gt;Launchpad integration&lt;/a&gt; with &lt;a href="http://launchpad.net/quickly"&gt;Quickly&lt;/a&gt;, as my contribution to &lt;a href="http://www.jonobacon.org/2010/02/04/project-awesome-opportunity/"&gt;Project Awesome Opportunity&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5733547231775030285-325373824797303769?l=code.mumak.net' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/5733547231775030285/325373824797303769/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=5733547231775030285&amp;postID=325373824797303769' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5733547231775030285/posts/default/325373824797303769'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5733547231775030285/posts/default/325373824797303769'/><link rel='alternate' type='text/html' href='http://code.mumak.net/2010/03/back-from-pycon.html' title='Back from PyCon'/><author><name>jml</name><uri>http://www.blogger.com/profile/11400080716012026985</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='06159200095703820658'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5733547231775030285.post-3047169740033600943</id><published>2010-02-22T13:51:00.002+11:00</published><updated>2010-02-22T13:59:52.792+11:00</updated><title type='text'>Twisted 10.0.0pre1 released</title><content type='html'>It's not going to work, it's not the final release, but I'm very pleased to announce that &lt;a href="http://people.canonical.com/~jml/Twisted"&gt;Twisted 10.0.0pre1&lt;/a&gt; is available for testing.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Download it, test it, play with it and help us make 10.0 the best release ever!&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;On a side note, this is hopefully the start of a much simpler, more automated &lt;a href="http://twistedmatrix.com/trac/wiki/ReleaseProcess"&gt;release process&lt;/a&gt; and maybe even time-based releases.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5733547231775030285-3047169740033600943?l=code.mumak.net' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/5733547231775030285/3047169740033600943/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=5733547231775030285&amp;postID=3047169740033600943' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5733547231775030285/posts/default/3047169740033600943'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5733547231775030285/posts/default/3047169740033600943'/><link rel='alternate' type='text/html' href='http://code.mumak.net/2010/02/twisted-1000pre1-released.html' title='Twisted 10.0.0pre1 released'/><author><name>jml</name><uri>http://www.blogger.com/profile/11400080716012026985</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='06159200095703820658'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5733547231775030285.post-4433288930998986553</id><published>2010-02-11T01:00:00.002+11:00</published><updated>2010-02-11T01:13:14.713+11:00</updated><title type='text'>From the Strategist</title><content type='html'>&lt;div&gt;If I don't dump a bunch of stuff that's on my mind, I'll never blog again. Here goes:&lt;/div&gt;&lt;ul&gt;&lt;li&gt;Launchpad users within Canonical seem to appreciate the &lt;a href="https://dev.launchpad.net/RoadMap"&gt;Roadmap&lt;/a&gt;. Still receive some complaints about not communicating our plans enough, but not sure what to do.&lt;/li&gt;&lt;li&gt;Team lead meeting in London went well. Good to see the gang again.&lt;/li&gt;&lt;li&gt;The Wellington sprint was amazing. Rarely seen a sprint that's more productive.&lt;/li&gt;&lt;li&gt;My favourite result: a fixed, pre-planned annual schedule of sprints, including &lt;i&gt;two&lt;/i&gt; annual whole-team sprints. I get to meet with my colleagues &lt;i&gt;and&lt;/i&gt; have a life and Canonical saves money all at once.&lt;/li&gt;&lt;li&gt;The team leads like the &lt;a href="https://dev.launchpad.net/ReadyToCode"&gt;Ready-to-Code&lt;/a&gt; and &lt;a href="https://dev.launchpad.net/LaunchpadEnhancementProposalProcess"&gt;Launchpad Enhancement Proposal&lt;/a&gt; process things.&lt;/li&gt;&lt;li&gt;Daily builds work is going well. There's a lot of UI bits to consider, and we're trying to get the UI correct before building it. Grates my JFDI nerves, but maybe it's the right approach.&lt;/li&gt;&lt;li&gt;Challenged the Launchpad team leads to blog once every two weeks about anything, as long as it's vaguely related to Launchpad. The name of the challenge? Blog like it's 2006.&lt;/li&gt;&lt;li&gt;&lt;a href="https://help.launchpad.net/HelpRotation"&gt;Community Help Rotation&lt;/a&gt; sucks and basically no-one really knows what to do about it.&lt;/li&gt;&lt;li&gt;I'm cautiously excited about using kanban to track our work-in-progress.&lt;/li&gt;&lt;li&gt;Launchpad needs graphs in the Launchpad application. I think all we need is someone to just add one. I don't have the time to do it as part of my day job, and I've got a backlog of other hacking tasks. Could I help you do it instead?&lt;/li&gt;&lt;li&gt;I'm going to PyCon.&lt;/li&gt;&lt;/ul&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5733547231775030285-4433288930998986553?l=code.mumak.net' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/5733547231775030285/4433288930998986553/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=5733547231775030285&amp;postID=4433288930998986553' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5733547231775030285/posts/default/4433288930998986553'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5733547231775030285/posts/default/4433288930998986553'/><link rel='alternate' type='text/html' href='http://code.mumak.net/2010/02/from-strategist.html' title='From the Strategist'/><author><name>jml</name><uri>http://www.blogger.com/profile/11400080716012026985</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='06159200095703820658'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5733547231775030285.post-8608109106301955376</id><published>2010-01-26T22:13:00.002+11:00</published><updated>2010-01-26T22:17:53.690+11:00</updated><title type='text'>Black out</title><content type='html'>I've been a bit slack and have yet to black out my website or avatar to protest the Australian government's mandatory Internet censorship policy.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;In case circumstances prevent me from doing so, please read the &lt;a href="http://www.internetblackout.com.au/"&gt;Internet Blackout Australia&lt;/a&gt; website to see why it's so important. You might also want to read &lt;a href="http://blemings.org/hugh/blog/blosxom.cgi/2010/01/25#20100125a"&gt;Hugh Blemings' well-written thoughts&lt;/a&gt; on the matter.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5733547231775030285-8608109106301955376?l=code.mumak.net' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/5733547231775030285/8608109106301955376/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=5733547231775030285&amp;postID=8608109106301955376' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5733547231775030285/posts/default/8608109106301955376'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5733547231775030285/posts/default/8608109106301955376'/><link rel='alternate' type='text/html' href='http://code.mumak.net/2010/01/black-out.html' title='Black out'/><author><name>jml</name><uri>http://www.blogger.com/profile/11400080716012026985</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='06159200095703820658'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5733547231775030285.post-7026377911891784894</id><published>2010-01-25T18:16:00.001+11:00</published><updated>2010-01-25T18:17:35.945+11:00</updated><title type='text'>Electronic book reader?</title><content type='html'>On &lt;a href="http://life.mumak.net"&gt;my other blog&lt;/a&gt;, I ask about &lt;a href="http://life.mumak.net/2010/01/electronic-book-reader.html"&gt;electronic book readers&lt;/a&gt;. Recommendations greatly desired.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5733547231775030285-7026377911891784894?l=code.mumak.net' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/5733547231775030285/7026377911891784894/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=5733547231775030285&amp;postID=7026377911891784894' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5733547231775030285/posts/default/7026377911891784894'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5733547231775030285/posts/default/7026377911891784894'/><link rel='alternate' type='text/html' href='http://code.mumak.net/2010/01/electronic-book-reader.html' title='Electronic book reader?'/><author><name>jml</name><uri>http://www.blogger.com/profile/11400080716012026985</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='06159200095703820658'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5733547231775030285.post-9085047783759028579</id><published>2010-01-05T11:07:00.003+11:00</published><updated>2010-01-05T11:21:29.861+11:00</updated><title type='text'>Python testing goodies</title><content type='html'>Just found out that there's &lt;a href="https://edge.launchpad.net/~subunit/+archive/ppa"&gt;a PPA with the latest releases of a whole bunch of Python testing goodies&lt;/a&gt;, including:&lt;div&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="https://launchpad.net/testtools"&gt;testtools&lt;/a&gt; - Extensions to unittest that make real extensions possible&lt;/li&gt;&lt;li&gt;&lt;a href="https://launchpad.net/testresources"&gt;testresources&lt;/a&gt; - Safely re-use expensive resources in tests without paying massive set-up costs&lt;/li&gt;&lt;li&gt;&lt;a href="https://launchpad.net/subunit"&gt;subunit&lt;/a&gt; - Manipulate, exchange and analyze test results without writing code&lt;/li&gt;&lt;li&gt;&lt;a href="https://launchpad.net/testscenarios"&gt;testscenarios&lt;/a&gt; - Run the same tests against many different implementations&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;If you are running Ubuntu 9.10 or later, then &lt;code&gt;sudo add-apt-repository ppa:subunit&lt;/code&gt; will add it to your apt sources.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;We're starting to grow a lot of useful, small testing tools that become even more useful when combined. I really like the "small pieces, loosely joined" approach, but sometimes that can make deployment &amp;amp; dependency management a colossal pain. Happily, Ubuntu, &lt;a href="http://rbtcollins.wordpress.com/"&gt;Rob&lt;/a&gt; and &lt;a href="https://edge.launchpad.net/ubuntu/+ppas"&gt;Launchpad PPAs&lt;/a&gt; to the rescue.&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5733547231775030285-9085047783759028579?l=code.mumak.net' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/5733547231775030285/9085047783759028579/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=5733547231775030285&amp;postID=9085047783759028579' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5733547231775030285/posts/default/9085047783759028579'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5733547231775030285/posts/default/9085047783759028579'/><link rel='alternate' type='text/html' href='http://code.mumak.net/2010/01/python-testing-goodies.html' title='Python testing goodies'/><author><name>jml</name><uri>http://www.blogger.com/profile/11400080716012026985</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='06159200095703820658'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5733547231775030285.post-8878173265240028583</id><published>2009-12-16T09:55:00.002+11:00</published><updated>2009-12-16T10:19:56.667+11:00</updated><title type='text'>testtools 0.9.2 released</title><content type='html'>I've just released &lt;a href="http://pypi.python.org/pypi/testtools/0.9.2"&gt;testtools 0.9.2&lt;/a&gt;, which I firmly believe is the best &lt;a href="https://launchpad.net/testtools"&gt;testtools&lt;/a&gt; release ever. Thanks very much to &lt;a href="http://rbtcollins.wordpress.com/"&gt;Robert Collins&lt;/a&gt; and &lt;a href="http://pybites.blogspot.com/"&gt;Benjamin Peterson&lt;/a&gt; for making it so.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;For the last few releases, we've been working on being more than just a simple aggregation of existing unit testing best practices and tried to do our own experimental extensions.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;These extensions aren't actually all that exciting by themselves. We haven't added better logging support or new types of outcomes or test replay or smart rendering of error results or anything like that. I'm pretty sure testtools will never do those sorts of things.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Rather, the extensions we've added are designed to let &lt;i&gt;you&lt;/i&gt; do that, and then share &lt;i&gt;your&lt;/i&gt; extensions with other people without getting them into the standard library's base &lt;code&gt;unittest&lt;/code&gt; classes.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;If you are using testtools, you can change the way &lt;code&gt;TestCase.run()&lt;/code&gt; works without overriding run and without figuring out how to safely call user code. You can handle exceptions raised from tests however you'd like — again not needing to change &lt;code&gt;TestCase.run()&lt;/code&gt;. You can add new, rich types of assertions without having to modify some base class somewhere. You can store information on a test object that can be used by a sufficiently smart &lt;code&gt;TestResult&lt;/code&gt;, which can be handy if you want to see, say, access logs for all failed tests.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Of course, all this starts to get really powerful when testtools is in the standard library, and all of the other major Python test frameworks inherit from it: nose, py.test, zope.testing and Twisted Trial.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Even so, it's worth switching to testtools today, just for the assertion logic alone. All it takes is changing the base class of your test cases to &lt;code&gt;testtools.TestCase&lt;/code&gt;. If your test framework supports running standard Python unit tests, it'll support testtools.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5733547231775030285-8878173265240028583?l=code.mumak.net' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/5733547231775030285/8878173265240028583/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=5733547231775030285&amp;postID=8878173265240028583' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5733547231775030285/posts/default/8878173265240028583'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5733547231775030285/posts/default/8878173265240028583'/><link rel='alternate' type='text/html' href='http://code.mumak.net/2009/12/testtools-092-released.html' title='testtools 0.9.2 released'/><author><name>jml</name><uri>http://www.blogger.com/profile/11400080716012026985</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='06159200095703820658'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5733547231775030285.post-1282121015269802629</id><published>2009-11-28T03:50:00.003+11:00</published><updated>2009-11-28T04:07:46.098+11:00</updated><title type='text'>Lean Lean</title><content type='html'>Ever been confused by people saying "this is Lean" or "that is Lean" or "we should actually be using a cyclometric value-stream set-based burndown kanban for this"? I have, so I thought I'd write a quick pared-down cheat sheet to explain exactly what Lean is. A lean version of Lean, if you will.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;At the very least, Lean is seven principles which, we're told, we should apply to making software.&lt;/div&gt;&lt;div&gt;&lt;ol&gt;&lt;li&gt;Eliminate waste&lt;/li&gt;&lt;li&gt;Amplify learning&lt;/li&gt;&lt;li&gt;Decide as late as possible&lt;/li&gt;&lt;li&gt;Deliver as fast as possible&lt;/li&gt;&lt;li&gt;Empower the team&lt;/li&gt;&lt;li&gt;Build integrity in&lt;/li&gt;&lt;li&gt;See the whole&lt;/li&gt;&lt;/ol&gt;&lt;div&gt;The first principle is fundamental.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;List taken from &lt;a href="http://www.poppendieck.com/"&gt;Lean Software Development&lt;/a&gt;.&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5733547231775030285-1282121015269802629?l=code.mumak.net' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/5733547231775030285/1282121015269802629/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=5733547231775030285&amp;postID=1282121015269802629' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5733547231775030285/posts/default/1282121015269802629'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5733547231775030285/posts/default/1282121015269802629'/><link rel='alternate' type='text/html' href='http://code.mumak.net/2009/11/lean-lean.html' title='Lean Lean'/><author><name>jml</name><uri>http://www.blogger.com/profile/11400080716012026985</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='06159200095703820658'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5733547231775030285.post-7400062221229974167</id><published>2009-11-27T20:12:00.003+11:00</published><updated>2009-11-27T22:50:54.776+11:00</updated><title type='text'>How to ask an open source project to do something</title><content type='html'>This isn't exhaustive, but I think there are two ways to ask an open source project to do something:&lt;div&gt;&lt;ol&gt;&lt;li&gt;I want X. You should do X.&lt;/li&gt;&lt;li&gt;I want X. How can I help do X?&lt;/li&gt;&lt;/ol&gt;&lt;/div&gt;&lt;div&gt;I have no data, but I think that asking the second way is what makes open source actually work.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5733547231775030285-7400062221229974167?l=code.mumak.net' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/5733547231775030285/7400062221229974167/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=5733547231775030285&amp;postID=7400062221229974167' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5733547231775030285/posts/default/7400062221229974167'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5733547231775030285/posts/default/7400062221229974167'/><link rel='alternate' type='text/html' href='http://code.mumak.net/2009/11/how-to-ask-open-source-project-to.html' title='How to ask an open source project to do something'/><author><name>jml</name><uri>http://www.blogger.com/profile/11400080716012026985</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='06159200095703820658'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5733547231775030285.post-6729277015900487726</id><published>2009-11-26T20:22:00.002+11:00</published><updated>2009-11-26T22:16:49.008+11:00</updated><title type='text'>To do: To dos (Palm Prē)</title><content type='html'>You might already know that I have a lot of &lt;span style="font-style: italic;"&gt;lists&lt;/span&gt; on my computer. I may have mentioned once or twice that I have such lists. These lists are connected to a certain popular productivity system which isn't really about productivity and is a little bit like a cult.&lt;br /&gt;&lt;br /&gt;I might have also mentioned that I've been longing for a "smart" phone, partly so I can have these lists with me at all times, to clutch at reflexively like some Popish talisman.&lt;br /&gt;&lt;br /&gt;Now that I have a Palm Prē I have lists and a smart phone, and yet one does not know the other. I am at a loss as to how to get my lists — line-separated text files on my laptop — onto the Tasks application on the Palm. Even then, once they are on the Palm, I have no idea as to how to get them synchronized with something I can edit from my laptop.&lt;br /&gt;&lt;br /&gt;Any ideas?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5733547231775030285-6729277015900487726?l=code.mumak.net' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/5733547231775030285/6729277015900487726/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=5733547231775030285&amp;postID=6729277015900487726' title='10 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5733547231775030285/posts/default/6729277015900487726'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5733547231775030285/posts/default/6729277015900487726'/><link rel='alternate' type='text/html' href='http://code.mumak.net/2009/11/to-do-to-dos-palm-pre.html' title='To do: To dos (Palm Prē)'/><author><name>jml</name><uri>http://www.blogger.com/profile/11400080716012026985</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='06159200095703820658'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>10</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5733547231775030285.post-4483019994524041747</id><published>2009-11-24T23:31:00.002+11:00</published><updated>2009-11-24T23:36:24.227+11:00</updated><title type='text'>Palm Prē reflections</title><content type='html'>I got a Palm Prē yesterday. Here are some initial thoughts.&lt;div&gt;&lt;ul&gt;&lt;li&gt;I like the feel of the physical device&lt;/li&gt;&lt;li&gt;The keyboard is small&lt;/li&gt;&lt;li&gt;Camera is useless for taking photos of receipts&lt;/li&gt;&lt;li&gt;The gesture UI is great&lt;/li&gt;&lt;li&gt;The Mail application shows individual emails, rather than GMail-style conversations. Lame.&lt;/li&gt;&lt;li&gt;I don't know how to get my lists out of text files on my computer and onto the Palm&lt;/li&gt;&lt;li&gt;I don't know actually know anything about syncing from the Palm&lt;/li&gt;&lt;li&gt;I still don't regret not getting an iPhone&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5733547231775030285-4483019994524041747?l=code.mumak.net' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/5733547231775030285/4483019994524041747/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=5733547231775030285&amp;postID=4483019994524041747' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5733547231775030285/posts/default/4483019994524041747'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5733547231775030285/posts/default/4483019994524041747'/><link rel='alternate' type='text/html' href='http://code.mumak.net/2009/11/palm-pre-reflections.html' title='Palm Prē reflections'/><author><name>jml</name><uri>http://www.blogger.com/profile/11400080716012026985</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='06159200095703820658'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5733547231775030285.post-7710940222452990092</id><published>2009-11-23T22:48:00.002+11:00</published><updated>2009-11-23T23:00:42.134+11:00</updated><title type='text'>UDS</title><content type='html'>&lt;div&gt;I'm back in London after a mammoth two weeks travelling the globe bringing &lt;a href="https://launchpad.net"&gt;Launchpad&lt;/a&gt; joy to its four corners.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;First up I went to Mooloolaba, Australia. If you're Australian, you probably know how to pronounce it. If you aren't, you'll probably never get it. Sorry.&lt;/div&gt;&lt;div&gt;I was there with the Canonical Bazaar team and some other Launchpadders, talking about their next few months of development. They are going to be focusing on helping Launchpad and the Ubuntu platform team work on our daily build initiative. Hmm. I really need a place to link to for that last one, don't I?&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Mooloolaba is a beautiful place to be in November. If you are thinking of giving me something for Christmas, consider a holiday apartment there.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;After Mooloolaba, I crossed the Pacific to reach Dallas, home of the twenty-eight lane highway. I didn't really get into the city that much, but man, &lt;a href="https://wiki.ubuntu.com/UDS-L?action=show&amp;amp;redirect=UDS"&gt;UDS&lt;/a&gt; was great.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Most of the people there are directly involved in Ubuntu development. It's such a joy to see so many people from all over the world come together to work on Ubuntu, and an honour to think that I have a place in that work.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I spent most of the conference flitting from room to room, going to sessions about the Ubuntu development process, &lt;a href="https://wiki.ubuntu.com/DailyBuilds"&gt;daily builds&lt;/a&gt; and the &lt;a href="https://wiki.ubuntu.com/SoftwareCenter"&gt;Software Centre&lt;/a&gt;. Occasionally, I cheated a bit and went to a random session that interested me. Mostly it was about &lt;a href="https://launchpad.net/quickly"&gt;Quickly&lt;/a&gt;.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;As a Launchpad developer, one of the most exciting things about this UDS was seeing that Ubuntu developers have started building &lt;a href="https://help.launchpad.net/API/Uses"&gt;their own tools around Launchpad using our API&lt;/a&gt;. Many of these tools are things we'd love to integrate with the main web app, but many are things that are &lt;i&gt;so&lt;/i&gt; Ubuntu policy specific that we're happy to leave them outside. After all, this is exactly&lt;/div&gt;&lt;div&gt;what the API is about.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I did a short plenary session where I hacked up &lt;a href="https://code.edge.launchpad.net/~jml/+junk/bugstats"&gt;an API script&lt;/a&gt; using &lt;a href="https://help.launchpad.net/API/launchpadlib"&gt;launchpadlib&lt;/a&gt; and demonstrated it live. After the presentation, many people came up to me and started talking about their API-using programs and their experience making them. The amount of interest really surprised me.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I also ran a couple of workshop / discussions. The first was on improving Launchpad for API use, which was a bit disorganized, since I didn't realize I was supposed to be running it. The second was on getting started with Launchpad hacking.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;For the "Getting started with Launchpad hacking" session, I passed around a USB stick, and asked the audience for an API within Launchpad to expose. &lt;a href="http://mdzlog.alcor.net/"&gt;mdz&lt;/a&gt; suggested "blueprints", so I went to expose the 'drafter' element of a specification. In front of a room full of people. Sheesh.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;If you think pair programming is hard (it is, and if you think it isn't you are either doing it wrong or you have extremely helpful colleagues), programming in front of a room full of people is harder.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Still, we managed to actually expose the API and &lt;a href="https://code.edge.launchpad.net/~jml/launchpad/expose-blueprints/+merge/15060"&gt;propose the branch for merging&lt;/a&gt; with only a little bit of evil.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The point of the session was to get people set up with Launchpad development environments, to show them how to even begin to expose a method over the API but even more than that, to give people a little push into just giving Launchpad development a try. By blundering my way into a valid patch, I think maybe we succeeded.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Now UDS is over and I'm back in London, jetlagged and exhausted to be sure, but genuinely happy about the plans we have for Launchpad development, and eager to begin to make them happen.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5733547231775030285-7710940222452990092?l=code.mumak.net' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/5733547231775030285/7710940222452990092/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=5733547231775030285&amp;postID=7710940222452990092' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5733547231775030285/posts/default/7710940222452990092'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5733547231775030285/posts/default/7710940222452990092'/><link rel='alternate' type='text/html' href='http://code.mumak.net/2009/11/uds.html' title='UDS'/><author><name>jml</name><uri>http://www.blogger.com/profile/11400080716012026985</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='06159200095703820658'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5733547231775030285.post-3406548594265618981</id><published>2009-11-14T00:26:00.003+11:00</published><updated>2009-11-14T00:26:49.571+11:00</updated><title type='text'>Evil Overlord talks</title><content type='html'>My "Hack Like an Evil Overlord" talks are now linked from my &lt;a href="http://mumak.net/stuff"&gt;stuff&lt;/a&gt; page.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5733547231775030285-3406548594265618981?l=code.mumak.net' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/5733547231775030285/3406548594265618981/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=5733547231775030285&amp;postID=3406548594265618981' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5733547231775030285/posts/default/3406548594265618981'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5733547231775030285/posts/default/3406548594265618981'/><link rel='alternate' type='text/html' href='http://code.mumak.net/2009/11/evil-overlord-talks.html' title='Evil Overlord talks'/><author><name>jml</name><uri>http://www.blogger.com/profile/11400080716012026985</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='06159200095703820658'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5733547231775030285.post-8144946741495454609</id><published>2009-11-11T18:57:00.002+11:00</published><updated>2009-11-11T19:16:31.791+11:00</updated><title type='text'>Tests: Costs and Benefits</title><content type='html'>I like unit testing a lot. I've recently been thinking about whether it really is everything that advocates like myself make it out to be. I'm still thinking, but I reckon that language has something to do with it, and that I wouldn't like TDD so much if I were writing in Haskell. Maybe.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Anyway, here are the benefits of unit testing, without justification or explanation:&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;Easier to maintain code&lt;/li&gt;&lt;li&gt;Avoiding regressions&lt;/li&gt;&lt;li&gt;Make API clearer, both by describing it and by encouraging contracts.&lt;/li&gt;&lt;li&gt;Confidence in changes to code&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;For new contributors, there are other benefits:&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;Confidence in changes to code&lt;/li&gt;&lt;li&gt;Confidence in the validity of your own patch&lt;/li&gt;&lt;li&gt;Mechanism for exploring internal system behaviour&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div&gt;Some of the costs are:&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;Maintaining tests&lt;/li&gt;&lt;li&gt;Caring about the performance of tests&lt;/li&gt;&lt;li&gt;Running the tests&lt;/li&gt;&lt;li&gt;Debugging tests&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;For new contributors, there are other costs:&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;Finding tests&lt;/li&gt;&lt;li&gt;Figuring out how to run tests&lt;/li&gt;&lt;li&gt;Figuring out how to write tests&lt;/li&gt;&lt;li&gt;Learn unit testing&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;div&gt;Is this fair? Is this clear? And exactly where was that post by that guy about unit testing being overrated?&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;On a half-related and slightly exasperated note, many of the conversations I've been having recently have been about costs and benefits. What happened to doing something because it was the right thing?&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5733547231775030285-8144946741495454609?l=code.mumak.net' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/5733547231775030285/8144946741495454609/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=5733547231775030285&amp;postID=8144946741495454609' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5733547231775030285/posts/default/8144946741495454609'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5733547231775030285/posts/default/8144946741495454609'/><link rel='alternate' type='text/html' href='http://code.mumak.net/2009/11/tests-costs-and-benefits.html' title='Tests: Costs and Benefits'/><author><name>jml</name><uri>http://www.blogger.com/profile/11400080716012026985</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='06159200095703820658'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5733547231775030285.post-7442666575343354922</id><published>2009-10-28T03:46:00.002+11:00</published><updated>2009-10-28T04:04:28.947+11:00</updated><title type='text'>Raise your standards</title><content type='html'>I gatecrashed LugRadio Live last Saturday and went to an excellent talk by Matthew Paul Thomas about reporting usability problems. Matthew has reported &lt;a href="https://bugs.edge.launchpad.net/launchpad-project/+bugs?field.searchtext=&amp;amp;orderby=-importance&amp;amp;search=Search&amp;amp;field.status:list=NEW&amp;amp;field.status:list=INCOMPLETE_WITH_RESPONSE&amp;amp;field.status:list=INCOMPLETE_WITHOUT_RESPONSE&amp;amp;field.status:list=INVALID&amp;amp;field.status:list=WONTFIX&amp;amp;field.status:list=CONFIRMED&amp;amp;field.status:list=TRIAGED&amp;amp;field.status:list=INPROGRESS&amp;amp;field.status:list=FIXCOMMITTED&amp;amp;field.status:list=FIXRELEASED&amp;amp;assignee_option=any&amp;amp;field.assignee=&amp;amp;field.bug_reporter=mpt&amp;amp;field.bug_supervisor=&amp;amp;field.bug_commenter=&amp;amp;field.subscriber=&amp;amp;field.omit_dupes.used=&amp;amp;field.omit_dupes=on&amp;amp;field.has_patch.used=&amp;amp;field.has_cve.used=&amp;amp;field.tag=&amp;amp;field.tags_combinator=ANY"&gt;well over a thousand bugs against Launchpad itself&lt;/a&gt; (many of which &lt;a href="https://bugs.edge.launchpad.net/launchpad-project/+bugs?field.searchtext=&amp;amp;orderby=-importance&amp;amp;search=Search&amp;amp;field.status:list=FIXCOMMITTED&amp;amp;field.status:list=FIXRELEASED&amp;amp;assignee_option=any&amp;amp;field.assignee=&amp;amp;field.bug_reporter=mpt&amp;amp;field.bug_supervisor=&amp;amp;field.bug_commenter=&amp;amp;field.subscriber=&amp;amp;field.omit_dupes.used=&amp;amp;field.omit_dupes=on&amp;amp;field.has_patch.used=&amp;amp;field.has_cve.used=&amp;amp;field.tag=&amp;amp;field.tags_combinator=ANY"&gt;have been fixed&lt;/a&gt;) so he knows something about the subject.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Matthew gave six pointers on how to report usability problems, but for me the single most striking one was this:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: center;"&gt;&lt;b&gt;Raise your standards&lt;/b&gt;&lt;/div&gt;&lt;br /&gt;When you are using an application with the aim of improving its usability, you need to shed all of your tolerance and forget those many workarounds you've learned. Drum your fingers impatiently while you wait for something to load. Think of how this would look if you were showing it to a sceptical friend.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The point struck me because so many times as an application &lt;i&gt;developer&lt;/i&gt; I've thought to myself "it's good enough" or "it will work for now". Really though, that's not good enough. I should work until the thing I've added is invisible, or at least fun to use. I need to raise my standards.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Having raised one's standards, the trick is then to avoid the traps of perfectionism. Do you have any thoughts on how to walk the road, avoiding the pitfalls, standards held high?&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5733547231775030285-7442666575343354922?l=code.mumak.net' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/5733547231775030285/7442666575343354922/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=5733547231775030285&amp;postID=7442666575343354922' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5733547231775030285/posts/default/7442666575343354922'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5733547231775030285/posts/default/7442666575343354922'/><link rel='alternate' type='text/html' href='http://code.mumak.net/2009/10/raise-your-standards.html' title='Raise your standards'/><author><name>jml</name><uri>http://www.blogger.com/profile/11400080716012026985</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='06159200095703820658'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5733547231775030285.post-2363169978576622343</id><published>2009-10-20T22:50:00.002+11:00</published><updated>2009-10-20T23:02:11.777+11:00</updated><title type='text'>Bug squashing sprints</title><content type='html'>Every time somebody asks me what I think we should do for a sprint, I try to suggest "fix as many bugs as possible".&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Each of the Launchpad teams gets together in a single location for a week long "sprint" fairly regularly. Maybe each team has two sprints a year.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Often these sprints end up being long talking sessions where designs for features are thrashed out. That's great and all, and sprints are a rare opportunity to do that, but often the design work goes unused for months while the team deals with the work already on its collective plate.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Sometimes these sprints have the whole team working (i.e. coding) toward a single milestone, be it a release or a major feature. These sprints are fun, but they've been quite rare for Launchpad. (Bazaar had a great one in Brisbane earlier this year).&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;What I'd love to see is a sprint where people fixed as many bugs as possible. Perhaps as a product strategist, I ought to be advocating higher-level visions and responding to the market and so forth, rather than saying "fix lots of bugs". But I don't think so, at least, not yet.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Fixing as many bugs as we can in a fixed time frame will make many users happy, since behind each bug is a user in pain. It will make us happy as a team, since a vastly dropped bug count will make us feel less overwhelmed and will feel like a concrete achievement. It's an easy sprint to measure the success of, and my hunch is that it would be a fun sprint too. It's also substantially different to what we normally do, which adds to the fun.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;What do you think? I'd love to hear from people in community-driven open source projects, as well as people within Canonical who aren't in Launchpad. Maybe we're missing something that others know about.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5733547231775030285-2363169978576622343?l=code.mumak.net' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/5733547231775030285/2363169978576622343/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=5733547231775030285&amp;postID=2363169978576622343' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5733547231775030285/posts/default/2363169978576622343'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5733547231775030285/posts/default/2363169978576622343'/><link rel='alternate' type='text/html' href='http://code.mumak.net/2009/10/bug-squashing-sprints.html' title='Bug squashing sprints'/><author><name>jml</name><uri>http://www.blogger.com/profile/11400080716012026985</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='06159200095703820658'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5733547231775030285.post-7350864700495649504</id><published>2009-10-15T21:42:00.003+11:00</published><updated>2009-10-15T21:59:54.584+11:00</updated><title type='text'>Command line apps</title><content type='html'>Back in the day, I used to want to use &lt;a href="http://twistedmatrix.com/projects/core/documentation/howto/options.html"&gt;twisted.python.usage&lt;/a&gt; for all of my command-line apps. It's a fairly nice &lt;a href="http://twistedmatrix.com/documents/8.2.0/api/twisted.python.usage.html"&gt;API&lt;/a&gt; &amp;amp; a good way of writing code.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Since I started writing Bazaar plugins though, I've fallen in love with Bazaar's command interface. &lt;a href="https://code.edge.launchpad.net/~jkakar"&gt;Jamu&lt;/a&gt; has too, so he wrote &lt;a href="https://edge.launchpad.net/commandant"&gt;Commandant&lt;/a&gt;. I don't really understand it though, which is mostly for lack of trying.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Michael turned our internal EC2-using testing tool into a bzr-a-like app &lt;a href="http://bazaar.launchpad.net/~launchpad-pqm/launchpad/stable/annotate/head:/lib/devscripts/ec2test/builtins.py"&gt;using the Bazaar APIs&lt;/a&gt;. There's a bit of duplication, but it works pretty well.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The Bazaar developers are aware that their command-line interface code rocks and that it's too closely bound to Bazaar. I'm not sure whether anyone has filed bugs about it or not, but here's what I actually want:&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;The subcommand interface, e.g. "bzr foo"&lt;/li&gt;&lt;li&gt;Option parsing&lt;/li&gt;&lt;li&gt;Help&lt;/li&gt;&lt;li&gt;Command aliasing&lt;/li&gt;&lt;li&gt;Error handling&lt;/li&gt;&lt;li&gt;Progress display&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;There's also a bunch of cool stuff in Bazaar that's useful for a lot of applications, command-line or not.&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;Registries&lt;/li&gt;&lt;li&gt;Transports&lt;/li&gt;&lt;li&gt;Hooks&lt;/li&gt;&lt;li&gt;Oh yeah, &lt;b&gt;plugins&lt;/b&gt;. (How could I have forgotten this?)&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;Sometimes I wish projects like Bazaar and Twisted split this sort of stuff out into separate packages. That would probably change the way the packages are maintained, and I don't know whether it would be for better or for worse.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Sadly, no moral or action for this post. Just stuff that's been on my mind that I wanted to write down and publish. I'd very much welcome input.&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5733547231775030285-7350864700495649504?l=code.mumak.net' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/5733547231775030285/7350864700495649504/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=5733547231775030285&amp;postID=7350864700495649504' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5733547231775030285/posts/default/7350864700495649504'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5733547231775030285/posts/default/7350864700495649504'/><link rel='alternate' type='text/html' href='http://code.mumak.net/2009/10/command-line-apps.html' title='Command line apps'/><author><name>jml</name><uri>http://www.blogger.com/profile/11400080716012026985</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='06159200095703820658'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5733547231775030285.post-2581147091234827441</id><published>2009-10-15T20:16:00.002+11:00</published><updated>2009-10-15T20:26:47.355+11:00</updated><title type='text'>Launchpad extensions</title><content type='html'>Launchpad has a pretty awesome &lt;a href="http://edge.launchpad.net/+apidoc"&gt;public API&lt;/a&gt;, implemented using &lt;a href="https://launchpad.net/lazr.restful"&gt;lazr.restful&lt;/a&gt;. I've written a few small scripts for it, and the Launchpad team has a few scripts that they use internally for doing admin tasks.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The Ubuntu Platform team does a heap of stuff with the Launchpad API. &lt;a href="http://jameswestby.net/weblog"&gt;James Westby&lt;/a&gt; has been using it to make sure that there's a branch on Launchpad for every single package in Ubuntu.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;There's all this great work, but there's been nothing to tie the room together. I've seen hardly any discussion about how to write Launchpad API applications, or how to test them, or how to get &lt;a href="https://launchpad.net/launchpadlib"&gt;launchpadlib&lt;/a&gt; working in GTK+. I haven't even seen much code sharing.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;So, borrowing a trick from Twisted's &lt;a href="https://launchpad.net/tx"&gt;tx&lt;/a&gt; super-project, I've created an '&lt;a href="https://launchpad.net/lpx"&gt;lpx&lt;/a&gt;' project group on Launchpad. Bring it your scripts, your applications, your huddled masses. If you want to know more about the API, look at the &lt;a href="http://help.launchpad.net/API"&gt;API help page&lt;/a&gt;.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Thanks to &lt;a href="http://markshuttleworth.com"&gt;Mark&lt;/a&gt; for reminding me that this is important.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5733547231775030285-2581147091234827441?l=code.mumak.net' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/5733547231775030285/2581147091234827441/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=5733547231775030285&amp;postID=2581147091234827441' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5733547231775030285/posts/default/2581147091234827441'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5733547231775030285/posts/default/2581147091234827441'/><link rel='alternate' type='text/html' href='http://code.mumak.net/2009/10/launchpad-extensions.html' title='Launchpad extensions'/><author><name>jml</name><uri>http://www.blogger.com/profile/11400080716012026985</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='06159200095703820658'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5733547231775030285.post-3977792615495631243</id><published>2009-10-09T20:06:00.002+11:00</published><updated>2009-10-09T20:31:56.417+11:00</updated><title type='text'>Launchpad status now on identi.ca</title><content type='html'>Sometimes, sadly, Launchpad doesn't behave as well as we'd like.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Although we try extremely hard to always be available, and take each instance of downtime (planned or unplanned) as a personal insult, sometimes we're forced to disappoint both our users and ourselves. It's no excuse, of course, but at least we're in &lt;a href="http://www.worldofwarcraft.com/"&gt;good&lt;/a&gt; &lt;a href="https://mail.google.com/"&gt;company&lt;/a&gt;.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;To make these inevitable interruptions easier to swallow, we've set up &lt;a href="http://identi.ca/launchpadstatus"&gt;identi.ca&lt;/a&gt; and &lt;a href="http://twitter.com/launchpadstatus"&gt;Twitter&lt;/a&gt; accounts that report the Launchpad server statuses, and only the server statuses. We've got people all around the world who are able to update it when things go bump in the night. There's also a link to the identi.ca page in our footer, so you don't have to keep consulting a blog.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Thanks very much to &lt;a href="http://www.understated.co.uk/"&gt;Matt Revell&lt;/a&gt; for getting this done.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5733547231775030285-3977792615495631243?l=code.mumak.net' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/5733547231775030285/3977792615495631243/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=5733547231775030285&amp;postID=3977792615495631243' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5733547231775030285/posts/default/3977792615495631243'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5733547231775030285/posts/default/3977792615495631243'/><link rel='alternate' type='text/html' href='http://code.mumak.net/2009/10/launchpad-status-now-on-identica.html' title='Launchpad status now on identi.ca'/><author><name>jml</name><uri>http://www.blogger.com/profile/11400080716012026985</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='06159200095703820658'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5733547231775030285.post-3411025813324059298</id><published>2009-10-09T05:19:00.002+11:00</published><updated>2009-10-09T05:29:55.962+11:00</updated><title type='text'>Meta-meeting stuff</title><content type='html'>Last week the Launchpad team leads gathered in London and had an absolutely huge meeting. Fifteen or sixteen smart, opinionated &amp;amp; passionate people in a room talking about the next six months of Launchpad development. It was a lot of fun.&lt;br /&gt;&lt;br /&gt;When planning the agenda, Martin Albisetti and I were a little worried about things wandering off track, so we thrashed out a lists of dos &amp;amp; don'ts. I'll blurt them out here, with the really terrible ideas filtered out so I look more clever, and then offer some thoughts on how they worked.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Do&lt;/span&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;be happy with the results of this meeting.&lt;/li&gt;&lt;li&gt;ask questions, especially "why"&lt;/li&gt;&lt;li&gt;be punctual&lt;/li&gt;&lt;li&gt;stay on point&lt;/li&gt;&lt;/ul&gt;&lt;span style="font-weight: bold;"&gt;Don't&lt;br /&gt;&lt;/span&gt;&lt;ul&gt;&lt;li&gt;design features&lt;/li&gt;&lt;li&gt;check your email, i.e. laptops closed&lt;br /&gt;&lt;/li&gt;&lt;li&gt;leave the meeting without being clear&lt;/li&gt;&lt;li&gt;leave the meeting without being happy&lt;/li&gt;&lt;/ul&gt;The "laptops closed" one didn't work so well. It was great for the first couple of days, but by Thursday afternoon there were always people in a corner with those open LCD screens sucking chi out of the room like little dragons of despair.&lt;br /&gt;&lt;br /&gt;The "Don't design features" rule was awesome. The rationale is that feature design leads to long discussions, and that it does a disservice to the many excellent engineers we have who aren't at the meeting and will be actually implementing a feature. At best, it's waste and at worst it's us telling people how to do something that they know how to do better. The clearest sign that it was a good idea came when other people started using it to shut me up.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5733547231775030285-3411025813324059298?l=code.mumak.net' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/5733547231775030285/3411025813324059298/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=5733547231775030285&amp;postID=3411025813324059298' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5733547231775030285/posts/default/3411025813324059298'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5733547231775030285/posts/default/3411025813324059298'/><link rel='alternate' type='text/html' href='http://code.mumak.net/2009/10/meta-meeting-stuff.html' title='Meta-meeting stuff'/><author><name>jml</name><uri>http://www.blogger.com/profile/11400080716012026985</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='06159200095703820658'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5733547231775030285.post-5538618958290327740</id><published>2009-10-08T02:44:00.004+11:00</published><updated>2009-10-08T03:01:53.731+11:00</updated><title type='text'>Talking Time</title><content type='html'>I've been working on the Launchpad team for a while, with most of that time being in Australia. Others in the team are in the US (red states &amp;amp; blue states), the UK, Germany, Brazil, Canada, New Zealand, Serbia, Lithuania and Thailand.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Here are some tips I've picked up for smoother online conversations, particularly around scheduling.&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;Don't say "summer" or "fall". Say the month, or the range of months.&lt;/li&gt;&lt;li&gt;Say "my morning" rather than "the morning".&lt;/li&gt;&lt;li&gt;Use 24-hour time.&lt;/li&gt;&lt;li&gt;In real-time conversations, say "in 2 hours time" rather than "at 10".&lt;/li&gt;&lt;li&gt;Always include the timezone. Avoid using local abbreviations (e.g. PST), instead use offset from UTC.&lt;/li&gt;&lt;li&gt;Better still, just give the time in UTC.&lt;/li&gt;&lt;li&gt;Know your UTC offset.&lt;/li&gt;&lt;li&gt;Use a timezone-aware &lt;a href="http://timeanddate.com/worldclock/meeting.html"&gt;meeting planner&lt;/a&gt;. You'll get the arithmetic wrong otherwise.&lt;/li&gt;&lt;li&gt;Say "Oct 7" rather than 10/7 or 7/10. Everyone speaks English, but not everyone uses your dialect.&lt;/li&gt;&lt;li&gt;The time that you end a meeting is more important than when you start it. Thoughtfully consider the timezones of other attendees when you are planning for &amp;amp; participating in meetings.&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;Violating these rules isn't a big deal, since people can generally figure out what you mean. Following them, however, can speed things along and sometimes even avoid tedious conversations.&lt;/div&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5733547231775030285-5538618958290327740?l=code.mumak.net' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://www.blogger.com/feeds/5733547231775030285/5538618958290327740/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment.g?blogID=5733547231775030285&amp;postID=5538618958290327740' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5733547231775030285/posts/default/5538618958290327740'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5733547231775030285/posts/default/5538618958290327740'/><link rel='alternate' type='text/html' href='http://code.mumak.net/2009/10/talking-time.html' title='Talking Time'/><author><name>jml</name><uri>http://www.blogger.com/profile/11400080716012026985</uri><email>noreply@blogger.com</email><gd:extendedProperty xmlns:gd='http://schemas.google.com/g/2005' name='OpenSocialUserId' value='06159200095703820658'/></author><thr:total xmlns:thr='http://purl.org/syndication/thread/1.0'>5</thr:total></entry></feed>