Thanks to the excellent work from the Launchpad Code team and others (James and William, to name just two), here’s a preview of how easy it will soon be to build a branch into published binaries in your PPA:

Having just been through the process of trying to involve people in open source design and development, Maris Fogels (another Launchpad engineer) and I took some time to document/reflect on the process. The strongest point that came out of the Q&A for me is the importance of voice conversations for iterating a design like this.

Ubuntu is beginning to manage its source packages as Bazaar branches, as part of the DistributedDevelopment project.

One incredibly important activity for source packages is building them into binary packages that can be downloaded and installed. This spec explains how Launchpad can make this a wonderful experience.

Mars: Have you done any work designing user interfaces before this?

Michael: A little – we went through a similar process for the PPA redesign as
part of Launchpad 3.0. Prior to that, no, only your typical “Oh this
needs a UI – let’s just start creating the UI that *we* think the
target users will want.”

We had tried (in the Launchpad Soyuz team) doing something similar to
this design process previously (particularly, defining stories for an
interaction before coding, and getting feedback from the people
representing the target users), but no matter how hard we tried, we
weren’t able to get the time with them or any feedback, and so we
ended up implementing the design and landing it without their
feedback, which was a mistake – and a lesson learned which influenced
the process I used here.

Mars: What tools and resources did you use as you went through the project?

Michael: Balsamiq, wikis, email discussions and phone calls. Balsamiq was great
as a way to create UI’s quickly, modify them easily as we learned
more, share them for others to modify (I just pushed a bzr branch that
I kept up to date).

Mars: Was there a particular process that you followed?

Michael: Basically I tried to:

Identify and describe the use-cases,

Create mockups for each use-case,

Get feedback from as many people as possible,

and then constantly update or add new use-cases and mockups as more
info came in. Looking back, it seems we went through three definite
iterations.

Mars: How long did it take to design the page?

Michael: We just designed the main interactions to build a branch into a PPA,
which is 2 pages/overlays (they’ll be overlays if js is enabled). I
think the process (3 iterations above of gathering feedback,
phone-calls etc.) spanned 3 weeks, on and off.

Mars: Do you think the problem was well-understood before you started working on the user interface?

Michael: I think different people understood their own domains of the
build-from-branch interaction, and everyone had ideas about how the
other parts should work, but no, I don’t think any of us understood
the use-cases properly – particularly the issues around re-using
recipes in the UI – until all the ideas and feeback was collected and
put together.

Mars: Did the design of the interface change much as work progressed?

Old vs. New

Michael: Yes, quite a bit. Initially I had initially (mis)understood that we
needed to work with the current implementation of bzr-builder, but
after the first iteration, James Westby pointed out that bzr-builder
can be updated to support the requirements of the UI. This freed us to
consider sharing recipes in the UI in a way that would not have been
possible otherwise.

Collecting and expanding the use-cases naturally required updates to
the design. Also feedback and questions from various people helped to
keep refocusing on what people want to be able to do (for example,
“This recipe supports building to Ubuntu Lucid, Ubuntu 9.10 and Ubuntu
9.04″, while still allowing the person using the recipe to select just
the distroseries they want).

Mars: How did you get feedback on your designs? Was there a good response?

Michael: (Just an aside, there’s no ‘y’ there – they are really our designs, I
was just filtering and focusing the collected thoughts and ideas into
something visible).

So as above, email to the dev list, then irc chats, but the biggest
throughput of communication and feedback came via actual calls. It’s
just so much easier to clear misunderstandings on the spot if you walk
through the process together. I had multiple calls with 6 different
people, all which were invaluable.

With (1) the best I could do with the time I had was to communicate
with representatives of target users, which I think worked quite well.
And (2) was difficult mostly due to the nature of the problem for
build-from-branch. IMO it requires someone to sit physically in the
office and walk through the process with a designer, something I
couldn’t do, and hasn’t been done yet as far as I know.

Mars: What did you most enjoy about the work?

Michael: Bringing lots of ideas together from lots of people, clarifying the
different needs to different people to build a common understanding of
the issues involved.

But, to be honest, I am also enjoying getting back to soyuz coding. I
enjoy doing this kind of thing for a week or two, but after that I’m
always keen to get back to doing some coding.

I think I (and James?) also enjoyed the fact that we could work on
defining the interaction *before* anything had been coded. Too often
we get in there and just start coding something without thinking
through the use-cases properly (or even defining them), and it ends up
causing a lot of pain. Like everything, it’s a learning process.

Mars: Any final words for developers looking to try this themselves?

Michael: Sure, if you’d like a change of rhythm and enjoy facilitating
conversations and ideas, give it a go – it’s a great chance to
interact with other people in different areas and build your
understanding of what people actually want to do with your product.

Every time that I upgrade my operating system, I feel like I’m receiving a whole bunch of gifts from people I don’t know – which actually is what’s happening! As I learn more about the Debian and Ubuntu communities, and Launchpad (which I’ve been working on for the past year), I never stop feeling awed at the amount of effort that is being filtered through Launchpad (in both directions) in terms of bug-fixes, new packages, translations etc., into end-products that rock!

Having upgraded my netbook a few weeks ago, over the weekend I decided to upgrade my work machine to test the latest development release, Ubuntu Lucid, and the only difficult part of the process was having to install Windows XP to update my bios (because Samsung, the manufacturer of my work laptop, only provide bios updates as win-32 applications). Other than that, it’s been a joy seeing all the improvements (like the open-source nvidia support – a few clicks and my dual monitors worked perfectly, something I could only do previously with the proprietary drivers).

