<?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' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-5733547231775030285</id><updated>2012-02-16T10:55:29.047Z</updated><category term='launchpad subunit data'/><category term='Personal'/><category term='UI'/><category term='Hacking'/><category term='launchpad'/><category term='Uncategorized'/><category term='ubuntu'/><category term='Twisted'/><category term='Bazaar'/><category term='testtools'/><category term='subunit data'/><category term='Testing'/><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='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://code.mumak.net/feeds/posts/default'/><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'/><author><name>jml</name><uri>http://www.blogger.com/profile/11400080716012026985</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='http://1.bp.blogspot.com/-M_jE0GQZ9H0/TiFSUOGRb8I/AAAAAAAAAEI/w7DhhWkNUZs/s220/Texas-2011-01.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>200</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-5733547231775030285.post-6777212250918592295</id><published>2012-02-16T10:55:00.000Z</published><updated>2012-02-16T10:55:29.055Z</updated><title type='text'>testtools 0.9.14 released</title><content type='html'>&lt;a href="http://pypi.python.org/pypi/testtools"&gt;testtools&lt;/a&gt;'s sister project, &lt;a href="https://launchpad.net/subunit"&gt;subunit&lt;/a&gt;,&amp;nbsp;was using a&amp;nbsp;private API that we deleted in the 0.9.13 release. &amp;nbsp;This release restores&amp;nbsp;that API in order to smooth out the upgrade path.&lt;br /&gt;&lt;br /&gt;If you don't use subunit, then this release won't matter very much to you.&lt;br /&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-6777212250918592295?l=code.mumak.net' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://code.mumak.net/feeds/6777212250918592295/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5733547231775030285&amp;postID=6777212250918592295' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5733547231775030285/posts/default/6777212250918592295'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5733547231775030285/posts/default/6777212250918592295'/><link rel='alternate' type='text/html' href='http://code.mumak.net/2012/02/testtools-0914-released.html' title='testtools 0.9.14 released'/><author><name>jml</name><uri>http://www.blogger.com/profile/11400080716012026985</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='http://1.bp.blogspot.com/-M_jE0GQZ9H0/TiFSUOGRb8I/AAAAAAAAAEI/w7DhhWkNUZs/s220/Texas-2011-01.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5733547231775030285.post-5806693077249526681</id><published>2012-02-06T15:55:00.000Z</published><updated>2012-02-06T15:55:12.074Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='testtools'/><title type='text'>testtools 0.9.13 released</title><content type='html'>It has been a while, but &lt;a href="http://pypi.python.org/pypi/testtools"&gt;testtools 0.9.13&lt;/a&gt; is finally out!&amp;nbsp;Lots more matchers and bug fixes, as well as improved error reporting. Full release notes &lt;a href="https://launchpad.net/testtools/0.9/0.9.13"&gt;on Launchpad&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Thanks to &lt;a href="http://jameswestby.net/weblog"&gt;James Westby&lt;/a&gt;, &lt;a href="http://grahambinns.com/"&gt;Graham Binns&lt;/a&gt;, &lt;a href="https://launchpad.net/~frankban"&gt;Francesco Banconi&lt;/a&gt; and &lt;a href="http://rbtcollins.wordpress.com/"&gt;Robert Collins&lt;/a&gt; for making this release possible.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5733547231775030285-5806693077249526681?l=code.mumak.net' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://code.mumak.net/feeds/5806693077249526681/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5733547231775030285&amp;postID=5806693077249526681' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5733547231775030285/posts/default/5806693077249526681'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5733547231775030285/posts/default/5806693077249526681'/><link rel='alternate' type='text/html' href='http://code.mumak.net/2012/02/testtools-0913-released.html' title='testtools 0.9.13 released'/><author><name>jml</name><uri>http://www.blogger.com/profile/11400080716012026985</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='http://1.bp.blogspot.com/-M_jE0GQZ9H0/TiFSUOGRb8I/AAAAAAAAAEI/w7DhhWkNUZs/s220/Texas-2011-01.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5733547231775030285.post-4903070032423248361</id><published>2012-02-01T13:50:00.000Z</published><updated>2012-02-01T13:50:38.462Z</updated><title type='text'>Simple made easy</title><content type='html'>Rich Hickey did a great talk at Strange Loop called "&lt;a href="http://www.infoq.com/presentations/Simple-Made-Easy"&gt;Simple Made Easy&lt;/a&gt;". You should watch it.&lt;br /&gt;&lt;br /&gt;When I tried to explain the talk to someone, I stumbled a lot and it was obvious to me that I didn't really understand it. So I'm going through it again and turning it into a blog post, purely for my own gain.&lt;br /&gt;&lt;br /&gt;This is roughly the first half of the talk. Not much of my own analysis or opinion is inserted, and I've pretty much stuck with Hickey's illustrations and phrasings. Thus this post is pretty derivative. Oops.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Simple vs Easy&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;"Simple" means one thing, "easy" another. Simple is the opposite of complex. A thing is simple if it has no interleaving, if it has one purpose, one concept, one dimension, one task. Being simple does not imply one instance or one operation: it's about interleaving, not cardinality. Importantly, this means that simplicity is &lt;i&gt;objective&lt;/i&gt;.&lt;br /&gt;&lt;br /&gt;Easy is the opposite of hard, or difficult. A thing is easy if it's near to hand, if it's easy to get at (location), if it's near to our understanding (familiarity) or skill set or if it's within our capabilities. This means that ease is&lt;i&gt; relative&lt;/i&gt;.&lt;br /&gt;&lt;br /&gt;Speaking English is dead easy for me, but that doesn't mean that speaking English is intrinsically simple. I find French quite difficult. Little French children speak French all the time, and there's always a part of me that thinks, "Boy, those kids are clever, being able to speak a foreign language at that age", but that's silly. It's easy for them, it lies near to them.&lt;br /&gt;&lt;br /&gt;This distinction between simple &amp;amp; easy is good one, and is useful in all sorts of areas. But how does it relate to software?&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Constructs vs Artefacts&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;As programmers, when we make software we are working on &lt;i&gt;constructs&lt;/i&gt;: source code, libraries, language concepts and so forth. Rich contends that we focus on the ease of use of those constructs: How many lines of code? How much boilerplate? Will new developers be familiar with our technology?&lt;br /&gt;&lt;br /&gt;But all of this is secondary. What actually matters is the &lt;i&gt;artefact&lt;/i&gt;, the running programs that users actually use. Does it do what it's supposed to do? Does it do it well? Can we rely on it working well? Can we fix problems when they occur? Can we change it? You know, the interesting problems.&lt;br /&gt;&lt;br /&gt;Thus we need to be assessing our constructs – our code, our technology choices – based on the attributes of the artefacts that we'll create, not based on the experience of typing code in.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Limits&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;We can't make something reliable if we don't understand it. And, actually, everyone's understanding is pretty limited. We can all only hold a small number of things in our head at once.&lt;br /&gt;&lt;br /&gt;When things are complex, many parts are tied together by definition. You can't pull out just one piece and consider it because it's intertwined with other pieces. This creates an extra burden to understanding a system and thus makes it difficult to reason about the system.&lt;br /&gt;&lt;br /&gt;You do need to reason about a system, both to know what to change and to be able to do so without introducing defects. Tests, refactoring, rapid deployment and all that are great, but to make a change to the system safely &amp;amp; without fear still requires you to be able to reason about it. Every bug in your product that was found in the field passed the type checker and passed all of the tests. &amp;nbsp;Your type system doesn't tell you what change to make next in order to get the software you want any more than guard rails on a highway tell you how to get to Grandma's.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Speed&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Focusing on ease and ignoring simplicity means that you'll go really fast in the beginning, but will become slower and slower as the complexity builds.&lt;br /&gt;&lt;br /&gt;Focusing on simplicity will mean that you'll go slower in the beginning, because you'll have to do some work to simplify the problem space, but making sure that you only have intrinsic complexity means that your rate of development will remain at a high constant.&lt;br /&gt;&lt;br /&gt;There are no actual numbers for this.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Complicating constructs&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Many complicating constructs are available, familiar, succinctly described and easy to use. But none of that matters to end users. What matters is the complexity they yield. This complexity is &lt;i&gt;incidental&lt;/i&gt;, it's not intrinsic to the problem.&lt;br /&gt;&lt;br /&gt;If we build things simply, then the resulting system is easier to debug, easier to change and easier to understand.&lt;br /&gt;&lt;br /&gt;Compare a knitted castle to a castle made of Lego. The knitted castle might have been great fun to make, and might have been really easy if knitted using a loom and cutting edge knitting tools, but there's no way that it's easier to change than a Lego castle. It's not about the &lt;i&gt;ease of construction&lt;/i&gt;, it's about the &lt;i&gt;simplicity of the artefact&lt;/i&gt;.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;How can we make software easier?&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Well, we can install it to make it easier by location. We can learn it and try it to make it easier by familiarity. We can't do much about our capabilities though. If we want software to be easier to comprehend, we are going to have to bring it down to our level. We have to make it simpler.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Take Lisp as an example. It's hard for many people because they don't have a Lisp installed, or their editor doesn't support paren matching, but they can make it easier by installing a Lisp and getting a plugin for their editor. It's also hard because it's unfamiliar. Who'd have thought that parens could go on that side of the function? But you can gain that familiarity quickly enough.&lt;br /&gt;&lt;br /&gt;But parens in Lisp are used for functions and for grouping data. That's hard to get your head around, and that's because it's complex. It braids together two distinct notions.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5733547231775030285-4903070032423248361?l=code.mumak.net' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://code.mumak.net/feeds/4903070032423248361/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5733547231775030285&amp;postID=4903070032423248361' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5733547231775030285/posts/default/4903070032423248361'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5733547231775030285/posts/default/4903070032423248361'/><link rel='alternate' type='text/html' href='http://code.mumak.net/2012/02/simple-made-easy.html' title='Simple made easy'/><author><name>jml</name><uri>http://www.blogger.com/profile/11400080716012026985</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='http://1.bp.blogspot.com/-M_jE0GQZ9H0/TiFSUOGRb8I/AAAAAAAAAEI/w7DhhWkNUZs/s220/Texas-2011-01.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5733547231775030285.post-7007235897083396697</id><published>2012-01-23T14:32:00.001Z</published><updated>2012-01-23T17:44:37.178Z</updated><title type='text'>Undistract me</title><content type='html'>Here's a thing that happens a lot to me: I'm doing some work, and as part of that work I need to run a command in my terminal that takes a little while. I run the command, look at it for about a second and then switch to doing something else – checking email, perhaps. I get deeply involved in my email checking, and then about twenty minutes later I switch back to the terminal and see the command has finished.&amp;nbsp;For all I know, it finished nineteen minutes ago, and I was just too engrossed to notice it.&lt;br /&gt;&lt;br /&gt;This is a big productivity sink for me, especially if the command happened to fail and need retrying. I'm not disciplined enough to just sit and watch the command, and I'm not prescient enough to add something to each invocation telling me when a command is done. What I want is something that alerts me whenever long running commands finish.&lt;br /&gt;&lt;br /&gt;Well, that thing now exists, thanks to &lt;a href="http://glyph.twistedmatrix.com/"&gt;glyph&lt;/a&gt;'s &lt;a href="http://glyph.twistedmatrix.com/2006/11/bash-shell-is-now-fully-operational.html"&gt;script that provides precmd and postcmd support to bash&lt;/a&gt;&amp;nbsp;and a lot of help from &lt;a href="http://www.tenshu.net/"&gt;Chris Jones&lt;/a&gt;&amp;nbsp;of &lt;a href="http://www.tenshu.net/p/terminator.html"&gt;Terminator&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;To use it right now:&lt;br /&gt;&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;&amp;nbsp;$ bzr co lp:~jml/+junk/shell-tools&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;&amp;nbsp;$ . shell-tools/long-running.bash&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;&amp;nbsp;$&amp;nbsp;notify_when_long_running_commands_finish_install&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;You'll see that if you run a command that takes over 30 seconds to complete, it will pop up a notification, which should hopefully take you away from whatever it was you are doing and back to the task at hand.&lt;br /&gt;&lt;br /&gt;If you &lt;a href="http://bazaar.launchpad.net/~jml/+junk/shell-tools/view/head:/long-running.bash"&gt;look at the code&lt;/a&gt;, you'll see that it installs two hooks: &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;precmd&lt;/span&gt; and &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;preexec&lt;/span&gt;. &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;preexec&lt;/span&gt; runs just before the shell launches a command, and &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;precmd&lt;/span&gt; runs just before it prompts for the next command. Our &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;preexec&lt;/span&gt; stores when the command was launched and the &lt;span style="font-family: 'Courier New', Courier, monospace;"&gt;precmd&lt;/span&gt; checks to see if it finished within a certain time frame. If not, it sends out a notification.&lt;br /&gt;&lt;br /&gt;Currently, you'll get a notification when you finish reading a long document, since the command finishes a long time after the command starts. Obviously this isn't ideal. I think the fix is to only send notifications when the shell doesn't have focus. Unfortunately, that's a little tricky and I think is going to be highly terminal specific.&lt;br /&gt;&lt;br /&gt;Anyway, I'm a total shell newbie, so I'd love to know if there's any way this could be done better. &amp;nbsp;Also let me know if you find this useful, or you know of someone who has already done this.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5733547231775030285-7007235897083396697?l=code.mumak.net' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://code.mumak.net/feeds/7007235897083396697/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5733547231775030285&amp;postID=7007235897083396697' title='10 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5733547231775030285/posts/default/7007235897083396697'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5733547231775030285/posts/default/7007235897083396697'/><link rel='alternate' type='text/html' href='http://code.mumak.net/2012/01/undistract-me.html' title='Undistract me'/><author><name>jml</name><uri>http://www.blogger.com/profile/11400080716012026985</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='http://1.bp.blogspot.com/-M_jE0GQZ9H0/TiFSUOGRb8I/AAAAAAAAAEI/w7DhhWkNUZs/s220/Texas-2011-01.jpg'/></author><thr:total>10</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5733547231775030285.post-8212227942183096608</id><published>2011-12-26T04:54:00.000Z</published><updated>2011-12-26T04:54:40.336Z</updated><title type='text'>What are my projects?</title><content type='html'>Launchpad doesn't really have any good mechanism for letting you review a list of "your" projects.&lt;br /&gt;&lt;br /&gt;That's partly because there are a lot of different ways that it &lt;i&gt;could&lt;/i&gt;&amp;nbsp;do it. You could be the maintainer of a project, or its driver, or its bug supervisor, or you might have commit access to its trunk branch. All of this could be direct, or through membership of a team. It's tough.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Since it's that time of year when I review my projects, responsibilities, goals and the like and start to figure out what I want to do next year, I want to figure out what are my projects on Launchpad.&lt;br /&gt;&lt;br /&gt;Luckily, Launchpad has an API. I can't use it to figure out what projects I'm the maintainer of, but I can use it to figure out &lt;a href="http://paste.ubuntu.com/783038/"&gt;what trunk branches I have commit access to&lt;/a&gt;. &amp;nbsp;The link has the Python code for the script.&lt;br /&gt;&lt;br /&gt;Really, Launchpad should allow me to curate my own list of projects, with input to that list coming from all of the sources mentioned above, as well as arbitrarily selecting projects.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5733547231775030285-8212227942183096608?l=code.mumak.net' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://code.mumak.net/feeds/8212227942183096608/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5733547231775030285&amp;postID=8212227942183096608' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5733547231775030285/posts/default/8212227942183096608'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5733547231775030285/posts/default/8212227942183096608'/><link rel='alternate' type='text/html' href='http://code.mumak.net/2011/12/what-are-my-projects.html' title='What are my projects?'/><author><name>jml</name><uri>http://www.blogger.com/profile/11400080716012026985</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='http://1.bp.blogspot.com/-M_jE0GQZ9H0/TiFSUOGRb8I/AAAAAAAAAEI/w7DhhWkNUZs/s220/Texas-2011-01.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5733547231775030285.post-470633188402716824</id><published>2011-11-21T12:44:00.001Z</published><updated>2011-11-21T14:29:05.679Z</updated><title type='text'>pyflakes update</title><content type='html'>Thanks to &lt;a href="http://radix.twistedmatrix.com/"&gt;radix&lt;/a&gt;, &lt;a href="http://as.ynchrono.us/"&gt;exarkun&lt;/a&gt; &amp;amp; &lt;a href="http://as.ynchrono.us/"&gt;dash&lt;/a&gt;, my branch to &lt;a href="http://pypi.python.org/pypi/pyflakes"&gt;pyflakes&lt;/a&gt; to warn about duplicate definitions of classes finally landed. I did the work a year ago as an outrage-powered, opportunistic fix after I saw a co-worker struggle with tests weirdly not failing (Turned out it was a huge test module and there was another class at the bottom with the same name). I'm very happy to see it landed.&lt;br /&gt;&lt;br /&gt;For those who haven't been paying attention, official pyflakes development is now taking place on &lt;a href="https://launchpad.net/"&gt;Launchpad&lt;/a&gt; as part of the &lt;a href="http://launchpad.net/divmod.org"&gt;divmod.org&lt;/a&gt; project. The trunk of that project now has the best version of pyflakes known to man.&lt;br /&gt;&lt;br /&gt;pyflakes is the best static Python checker. It's fast, and has very few false positives.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Update: &lt;/b&gt;A couple of people have asked me about &lt;a href="https://launchpad.net/pyflakes"&gt;lp:pyflakes&lt;/a&gt;. It's dead. It died when the divmorg.org trac instance died ages ago. Don't use it. To get pyflakes or any other divmod project, use &lt;a href="https://launchpad.net/divmod.org"&gt;lp:divmod.org&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5733547231775030285-470633188402716824?l=code.mumak.net' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://code.mumak.net/feeds/470633188402716824/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5733547231775030285&amp;postID=470633188402716824' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5733547231775030285/posts/default/470633188402716824'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5733547231775030285/posts/default/470633188402716824'/><link rel='alternate' type='text/html' href='http://code.mumak.net/2011/11/pyflakes-update.html' title='pyflakes update'/><author><name>jml</name><uri>http://www.blogger.com/profile/11400080716012026985</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='http://1.bp.blogspot.com/-M_jE0GQZ9H0/TiFSUOGRb8I/AAAAAAAAAEI/w7DhhWkNUZs/s220/Texas-2011-01.jpg'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5733547231775030285.post-2586467635191977316</id><published>2011-11-10T12:40:00.002Z</published><updated>2011-11-10T12:40:33.809Z</updated><title type='text'>Automatic packaging update</title><content type='html'>I just blogged on developer.ubuntu.com about &lt;a href="http://developer.ubuntu.com/2011/11/automatic-packaging-progress/"&gt;the work we're doing with automatic packaging&lt;/a&gt;. Read it!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5733547231775030285-2586467635191977316?l=code.mumak.net' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://code.mumak.net/feeds/2586467635191977316/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5733547231775030285&amp;postID=2586467635191977316' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5733547231775030285/posts/default/2586467635191977316'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5733547231775030285/posts/default/2586467635191977316'/><link rel='alternate' type='text/html' href='http://code.mumak.net/2011/11/automatic-packaging-update.html' title='Automatic packaging update'/><author><name>jml</name><uri>http://www.blogger.com/profile/11400080716012026985</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='http://1.bp.blogspot.com/-M_jE0GQZ9H0/TiFSUOGRb8I/AAAAAAAAAEI/w7DhhWkNUZs/s220/Texas-2011-01.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5733547231775030285.post-6888679017330633879</id><published>2011-11-04T18:29:00.000Z</published><updated>2011-11-04T18:29:19.353Z</updated><title type='text'>How to feel better (or, some tips on refactoring)</title><content type='html'>&lt;span style="background-color: transparent;"&gt;A few months back I gave a lightning talk at the &lt;a href="https://launchpad.net/"&gt;Launchpad&lt;/a&gt; Thunderdome about how I do refactoring. &amp;nbsp;It's very opinionated, and mostly applies to big, old code bases, but worth writing up anyway.&lt;/span&gt;&lt;br /&gt;&lt;span style="background-color: transparent;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="background-color: transparent;"&gt;The core idea here is that very few things make me feel as good as deleting code. I love cleaning up code and the clean code base that results, and I'm sure that many others feel like me. As such, this is a guide on how to feel better.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;b&gt;1. Know your enemy&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;“Functionality is an asset, code is a liability”. Truer words were never spoken. Every line of code is a potential source of bugs and a barrier to understanding, and thus carries a maintenance cost.&lt;br /&gt;&lt;br /&gt;Maintain an awareness of things that need refactoring. Here's a quick and incomplete list:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;&lt;span style="background-color: transparent;"&gt;unused code – this can be deleted&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="background-color: transparent;"&gt;boilerplate – this should become a function or class&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="background-color: transparent;"&gt;wrong documentation – these should be updated&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="background-color: transparent;"&gt;two ways of doing something – perhaps there should be one&lt;/span&gt;&lt;/li&gt;&lt;li&gt;&lt;span style="background-color: transparent;"&gt;bad names – change them to something that makes you think less&lt;/span&gt;&lt;/li&gt;&lt;/ul&gt;&lt;b&gt;2. Keep a "yak stack"&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;&lt;a href="http://projects.csail.mit.edu/gsb/old-archive/gsb-archive/gsb2000-02-11.html" style="background-color: transparent;"&gt;Yak shaving&lt;/a&gt;&lt;span style="background-color: transparent;"&gt;&amp;nbsp;is "any seemingly pointless activity which is actually necessary to solve a problem which solves a problem which, several levels of recursion later, solves the real problem you're working on." (&lt;a href="http://catb.org/jargon/html/Y/yak-shaving.html"&gt;Jargon File&lt;/a&gt;)&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;A few of us have extended the concept beyond the "actually necessary" to include anything that's making the task at hand more difficult and less fun but is not worth fixing &lt;i&gt;right&lt;/i&gt;&amp;nbsp;now. Hence the yak stack. Here's how it works:&lt;br /&gt;&lt;br /&gt;Whenever you come across something in your code base that is difficult to understand or that slows you down: make a note of it. When you've finished the task at hand, fix the problem. If you encounter other things that slow you down, write them down. Work through the list.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;3. Every option is wrong&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;In a big, old code base, there are probably many, many areas that need refactoring. &amp;nbsp;Don't worry about which is the "best" place to start – there is no best place.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;4. Start from green, stay green&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Never, ever refactor while your tests are failing. Refactoring is about changing the shape of code while preserving its behaviour. It's much harder to be sure you're keeping the behaviour if you are comparing one set of thirty tracebacks with another set of thirty tracebacks. Better to compare a passing ("green") test run with another passing test run.&lt;br /&gt;&lt;br /&gt;Run tests frequently. More often then you think you should. Commit often – think of it like quick save in a tough level of a video game. It frees you up to experiment more and means you have less in your head at any one time.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;5. Do not nest&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Don't begin a refactoring while you are in the middle of another refactoring. If you find you must, use tools like '&lt;a href="http://doc.bazaar.canonical.com/beta/en/user-guide/shelving_changes.html"&gt;bzr shelve&lt;/a&gt;' to store your current diff and then work from the clean head of your branch.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;6. Keep moving, leave a trail&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Don't get bogged down in details, otherwise you'll never finish. Literally. Someone will come along and distract you and before you know it, three months will pass and your refactoring branch will be full of conflicts. If you see something you are unsure of, mark it with a XXX or a FIXME or a TODO or whatever works for you and then continue with what you are doing.&lt;br /&gt;&lt;br /&gt;Tools like '&lt;a href="http://launchpad.net/difftodo"&gt;bzr todo&lt;/a&gt;' can make it really easy to check to see if you've added any XXX comments.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;7. Translate tests with care&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;As said above, refactoring is about changing the shape of code while preserving its behaviour. When you update tests, you risk changing your definition of the system's behaviour – so be careful.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;8. Confront uncertainty with destruction&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;If you see some code and you are not sure if it's needed, delete it. Doesn't matter if it's a whole function or just an odd line. If you have a test suite, and it was important, that will catch the failure. If you have version control, and it was important, one of your collaborators will notice and revert the change.&lt;br /&gt;&lt;br /&gt;If it was important and neither of these happened, then your whole project has learned something new about itself, and that's probably worth the hassle. (Oh, add tests &amp;amp; better docs after this happens.)&lt;br /&gt;&lt;br /&gt;&lt;b&gt;9. Good grep tools&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Remember that symbols aren't only referenced from files that match *.py. &amp;nbsp;In big code bases there are often other sorts of files that refer to symbols in the main code. In Launchpad, for example, we have ZCML and doctest files that refer to symbols. When you want to know how something is used or you want to rename something, make sure you use a grep command that actually finds everything.&lt;br /&gt;&lt;br /&gt;Ideally, you should be able to run this command faster than you can think about wanting to do it.&lt;br /&gt;&lt;br /&gt;Personally, I use 'bzr grep' a lot. Others recommend 'ack'.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;10. There will be failures&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Mentally prepare yourself for the fact that the first two or three full test runs after your refactoring will fail. &amp;nbsp;This is especially important for code bases that have multi-hour test run times.&lt;br /&gt;&lt;br /&gt;If you think this way, then you won't be as discouraged when it actually happens.&lt;br /&gt;&lt;br /&gt;&lt;b style="background-color: transparent;"&gt;11. Finish the job&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;Busy people refactoring a big code base are often tempted to apply a refactoring to only a single part. &amp;nbsp;For example, some useful function is extracted from repeated boilerplate in a few other functions. However, many, many other instances in the code base continue to use the repeated boilerplate.&lt;br /&gt;&lt;br /&gt;This is &lt;i&gt;almost&lt;/i&gt; worse than just leaving the repeated boilerplate. &amp;nbsp;There are now two idiomatic ways of doing the activity. &amp;nbsp;Further, other developers who work on other parts of the code base probably won't find out about it, and might end up repeating your refactoring. Ugh. How is anyone new expected to get to grips with this code?&lt;br /&gt;&lt;br /&gt;Similarly, if a class, function or concept is renamed, rename it everywhere, especially in the documentation.&lt;br /&gt;&lt;br /&gt;It's difficult and often tedious, but it really is worth taking refactorings to completion. Apply them to the whole code base, or not at all.&lt;br /&gt;&lt;br /&gt;Note that I'm referring to completeness, not perfection. If you block on perfection, you never get anything useful done. If you aim for frequent incremental improvements, you soar.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;12. Read these books&lt;/b&gt;&lt;br /&gt;&lt;br /&gt;I highly recommend "&lt;a href="http://www.amazon.com/Refactoring-Improving-Design-Existing-Code/dp/0201485672/ref=sr_1_1?s=books&amp;amp;ie=UTF8&amp;amp;qid=1320430812&amp;amp;sr=1-1"&gt;Refactoring&lt;/a&gt;" by Martin Fowler and "&lt;a href="http://www.amazon.com/Refactoring-Improving-Design-Existing-Code/dp/0201485672/ref=sr_1_1?s=books&amp;amp;ie=UTF8&amp;amp;qid=1320430812&amp;amp;sr=1-1"&gt;TDD by Example&lt;/a&gt;" by Kent Beck. I stole many of these ideas from them.&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;b&gt;Over to you&lt;/b&gt;&lt;/div&gt;&lt;div&gt;&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/div&gt;&lt;div&gt;This was very much just a dump of how I do refactoring when hacking on Launchpad. I'm always keen to learn more, and would love to hear about what works for you.&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-6888679017330633879?l=code.mumak.net' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://code.mumak.net/feeds/6888679017330633879/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5733547231775030285&amp;postID=6888679017330633879' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5733547231775030285/posts/default/6888679017330633879'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5733547231775030285/posts/default/6888679017330633879'/><link rel='alternate' type='text/html' href='http://code.mumak.net/2011/11/how-to-feel-better-or-some-tips-on.html' title='How to feel better (or, some tips on refactoring)'/><author><name>jml</name><uri>http://www.blogger.com/profile/11400080716012026985</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='http://1.bp.blogspot.com/-M_jE0GQZ9H0/TiFSUOGRb8I/AAAAAAAAAEI/w7DhhWkNUZs/s220/Texas-2011-01.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5733547231775030285.post-6056092545256978331</id><published>2011-09-14T12:01:00.000+01:00</published><updated>2011-09-14T12:01:19.632+01:00</updated><title type='text'>testtools 0.9.12 out</title><content type='html'>&lt;a href="http://pypi.python.org/pypi/testtools"&gt;testtools&lt;/a&gt; 0.9.12 has just been released!&lt;br /&gt;&lt;br /&gt;It's a huge release, this one. We normally try to release much more frequently, but for this release I wanted to wait until &lt;a href="https://bugs.launchpad.net/testtools/+bugs?field.tag=unicode&amp;amp;field.status=Fix+Released"&gt;all of our known unicode handling bugs were fixed&lt;/a&gt;. Today, &lt;a href="https://launchpad.net/~gz"&gt;Martin [gz]&lt;/a&gt; finished off his &lt;a href="https://code.launchpad.net/~gz/testtools/unprintable-assertThat-804127/+merge/72641"&gt;heroic branch&lt;/a&gt; to fix up &lt;a href="http://testtools.readthedocs.org/en/latest/for-test-authors.html#matchers"&gt;&lt;code&gt;assertThat&lt;/code&gt;&lt;/a&gt;, and I figured it was time to release.&lt;br /&gt;&lt;br /&gt;In addition to all of the unicode fixes, we've really cleaned up the way test failures are displayed. A lot of the boilerplate around the traceback has been removed, a lot of levels of the stack are gone (although you can get them back if you want), and &lt;code&gt;assertThat&lt;/code&gt; is way less repetitive. This all really adds up. If you're using an old release, you want to upgrade right now. Honest.&lt;br /&gt;&lt;br /&gt;For me, this release is the one where using &lt;a href="http://testtools.readthedocs.org/en/latest/for-test-authors.html#matchers"&gt;matchers&lt;/a&gt; becomes really and properly fun. As such, all of our &lt;code&gt;assertFoo&lt;/code&gt; methods are now implemented in terms of matchers.&lt;br /&gt;&lt;br /&gt;Of course, we have our usual raft of fixes, helpers and new matchers too. The &lt;a href="https://launchpad.net/testtools/0.9/0.9.12"&gt;full changelog&lt;/a&gt; is on Launchpad.&lt;br /&gt;&lt;br /&gt;In addition to Martin [gz], thanks to &lt;a href="https://launchpad.net/~kampka"&gt;Christian Kampka&lt;/a&gt;, &lt;a href="https://launchpad.net/~lifeless"&gt;Robert Collins&lt;/a&gt; and &lt;a href="http://canonical.com/"&gt;Canonical&lt;/a&gt; for making this release what it is.&lt;br /&gt;&lt;br /&gt;If you're new to testtools, it's basically a way to do serious, &lt;a href="http://testtools.readthedocs.org/en/latest/overview.html"&gt;tasteful unit testing in Python&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Documentation lives at&amp;nbsp;&lt;a href="http://testtools.readthedocs.org/en/latest/"&gt;http://testtools.readthedocs.org/en/latest/&lt;/a&gt;.&lt;br /&gt;PyPI:&amp;nbsp;&lt;a href="http://pypi.python.org/pypi/testtools"&gt;http://pypi.python.org/pypi/testtools&lt;/a&gt;&lt;br /&gt;All development takes place on Launchpad:&amp;nbsp;&lt;a href="https://launchpad.net/testtools"&gt;https://launchpad.net/testtools&lt;/a&gt;&lt;br /&gt;Join us on #python-testing on Freenode&lt;br /&gt;&lt;br /&gt;We don't currently have a release PPA, but we do have a &lt;a href="https://launchpad.net/~testing-cabal/+archive/archive"&gt;daily builds PPA&lt;/a&gt;. The trunk is kept stable using &lt;a href="http://mumak.net:8080/job/testtools/"&gt;Jenkins&lt;/a&gt;, so it's fairly safe to use.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5733547231775030285-6056092545256978331?l=code.mumak.net' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://code.mumak.net/feeds/6056092545256978331/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5733547231775030285&amp;postID=6056092545256978331' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5733547231775030285/posts/default/6056092545256978331'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5733547231775030285/posts/default/6056092545256978331'/><link rel='alternate' type='text/html' href='http://code.mumak.net/2011/09/testtools-0912-out.html' title='testtools 0.9.12 out'/><author><name>jml</name><uri>http://www.blogger.com/profile/11400080716012026985</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='http://1.bp.blogspot.com/-M_jE0GQZ9H0/TiFSUOGRb8I/AAAAAAAAAEI/w7DhhWkNUZs/s220/Texas-2011-01.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5733547231775030285.post-4657676752238884840</id><published>2011-09-09T18:36:00.001+01:00</published><updated>2011-09-09T18:39:48.901+01:00</updated><title type='text'>doctest really isn't very good</title><content type='html'>&lt;span style="background-color: white; font-family: Arial, sans-serif; font-size: 13px; line-height: 18px;"&gt;I just got sick of trying to decode obtuse doctest diff errors when using NORMALIZE_WHITESPACE and ELLIPSIS options. Although doctest gives you hooks to do something about this, it's really hard to actually write the logic.&lt;/span&gt;&lt;br /&gt;&lt;span style="background-color: white; font-family: Arial, sans-serif; font-size: 13px; line-height: 18px;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="background-color: white; font-family: Arial, sans-serif; font-size: 13px; line-height: 18px;"&gt;See, NORMALIZE_WHITESPACE also normalizes line breaks, and '...' can match across multiple lines. That means that you can't take a line-based approach, which makes it really hard to clean up a diff. Anyway, here's my attempt:&amp;nbsp;&lt;/span&gt;&lt;a href="https://code.launchpad.net/~jml/testtools/better-doctest-output-checker/+merge/74842"&gt;https://code.launchpad.net/~jml/testtools/better-doctest-output-checker/+merge/74842&lt;/a&gt;&lt;br /&gt;&lt;span style="background-color: white; font-family: Arial, sans-serif; font-size: 13px; line-height: 18px;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="background-color: white; font-family: Arial, sans-serif; font-size: 13px; line-height: 18px;"&gt;It's a pain, because both of them would be very useful without their line-spanning behaviour. I guess without the line-spanning behaviour of '...' there'd be no way to indicate multiple lines of crap in output.&lt;/span&gt;&lt;br /&gt;&lt;span style="background-color: white; font-family: Arial, sans-serif; font-size: 13px; line-height: 18px;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-family: Arial, sans-serif; font-size: x-small;"&gt;&lt;span style="line-height: 18px;"&gt;My suggestion in the mean time? Don't use doctest.&lt;/span&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5733547231775030285-4657676752238884840?l=code.mumak.net' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://code.mumak.net/feeds/4657676752238884840/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5733547231775030285&amp;postID=4657676752238884840' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5733547231775030285/posts/default/4657676752238884840'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5733547231775030285/posts/default/4657676752238884840'/><link rel='alternate' type='text/html' href='http://code.mumak.net/2011/09/doctest-really-isnt-very-good.html' title='doctest really isn&apos;t very good'/><author><name>jml</name><uri>http://www.blogger.com/profile/11400080716012026985</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='http://1.bp.blogspot.com/-M_jE0GQZ9H0/TiFSUOGRb8I/AAAAAAAAAEI/w7DhhWkNUZs/s220/Texas-2011-01.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5733547231775030285.post-7623468891540815290</id><published>2011-08-23T19:09:00.000+01:00</published><updated>2011-08-23T19:09:54.777+01:00</updated><title type='text'>Progress on auto packaging</title><content type='html'>Instead of a junk branch, the auto packaging code now has &lt;a href="https://launchpad.net/pkgme-binary"&gt;a proper home on Launchpad&lt;/a&gt;. I've filed bugs for all of the things that I could think of that were wrong with it. Actually, that's a lie. When I spot something wrong in code or behaviour I make a note, usually a XXX comment. The bugs up there are the ones I got from grepping my notes.&lt;br /&gt;&lt;br /&gt;Anyway, minor rant on effective use of brain and the gift of literacy aside, I've also done a &lt;a href="https://wiki.ubuntu.com/AutomagicBinaryPackaging"&gt;reasonably detailed specification&lt;/a&gt;. It's been a long time since I've done a spec this technical &amp;amp; detailed, but I hope it works out.&amp;nbsp;If you have any comments or questions, ask here or on the spec itself.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5733547231775030285-7623468891540815290?l=code.mumak.net' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://code.mumak.net/feeds/7623468891540815290/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5733547231775030285&amp;postID=7623468891540815290' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5733547231775030285/posts/default/7623468891540815290'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5733547231775030285/posts/default/7623468891540815290'/><link rel='alternate' type='text/html' href='http://code.mumak.net/2011/08/progress-on-auto-packaging.html' title='Progress on auto packaging'/><author><name>jml</name><uri>http://www.blogger.com/profile/11400080716012026985</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='http://1.bp.blogspot.com/-M_jE0GQZ9H0/TiFSUOGRb8I/AAAAAAAAAEI/w7DhhWkNUZs/s220/Texas-2011-01.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5733547231775030285.post-8249439675228752696</id><published>2011-08-18T13:18:00.000+01:00</published><updated>2011-08-18T13:18:20.035+01:00</updated><title type='text'>How dependency guessing works</title><content type='html'>Although in my &lt;a href="http://code.mumak.net/2011/08/automagic-packaging-of-binary-apps-for.html"&gt;last post&lt;/a&gt; I talked about our proof of concept tool, I didn't actually explain how to use it. That's mostly because it's not quite ready to be used by others. There's a good reason.&lt;br /&gt;&lt;br /&gt;The most interesting thing that &lt;a href="https://code.launchpad.net/~jml/+junk/pkgme-binary"&gt;pkgme-binary&lt;/a&gt; does is to guess the dependencies of an application given only its tarball. The way it does this is by finding all of the ELF objects (executables, shared libraries etc.), reading the symbols from them, and figuring out the packages based on those.&lt;br /&gt;&lt;br /&gt;Canny readers are already thinking, "Yes, that is what dpkg-shlibdeps does" – which is true. As some background, Debian packages that export symbols for linking also provide explicit metadata about those symbols and what versions they appear in, in order to allow Debian packagers to figure out dependencies easily using dpkg-shlibdeps. Fascinating reading can be found in the &lt;a href="http://www.debian.org/doc/debian-policy/ch-sharedlibs.html"&gt;Debian policy manual&lt;/a&gt;, a &lt;a href="http://wiki.debian.org/Projects/ImprovedDpkgShlibdeps"&gt;spec on improving dpkg-shlibdeps&lt;/a&gt; and &lt;a href="http://wiki.debian.org/UsingSymbolsFiles"&gt;the guide on using the new symbol files&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Unfortunately, dpkg-shlibdeps can only query packages that are installed on your system. If you have a binary with symbols that are not provided by any library on your system, you cannot use it to calculate dependencies. Debian (or the Debian flavour of your choosing) might have a perfectly good package to satisfy that dependency, but you won't be able to find it.&lt;br /&gt;&lt;br /&gt;So, to do dependency guessing properly, you need to have a database mapping symbols back to packages. Debian already has something like this in its &lt;a href="http://qa.debian.org/cgi-bin/mole/seedsymbols/"&gt;mole database&lt;/a&gt;. Ubuntu doesn't have anything like this that I know about.&lt;br /&gt;&lt;br /&gt;Assembling and maintaining such a database is pretty much a simple matter of programming, but it's still work that I wanted to avoid for the proof-of-concept. Instead, I used the mole database in Debian for the calculations. That means we'll get wrong answers for Ubuntu, but it demonstrates that the concept works.&lt;br /&gt;&lt;br /&gt;Since I have a copy of that mole database locally, and since it's about 1.5GB, I'm not distributing it with the branch. Which means that the &lt;a href="https://code.launchpad.net/~jml/+junk/pkgme-binary"&gt;automagic binary packaging branch&lt;/a&gt; won't actually work for you.&lt;br /&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5733547231775030285-8249439675228752696?l=code.mumak.net' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://code.mumak.net/feeds/8249439675228752696/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5733547231775030285&amp;postID=8249439675228752696' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5733547231775030285/posts/default/8249439675228752696'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5733547231775030285/posts/default/8249439675228752696'/><link rel='alternate' type='text/html' href='http://code.mumak.net/2011/08/how-dependency-guessing-works.html' title='How dependency guessing works'/><author><name>jml</name><uri>http://www.blogger.com/profile/11400080716012026985</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='http://1.bp.blogspot.com/-M_jE0GQZ9H0/TiFSUOGRb8I/AAAAAAAAAEI/w7DhhWkNUZs/s220/Texas-2011-01.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5733547231775030285.post-1398343073462714935</id><published>2011-08-18T12:52:00.001+01:00</published><updated>2011-08-18T12:57:39.719+01:00</updated><title type='text'>Automagic packaging of binary apps for Ubuntu</title><content type='html'>For the last few weeks I've been working on a tool to automagically package binary applications for Ubuntu.&amp;nbsp;The idea is that anyone who wants to distribute a binary app on Ubuntu should be able to do so without having to learn how to package it.&lt;br /&gt;&lt;br /&gt;I've used &lt;a href="http://pkgme.net/"&gt;pkgme&lt;/a&gt; to build a proof-of-concept: which you can look at here: &lt;a href="https://code.launchpad.net/~jml/+junk/pkgme-binary"&gt;lp:~jml/+junk/pkgme-binary&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Or, you can watch the demo:&lt;br /&gt;&lt;br /&gt;&lt;div class="separator" style="clear: both; text-align: center;"&gt;&lt;object class="BLOGGER-youtube-video" classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0" data-thumbnail-src="http://i.ytimg.com/vi/4oMDo4JbxZY/0.jpg" height="266" width="320"&gt;&lt;param name="movie" value="http://www.youtube.com/v/4oMDo4JbxZY?f=user_uploads&amp;c=google-webdrive-0&amp;app=youtube_gdata" /&gt;&lt;param name="bgcolor" value="#FFFFFF" /&gt;&lt;embed width="320" height="266"  src="http://www.youtube.com/v/4oMDo4JbxZY?f=user_uploads&amp;c=google-webdrive-0&amp;app=youtube_gdata" type="application/x-shockwave-flash"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Right now, the tool assumes that the tarball:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;is an application&lt;/li&gt;&lt;li&gt;contains ELF objects that can be scanned for symbols, which determine the dependencies&lt;/li&gt;&lt;li&gt;has one main executable file&lt;/li&gt;&lt;li&gt;that its contents can be copied into &lt;code&gt;/opt/$PACKAGE/&lt;/code&gt; and can be run from there by an ordinary user&lt;/li&gt;&lt;li&gt;comes with a JSON file specifying extra metadata&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;Our hope is that 90% of the binary applications we get will meet these requirements.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The plan is to take this proof-of-concept and turn it into something that will run server-side behind the &lt;a href="http://developer.ubuntu.com/"&gt;Ubuntu Developer Portal&lt;/a&gt;. Next steps are to spec it out, create a project, start filing bugs and fix the bugs I already know about.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Watch this space for more updates.&lt;br /&gt;&lt;br /&gt;Thanks to James Westby and Adam Conrad for their help in doing the proof-of-concept and to the dozen or so people who helped me get the darn screencast out.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5733547231775030285-1398343073462714935?l=code.mumak.net' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://code.mumak.net/feeds/1398343073462714935/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5733547231775030285&amp;postID=1398343073462714935' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5733547231775030285/posts/default/1398343073462714935'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5733547231775030285/posts/default/1398343073462714935'/><link rel='alternate' type='text/html' href='http://code.mumak.net/2011/08/automagic-packaging-of-binary-apps-for.html' title='Automagic packaging of binary apps for Ubuntu'/><author><name>jml</name><uri>http://www.blogger.com/profile/11400080716012026985</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='http://1.bp.blogspot.com/-M_jE0GQZ9H0/TiFSUOGRb8I/AAAAAAAAAEI/w7DhhWkNUZs/s220/Texas-2011-01.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5733547231775030285.post-2910216578274245847</id><published>2011-08-02T12:05:00.000+01:00</published><updated>2011-08-02T12:05:11.741+01:00</updated><title type='text'>launchpadlib helper</title><content type='html'>I often need to muck around in a Python interpreter to figure out what I need to do with &lt;a href="https://help.launchpad.net/API"&gt;Launchpad's API&lt;/a&gt;. As it is, I write out the same commands over and over.&lt;br /&gt;&lt;br /&gt;Since repetition is a stupid boring job that we should force machines to do while they are still subservient, I wrote &lt;a href="http://paste.ubuntu.com/657088/"&gt;a harness&lt;/a&gt; that, when run, gives you a Python interpreter and a few useful objects for playing with the Launchpad API.&lt;br /&gt;&lt;br /&gt;For example:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;$ ./lpharness.py &lt;br /&gt;lp:     authenticated Launchpad object&lt;br /&gt;me:     logged in user&lt;br /&gt;anon:   anonymous Launchpad object&lt;br /&gt;errors: launchpadlib.errors&lt;br /&gt;uris:   launchpadlib.uris&lt;br /&gt;&lt;br /&gt;pprint: pretty printer&lt;br /&gt;&amp;gt;&amp;gt;&amp;gt; pprint(list(me.searchTasks(status='In Progress')))&lt;br /&gt;[&amp;lt;bug_task at https://api.launchpad.net/1.0/launchpad/+bug/240067&amp;gt;,&lt;br /&gt; &amp;lt;bug_task at https://api.launchpad.net/1.0/launchpad/+bug/418932&amp;gt;,&lt;br /&gt; &amp;lt;bug_task at https://api.launchpad.net/1.0/hydrazine/+bug/535414&amp;gt;,&lt;br /&gt; &amp;lt;bug_task at https://api.launchpad.net/1.0/hydrazine/+bug/574981&amp;gt;,&lt;br /&gt; &amp;lt;bug_task at https://api.launchpad.net/1.0/hydrazine/+bug/612641&amp;gt;,&lt;br /&gt; &amp;lt;bug_task at https://api.launchpad.net/1.0/tarmac/+bug/683351&amp;gt;,&lt;br /&gt; &amp;lt;bug_task at https://api.launchpad.net/1.0/wikkid/+bug/695232&amp;gt;,&lt;br /&gt; &amp;lt;bug_task at https://api.launchpad.net/1.0/launchpad/+bug/721166&amp;gt;,&lt;br /&gt; &amp;lt;bug_task at https://api.launchpad.net/1.0/ensemble/+bug/728320&amp;gt;,&lt;br /&gt; &amp;lt;bug_task at https://api.launchpad.net/1.0/bughugger/+bug/731075&amp;gt;,&lt;br /&gt; &amp;lt;bug_task at https://api.launchpad.net/1.0/tarmac/+bug/807785&amp;gt;,&lt;br /&gt; &amp;lt;bug_task at https://api.launchpad.net/1.0/pkgme/+bug/809447&amp;gt;,&lt;br /&gt; &amp;lt;bug_task at https://api.launchpad.net/1.0/ubuntu-archive-tools/+bug/805634&amp;gt;]&lt;br /&gt;&lt;/pre&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;Script:&amp;nbsp;&lt;a href="http://paste.ubuntu.com/657088/"&gt;http://paste.ubuntu.com/657088/&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;You are free to do whatever you like with it. I hope that someone puts it into some useful, &lt;i&gt;maintained&lt;/i&gt;, centralized place for doing stuff with Launchpad. Perhaps launchpadlib itself.&lt;br /&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-2910216578274245847?l=code.mumak.net' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://code.mumak.net/feeds/2910216578274245847/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5733547231775030285&amp;postID=2910216578274245847' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5733547231775030285/posts/default/2910216578274245847'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5733547231775030285/posts/default/2910216578274245847'/><link rel='alternate' type='text/html' href='http://code.mumak.net/2011/08/launchpadlib-helper.html' title='launchpadlib helper'/><author><name>jml</name><uri>http://www.blogger.com/profile/11400080716012026985</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='http://1.bp.blogspot.com/-M_jE0GQZ9H0/TiFSUOGRb8I/AAAAAAAAAEI/w7DhhWkNUZs/s220/Texas-2011-01.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5733547231775030285.post-9168568010788487059</id><published>2011-07-10T14:52:00.000+01:00</published><updated>2011-07-10T14:52:30.659+01:00</updated><title type='text'>Ubuntu on my iMac</title><content type='html'>Long time readers will know of my attempts to get Ubuntu running on my iMac. Now that I'm working within the Ubuntu Engineering team at Canonical, I figured it would be a good time to try again.&lt;br /&gt;&lt;br /&gt;Installing natively fails on 11.04 in the same way that it failed on 10.10: the installer sends output to the Mini DisplayPort rather than the actual screen. I don't have an external monitor that I can hook up to the DisplayPort, so that's pretty much that.&lt;br /&gt;&lt;br /&gt;I can still run a VM, right? VirtualBox is pretty good, and I got me a running install of Ubuntu with the Unity shell without too much fuss. Problem comes with keyboard configuration. The literal keypresses Cmd+H and Cmd+Q are not passed through to the guest OS. With a Dvorak layout these become Cmd+D and Cmd+", and if one maps Cmd to Meta then you cannot easily kill-word in Emacs. That means for me to have a useful environment, I'd have to make do with Super and Meta swapped around from the usual PC layout.&lt;br /&gt;&lt;br /&gt;VM Fusion doesn't have this problem and has a nicer UI, but I can't run Unity or compiz under it. This makes Ubuntu feel really old and clunky, and I'd rather not do that.&lt;br /&gt;&lt;br /&gt;Parallels, well, at this point I'm running out of the will.&lt;br /&gt;&lt;br /&gt;Think I'll settle on VirtualBox for the time being.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5733547231775030285-9168568010788487059?l=code.mumak.net' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://code.mumak.net/feeds/9168568010788487059/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5733547231775030285&amp;postID=9168568010788487059' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5733547231775030285/posts/default/9168568010788487059'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5733547231775030285/posts/default/9168568010788487059'/><link rel='alternate' type='text/html' href='http://code.mumak.net/2011/07/ubuntu-on-my-imac.html' title='Ubuntu on my iMac'/><author><name>jml</name><uri>http://www.blogger.com/profile/11400080716012026985</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='http://1.bp.blogspot.com/-M_jE0GQZ9H0/TiFSUOGRb8I/AAAAAAAAAEI/w7DhhWkNUZs/s220/Texas-2011-01.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5733547231775030285.post-2853274017358241093</id><published>2011-06-20T12:10:00.000+01:00</published><updated>2011-06-20T12:10:17.999+01:00</updated><title type='text'>Leaving Launchpad, going to work on Ubuntu</title><content type='html'>After four and a half years of working on &lt;a href="https://launchpad.net/"&gt;Launchpad&lt;/a&gt;, I'm moving on within Canonical, taking a &lt;a href="http://t.co/R37ybBu"&gt;position&lt;/a&gt; on the Ubuntu Engineering team, working to get more and better apps on &lt;a href="http://ubuntu.com/"&gt;Ubuntu&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;I am very excited about the change, but also a little sad, since it will mean leaving what has been &lt;i&gt;the&lt;/i&gt; best team I've worked on.  They are a wonderful bunch of people who not only get a lot of great stuff done, but consistently surprise me with their constant drive to get better at what they do.&lt;br /&gt;&lt;br /&gt;Over the last couple of years, we have changed the way we are organized so that we can focus on building a small number of features at a time, the features that we do churn out are much, much better, we are rolling out new versions of Launchpad multiple times a week and we are actually paying off technical debt.&lt;br /&gt;&lt;br /&gt;And they've needed to: Launchpad is a massive, ambitious application.  I've never worked on something so big that aims to do so much, and with so few people actually hacking on it.&lt;br /&gt;&lt;br /&gt;I still care a lot about Launchpad, It's crammed with potential and has so much to offer the open source world. It's going to be hard for me to move on.&lt;br /&gt;&lt;br /&gt;But, wow, what a place to move on to, and what a time to do it. Ubuntu is aiming to go from about 20 million users to about 200 million, and to do that is going to need way, way more apps than they have now.  To do &lt;i&gt;that&lt;/i&gt;, we'll need a spiffing developer programme, and that's where I come in. I'll be loading up on information, plans and more concrete goals in a couple of week's time in Dublin, and will share them as I can.&lt;br /&gt;&lt;br /&gt;Oh, and if you want to guide the world's &lt;a href="https://launchpad.net/"&gt;best open source development collaboration platform&lt;/a&gt; into the future, do drop me or &lt;a href="https://launchpad.net/~flacoste"&gt;Francis Lacoste&lt;/a&gt; a line.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5733547231775030285-2853274017358241093?l=code.mumak.net' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://code.mumak.net/feeds/2853274017358241093/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5733547231775030285&amp;postID=2853274017358241093' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5733547231775030285/posts/default/2853274017358241093'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5733547231775030285/posts/default/2853274017358241093'/><link rel='alternate' type='text/html' href='http://code.mumak.net/2011/06/leaving-launchpad-going-to-work-on.html' title='Leaving Launchpad, going to work on Ubuntu'/><author><name>jml</name><uri>http://www.blogger.com/profile/11400080716012026985</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='http://1.bp.blogspot.com/-M_jE0GQZ9H0/TiFSUOGRb8I/AAAAAAAAAEI/w7DhhWkNUZs/s220/Texas-2011-01.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5733547231775030285.post-6063895291654576682</id><published>2011-06-12T14:08:00.000+01:00</published><updated>2011-06-12T14:08:41.863+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='testtools'/><title type='text'>testtools 0.9.11 released</title><content type='html'>While I slept, &lt;a href="https://launchpad.net/~lifeless"&gt;Robert Collins&lt;/a&gt; released &lt;a href="http://pypi.python.org/pypi/testtools/0.9.11"&gt;testtools 0.9.11&lt;/a&gt;. This release is mostly a bug fix release, but the fixes are very much worthwhile.&lt;br /&gt;&lt;br /&gt;In particular, &lt;a href="https://launchpad.net/~gz"&gt;Martin [gz]&lt;/a&gt; got our Python 3 support going again, &lt;a href="http://gavinpanella.com/"&gt;Gavin Panella&lt;/a&gt; fixed up a dodgy Matcher and fixed a bug in how we feed information from fixtures into test results.&lt;br /&gt;&lt;br /&gt;Also in this release, &lt;a href="https://launchpad.net/~tcole"&gt;Tim Cole&lt;/a&gt; and &lt;a href="http://sourcefrog.net/"&gt;Martin Pool&lt;/a&gt; made their first ever patches, for which they have my hearty thanks and congratulations. (The congratulations are also hearty.)&lt;br /&gt;&lt;br /&gt;As always, it's just so darn &lt;i&gt;pleasant&lt;/i&gt;&amp;nbsp;to see so many fine people working together to make an open source project work.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5733547231775030285-6063895291654576682?l=code.mumak.net' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://code.mumak.net/feeds/6063895291654576682/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5733547231775030285&amp;postID=6063895291654576682' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5733547231775030285/posts/default/6063895291654576682'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5733547231775030285/posts/default/6063895291654576682'/><link rel='alternate' type='text/html' href='http://code.mumak.net/2011/06/testtools-0911-released.html' title='testtools 0.9.11 released'/><author><name>jml</name><uri>http://www.blogger.com/profile/11400080716012026985</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='http://1.bp.blogspot.com/-M_jE0GQZ9H0/TiFSUOGRb8I/AAAAAAAAAEI/w7DhhWkNUZs/s220/Texas-2011-01.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5733547231775030285.post-210307413493105982</id><published>2011-04-11T13:44:00.002+01:00</published><updated>2011-04-11T13:44:58.605+01:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='testtools'/><title type='text'>testtools 0.9.10 released</title><content type='html'>There was a bug in testtools 0.9.9 that prevented it from being easy_installed. Tres Seaver has fixed this bug, and I've rolled out a new release: &lt;a href="http://pypi.python.org/pypi/testtools"&gt;testtools 0.9.10&lt;/a&gt;. Sorry for the inconvenience folks.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5733547231775030285-210307413493105982?l=code.mumak.net' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://code.mumak.net/feeds/210307413493105982/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5733547231775030285&amp;postID=210307413493105982' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5733547231775030285/posts/default/210307413493105982'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5733547231775030285/posts/default/210307413493105982'/><link rel='alternate' type='text/html' href='http://code.mumak.net/2011/04/testtools-0910-released.html' title='testtools 0.9.10 released'/><author><name>jml</name><uri>http://www.blogger.com/profile/11400080716012026985</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='http://1.bp.blogspot.com/-M_jE0GQZ9H0/TiFSUOGRb8I/AAAAAAAAAEI/w7DhhWkNUZs/s220/Texas-2011-01.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5733547231775030285.post-3946464801057171567</id><published>2011-04-08T13:00:00.000+01:00</published><updated>2011-04-08T13:00:17.005+01:00</updated><title type='text'>testtools 0.9.9 released</title><content type='html'>&lt;a href="http://pypi.python.org/pypi/testtools"&gt;testtools&lt;/a&gt; 0.9.9 has been released today. For me, the twin pillars of this release have been our &lt;a href="http://readthedocs.org/docs/testtools/en/latest/"&gt;vast documentation improvements&lt;/a&gt;&amp;nbsp;and &lt;a href="http://readthedocs.org/docs/testtools/en/latest/for-test-authors.html#matchers"&gt;the new matchers&lt;/a&gt;, which make it very, very easy to make meaningful assertions about complex objects. Well worth checking out.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Thanks to&amp;nbsp;Christian Kampka, Robert Collins, Aaron Bentley,&amp;nbsp;Jelmer Vernooij and Michael Hudson-Doyle their contributions.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5733547231775030285-3946464801057171567?l=code.mumak.net' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://code.mumak.net/feeds/3946464801057171567/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5733547231775030285&amp;postID=3946464801057171567' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5733547231775030285/posts/default/3946464801057171567'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5733547231775030285/posts/default/3946464801057171567'/><link rel='alternate' type='text/html' href='http://code.mumak.net/2011/04/testtools-099-released.html' title='testtools 0.9.9 released'/><author><name>jml</name><uri>http://www.blogger.com/profile/11400080716012026985</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='http://1.bp.blogspot.com/-M_jE0GQZ9H0/TiFSUOGRb8I/AAAAAAAAAEI/w7DhhWkNUZs/s220/Texas-2011-01.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5733547231775030285.post-782473392010164529</id><published>2011-03-08T09:02:00.000Z</published><updated>2011-03-08T09:02:09.031Z</updated><title type='text'>mdz on listening to users</title><content type='html'>&lt;a href="http://mdzlog.alcor.net/"&gt;Matt Zimmerman&lt;/a&gt; writes about whether we should&amp;nbsp;&lt;a href="http://mdzlog.alcor.net/2011/03/07/listening-to-users/"&gt;listen to users&lt;/a&gt;. It's a great post, and you should read it, but the summary is:&lt;br /&gt;&lt;br /&gt;&lt;ol&gt;&lt;li&gt;If you want inspiration for a new product, don't listen to users, watch them&lt;/li&gt;&lt;li&gt;To test whether a product is a good fit, ask users for feedback and listen to it&lt;/li&gt;&lt;li&gt;If you want to incrementally improve an existing offering, don't listen, gather data&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;I'm over-simplifying, you should read the original post. I also wonder whether it should be "when is it safe to not act on user feedback", rather than "not listening" per se.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5733547231775030285-782473392010164529?l=code.mumak.net' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://code.mumak.net/feeds/782473392010164529/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5733547231775030285&amp;postID=782473392010164529' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5733547231775030285/posts/default/782473392010164529'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5733547231775030285/posts/default/782473392010164529'/><link rel='alternate' type='text/html' href='http://code.mumak.net/2011/03/mdz-on-listening-to-users.html' title='mdz on listening to users'/><author><name>jml</name><uri>http://www.blogger.com/profile/11400080716012026985</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='http://1.bp.blogspot.com/-M_jE0GQZ9H0/TiFSUOGRb8I/AAAAAAAAAEI/w7DhhWkNUZs/s220/Texas-2011-01.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5733547231775030285.post-410101800974954324</id><published>2011-02-02T12:04:00.000Z</published><updated>2011-02-02T12:04:01.146Z</updated><title type='text'>Music is too hard</title><content type='html'>It's way too hard to keep all of my music stored on one machine in a lossless format, have it backed up to another machine, synced to my iPod in MP3 and have it pleasingly playable on my OS X computer. Way too hard. Really.&lt;br /&gt;Especially since fixes to track listings and so forth seem to vanish like smoke in the breeze. Banshee and Rhythmbox both pretend to help, but that's only so they can mess with my life more.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5733547231775030285-410101800974954324?l=code.mumak.net' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://code.mumak.net/feeds/410101800974954324/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5733547231775030285&amp;postID=410101800974954324' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5733547231775030285/posts/default/410101800974954324'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5733547231775030285/posts/default/410101800974954324'/><link rel='alternate' type='text/html' href='http://code.mumak.net/2011/02/music-is-too-hard.html' title='Music is too hard'/><author><name>jml</name><uri>http://www.blogger.com/profile/11400080716012026985</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='http://1.bp.blogspot.com/-M_jE0GQZ9H0/TiFSUOGRb8I/AAAAAAAAAEI/w7DhhWkNUZs/s220/Texas-2011-01.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5733547231775030285.post-2760044447945880562</id><published>2011-01-25T18:02:00.000Z</published><updated>2011-01-25T18:02:02.722Z</updated><title type='text'>Expressing agreement and disagreement numerically</title><content type='html'>There's a habit within Canonical on expressing agreement and disagreement numerically. If we agree with something someone says in email or IRC, we'll often say "+1", which means "I agree!" or "if we were to vote about this, you would have my vote". I sometimes hear people actually say the words "plus one" in conversation.&lt;br /&gt;&lt;br /&gt;Some have extrapolated from this to say "-1" to mean "I disagree", which is a pretty natural thing to do. However, it confuses me a lot.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;"&gt;You see, the "+1" thing is a little bit like the&amp;nbsp;&lt;a href="http://httpd.apache.org/dev/guidelines.html"&gt;Apache voting system&lt;/a&gt;, which I met in my early days of open source, back when I lurked on the Subversion development mailing list. The voting rules there were burned into my mind, and I foolishly assume that they are equally fundamental to everyone else.&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;In the Apache system, "-1" means "veto", which is a very strong way of disagreeing. When people on the Launchpad say "-1", I never really know what they mean. I don't blame them, "-1" is a bit of a silly way of vetoing a proposal. I bet if keyboards had a key for&amp;nbsp;∞, there'd be a much more sensible way.&lt;br /&gt;&lt;br /&gt;I guess the moral of the story is, "ambiguous shorthand is ambiguous".&lt;br /&gt;&lt;br /&gt;Incidentally, how does the Apache voting system work out in practice these days?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5733547231775030285-2760044447945880562?l=code.mumak.net' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://code.mumak.net/feeds/2760044447945880562/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5733547231775030285&amp;postID=2760044447945880562' title='7 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5733547231775030285/posts/default/2760044447945880562'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5733547231775030285/posts/default/2760044447945880562'/><link rel='alternate' type='text/html' href='http://code.mumak.net/2011/01/expressing-agreement-and-disagreement.html' title='Expressing agreement and disagreement numerically'/><author><name>jml</name><uri>http://www.blogger.com/profile/11400080716012026985</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='http://1.bp.blogspot.com/-M_jE0GQZ9H0/TiFSUOGRb8I/AAAAAAAAAEI/w7DhhWkNUZs/s220/Texas-2011-01.jpg'/></author><thr:total>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5733547231775030285.post-818956548715443266</id><published>2010-12-23T16:09:00.000Z</published><updated>2010-12-23T16:09:57.091Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='launchpad'/><title type='text'>Larval prototype for Launchpad dashboards</title><content type='html'>I mentioned &lt;a href="http://code.mumak.net/2010/11/and-then-what.html"&gt;a while ago&lt;/a&gt; that I really want to see something like a dashboard in Launchpad, some kind of view that shows you everything that you &lt;i&gt;must&lt;/i&gt;&amp;nbsp;do, everything that you are waiting on from others and&amp;nbsp;all of your current work-in-progress. Launchpad could do this really well, since it has rich, inter-linked data about what's going on and since it can show you this information for all of your projects.&lt;br /&gt;&lt;br /&gt;Today, I knocked up a very quick-and-dirty prototype for this. It shows all of the work-in-progress for a person across all of Launchpad, grouped by project.&lt;br /&gt;&lt;br /&gt;The code lives at &lt;a href="https://code.launchpad.net/~jml/+junk/whip"&gt;lp:~jml/+junk/whip&lt;/a&gt; and you can see examples of &lt;a href="http://people.canonical.com/~jml/jml-wip.html"&gt;my work-in-progress&lt;/a&gt; and &lt;a href="http://people.canonical.com/~jml/jelmer-wip.html"&gt;jelmer's work-in-progress&lt;/a&gt; online. You should be able to make your own with './bin/whip $LP-NAME &amp;gt; wip.html'. Note that there'll be some PYTHONPATH shenanigans.&lt;br /&gt;&lt;br /&gt;Hackers, I'd love to see if you could turn this prototype into a web-app, or even a page on Launchpad. There's a NOTES file in there with whatever ideas I've had.&lt;br /&gt;&lt;br /&gt;Designers, there's got to be a better way of showing this data than what I've picked. Take a look at the examples and see what you can turn them into.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5733547231775030285-818956548715443266?l=code.mumak.net' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://code.mumak.net/feeds/818956548715443266/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5733547231775030285&amp;postID=818956548715443266' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5733547231775030285/posts/default/818956548715443266'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5733547231775030285/posts/default/818956548715443266'/><link rel='alternate' type='text/html' href='http://code.mumak.net/2010/12/larval-prototype-for-launchpad.html' title='Larval prototype for Launchpad dashboards'/><author><name>jml</name><uri>http://www.blogger.com/profile/11400080716012026985</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='http://1.bp.blogspot.com/-M_jE0GQZ9H0/TiFSUOGRb8I/AAAAAAAAAEI/w7DhhWkNUZs/s220/Texas-2011-01.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5733547231775030285.post-8798343538771109683</id><published>2010-12-22T19:19:00.000Z</published><updated>2010-12-22T19:19:03.733Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='testtools'/><title type='text'>testtools 0.9.8 released</title><content type='html'>The announcement is a few days late, but I thought that you'd like to know that &lt;a href="http://pypi.python.org/pypi/testtools"&gt;testtools 0.9.8&lt;/a&gt; has been released.&lt;br /&gt;&lt;br /&gt;This is one of our biggest releases, we have fixed &lt;a href="https://launchpad.net/testtools/0.9/0.9.8"&gt;a lot of bugs&lt;/a&gt;, added experimental support for running tests inside Twisted's reactor and added a stack of new matchers and convenience methods. It's well worth upgrading.&lt;br /&gt;&lt;br /&gt;We've also got some good stuff in the pipeline, including a full re-working of our documentation, better error messages and still more matchers.&lt;br /&gt;&lt;br /&gt;The "more matchers" thing is significant. More and more people are starting to use testtools because of the way our matchers let them build domain-specific assertions with rich, useful error messages. We continue to get contributions for basic matchers and for new ways of combining matchers. Also, projects like James Westby's &lt;a href="https://launchpad.net/soupmatchers"&gt;soupmatchers&lt;/a&gt;&amp;nbsp;show just how useful matchers can be. It makes me think that eventually matchers will become part of the normal way that people write tests in Python.&lt;br /&gt;&lt;br /&gt;Thanks to &lt;a href="https://launchpad.net/~lifeless"&gt;Robert Collins&lt;/a&gt;, &lt;a href="https://launchpad.net/~gz"&gt;Martin [gz]&lt;/a&gt;, &lt;a href="https://launchpad.net/~jelmer"&gt;Jelmer Vernooij&lt;/a&gt;, &lt;a href="https://launchpad.net/~mwhudson"&gt;Michael Hudson-Doyle&lt;/a&gt; and &lt;a href="https://launchpad.net/~james-w"&gt;James Westby&lt;/a&gt; for making this our best release ever.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5733547231775030285-8798343538771109683?l=code.mumak.net' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://code.mumak.net/feeds/8798343538771109683/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5733547231775030285&amp;postID=8798343538771109683' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5733547231775030285/posts/default/8798343538771109683'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5733547231775030285/posts/default/8798343538771109683'/><link rel='alternate' type='text/html' href='http://code.mumak.net/2010/12/testtools-098-released.html' title='testtools 0.9.8 released'/><author><name>jml</name><uri>http://www.blogger.com/profile/11400080716012026985</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='http://1.bp.blogspot.com/-M_jE0GQZ9H0/TiFSUOGRb8I/AAAAAAAAAEI/w7DhhWkNUZs/s220/Texas-2011-01.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-5733547231775030285.post-2898476574400586653</id><published>2010-12-10T23:03:00.000Z</published><updated>2010-12-10T23:03:10.463Z</updated><category scheme='http://www.blogger.com/atom/ns#' term='testtools'/><title type='text'>testtools bug update</title><content type='html'>Hello &lt;a href="https://launchpad.net/testtools"&gt;testtools&lt;/a&gt; fans.&lt;br /&gt;&lt;br /&gt;If you are wondering what all the recent bug mail was about, wonder no more, for I shall explain. Thus.&lt;br /&gt;&lt;br /&gt;We're using only three different levels of importance for testtools bugs: Critical, Medium and Wishlist. Critical is reserved for release blockers: regressions, test failures and other disasters. Medium is for genuine defects and other things that we think are important. Wishlist is for everything else. I think of them as Critical, Important and Someday.&lt;br /&gt;&lt;br /&gt;All of this is in preparation for the 0.9.8 release, which promises to be a doozy. &amp;nbsp;Stay tuned.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5733547231775030285-2898476574400586653?l=code.mumak.net' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://code.mumak.net/feeds/2898476574400586653/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=5733547231775030285&amp;postID=2898476574400586653' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/5733547231775030285/posts/default/2898476574400586653'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/5733547231775030285/posts/default/2898476574400586653'/><link rel='alternate' type='text/html' href='http://code.mumak.net/2010/12/testtools-bug-update.html' title='testtools bug update'/><author><name>jml</name><uri>http://www.blogger.com/profile/11400080716012026985</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='31' src='http://1.bp.blogspot.com/-M_jE0GQZ9H0/TiFSUOGRb8I/AAAAAAAAAEI/w7DhhWkNUZs/s220/Texas-2011-01.jpg'/></author><thr:total>0</thr:total></entry></feed>