So, whether it is heard or not, I want to say a big thanks to the millions involved for the gift – my Lucid experience has been wonderful.

A few weeks ago at our Launchpad BuildFromBranch sprint, I gave a brief overview of the process I use when doing a significant design change – whether it’s a code architecture or UI design (hint: don’t try to do a presentation after flying for 26 hours with two kids).

The main point that I was keen to communicate is how important it is to involve people and get early feedback. Launchpad bugs provide a great way to invite this involvement too, as you’ve already got many of the interested people already subscribed, and if you add information early other people – such as the person who created the bug – have an opportunity to clarify and contribute to the design or solution.

As a result of our sprint, we’re now focusing on how we can provide the best user experience for automating the process of building code into installable packages that will be updated on peoples machines the next day. In particular, we want to enable easy setup of daily builds for projects, allowing people who like to live on the edge and contribute QA time to their favourite open-source projects (building on the excellent work of bzr-builder).

To encourage involvement in this process, I’m trying a combination of relevant email lists for discussion, phone calls where helpful, and a wiki page that I try to keep up-to-date with the current status of those discussions. The aim being that anyone can read the wiki page and, in addition to seeing the current UI mockups, can see all the significant questions that have been brought up already. We’ll see how it goes…

Reading all the comments there leaves me wondering whether we should stop using the phrase “web-of-trust” and instead use the more verbose “web-of-identity-trust” to avoid confusion – even though it doesn’t roll off the tounge so easily. I love Martin’s idea – the concern is real – but am wondering how it could be implemented in a decentralised way.

Of course, it would be possible to add this as an api feature of Launchpad – my feeling is that Launchpad should be a source of the social value of an archive (ie. user ratings etc.), but not necessarily a source of this fundamental trust-relationship.

So here is an idea: what if the repository contained this infrastructure itself, such as a directory of meta-information, ‘identities-who-trust-this-archive’, which contained signed trust files ‘trust-of-canonical.txt’ or ‘trust-of-joe-bloggs.txt’. The text could just be a standard paragraph, or be modified by the signer if needed. The installer on the operating system would allow the user to check the trust text etc. Could this work? Can anyone see any issues? (hmm… revoking trust would not be possible without revoking the key used to sign the document?)

For over 6 months now I’ve been working on launchpad.net – collaborative development for open source software – using Python (Zope). It’s been an unreal experience seeing various testing strategies on such a large code-base, but the two things I miss the most while developing on launchpad are:

The ability to do outside-in development properly – as is possible with ruby’s Cucumber project (although, this could be used, but it’d be adding yet-another-technology to the stack – I haven’t tried pyCucumber, but it doesn’t look too active), and

Something similar to rspactor – allowing tests to be run automatically as I edit files, and reporting them via the OS’s notification system.

But trying to communicate exactly what I mean by that to people who haven’t used rspactor or Cucumber is kind-of tricky, so here’s a video demo’ing how I’d love to do inside-out development on Ubuntu…

Since working with RSpec over the past 6 months – a Behaviour-Driven Development framework for ruby – I’ve been wondering if there’s anything comparable in Python (my preferred tool for development!). One of the things I love about RSpec is the ease with which Mock objects can be used to keep tests focused.

While there are a number of mock libraries around for Python most don’t result in particularly readable test code. But I was pleasantly suprised to discover Michael Foord’s Mocking and Testing utilities.

A simple example: I’ve got a Django application hosted on Google AppEngine and say I want to write a simple test to verify that my view does require the user to be logged in with their Google account and if not, redirects appropriately – but I don’t want to have to manually log a user in, or even use the Google api as part of my test. Here’s a snippet showing how easy this is with Mock:

from mock import Mockfrom google.appengine.api import users
class MySpecialView(TestCase):
def setUp(): """ Create the required mocks for the view tests """ # Mock the get_current_user method of the google users api users.get_current_user = Mock()
# Create a mock user that we'll pretend is logged in mock_user = Mock()
# Just for readability, save the special app-engine login url as # an instance variable self.url = reverse('my-special-view-name') self.login_url = "http://testserver/_ah/login?continue=http%%3A//testserver%s" % self.url
def test_logged_in_user_can_access_page(self): """A logged in user should not be redirected to the login page""" # Set the return value for the mocked # get_current_user method: users.get_current_user.return_value = mock_user
response = do_request()
# Make sure the mock method was called self.assertTrue(users.get_current_user.called)
# And the redirect did not take place, but the # normal template was rendered... self.assertTemplateUsed(response, 'myapp/overview.html')
def test_anonymous_user_is_redirected_to_login(self): """ An anonymous user should be redirected to the login page""" # Set the google api's get_current_user method to return None users.get_current_user.return_value = None
response = self.do_request()
# Make sure the mock method was called self.assertTrue(users.get_current_user.called)
# And that the redirect took place... note we can't use # the normal assertRedirects due to the app-engine specific # login url. self.assertEquals(response.status_code, 302) self.assertEquals( response['location'], "http://testserver/_ah/login?continue=http%%3A//testserver%s" % self.url )

Easy! Thanks Michael. The Mock object has lots of other goodies of course (such as auto-setting all the mock-methods from the real object, testing for call parameters etc.).