I love the OSA

Inspired by Nat Pryce’s recent scrapheap challenge idea for a Name That Tune style game, and given I’ve been having so much fun with the Ruby OSA lately, I decided to implement my own solution using it to drive iTunes and I had a lot of fun in the process.

I started by grabbing a reference to iTunes:

%w(rubygems rbosa).each {|lib| require lib }

itunes = OSA.app("iTunes")

And then playing about with it until I found the right properties to look at and methods to call. As the game requires a constant stream of random tracks, I thought using the Party Shuffle feature of iTunes to would fit just right. The Party Shuffle is a special playlist that sits inside your library:

library = itunes.sources.find {|s| s.kind == OSA::ITunes::ESRC::LIBRARY }
party_shuffle = library.playlists.find {|p| p.special_kind == OSA::ITunes::ESPK::PARTY_SHUFFLE }

With that party_shuffle (an OSA::ITunes::Playlist object) at hand, it’s pretty easy to do the rest: playing, changing tracks and figuring out how to score each guess.

If you can grab the complete solution and make it into a nice little dashboard widget, I’ll be forever in debt!


BONUS UPDATE: I just finished refactoring a couple of things (namely, moving the monkey patching of OSA::ITunes away - it’s now in itunes.rb) and, in the process of doing so, Tune Fight was born!

Geek
General

Comments (2)

Permalink

How would you improve this page?

On an application I’ve been working during my spare time, I had the need to ask my loyal friends and guinea pigs to give me some feedback, in order to help me fill in the gaps between what I think they want to do and what they really want to do in this application.

A quick, cheap and really useful solution I came up with was adding a feedback form right there, on every page the application renders. This can certainly be improved by people more knowledgeable in Rails than myself, as for now it doesn’t even use AJAX to post the data back (shame, shock and horror!)

After running scaffold_resource Comment body:text uri:string created_by:integer created_at:timestamp, you should be pretty much set to go. Now, on your application.rhtml, you can do something like:

<%= render :partial => "comment", :collection =>
Comment.find_all_by_uri(request.request_uri) %> <% form_for :comment, Comment.new, :url => comments_path do |f| %> <%= f.hidden_field :uri, :value => request.request_uri %> How would you improve this page? <%= f.text_area :body, :rows => 5 %> <%= submit_tag 'Add comment' %> <% end %>

The _comment.rhtml partial is something like this:

<%= comment.body %>
Created by <%= if comment.created_by.nil?
    'unknown'
else
    link_to(comment.created_by.name,
      profile_url(comment.created_by.profile))
end %>

<%= time_ago_in_words comment.created_at %> ago

[<%= link_to 'Destroy', comment_path(comment.id), :method => :delete %>]

Customize the Comment controller slightly, and that’s it — instant feedback forms everywhere! :)

Geek
General
Work

Comments (2)

Permalink

On Socks and Services

Every morning, you have a shower and put some clean socks on. You might still wear the same trousers as the other day, or that t-shirt you wore last friday. Or even an inside-out pair of boxers if you just can’t be bothered. But in the name of all that’s sacred, you need a fresh pair of socks every morning. Don’t dispute this fact.

And there are millions of ways to end up with at least one pair of fresh socks in your drawer, but it’s basically down to either constantly buying new ones, washing them yourself or getting someone else to do it for you, with various degrees of automation.

Suppose, like me, you already tried to buy a 7-pack of socks every week for about two months and realised that was a bad economic decision (and also not a very ecological one), and that you want to dedicate your time at home to learn how to cook that stuff you see on Cooking For Engineers, instead of having to constantly remind yourself to do the laundry. You just don’t want to think too much about it, if at all.

In fact, you want to minimise your involvement in the time it takes to do it, even if the task itself takes a bit longer. The laundrette next door seems like a good idea in this case - your involvement is reduced as now you don’t have to do so many little washes because of the laughable size of the washing machine in your flat.

This would be the equivalent of something like a Web Service. You have to go there, in baskets as big and full as possible as to avoid doing too many trips. You’re subject to environment instability (after all, it’s annoying to walk there in the rain or if the network is playing up) but the economies of scale make it quite cheap. Amazon S3 is a great example.

Then there’s the other laundrette on the high street, which offers pick-up and drop-off. You have even less involvement because now even the question of how your socks get to the service is out of your mind. An equivalent would be a good runtime library - you don’t care how it does it, you just tell it to do stuff, and it works. The environment doesn’t interfere as much, but contrary to the laundrette example, libraries are a lot cheaper to use - in fact, you’ll see in this an inverse relation of cost between the examples.

If you really don’t want to think about the socks, though, you’ll want to hire a maid. A maid will set you back a considerable amount, but your involvement is absolutely zero and your clothes would get washed as soon as they become dirty: a considerably better service. An equivalent would be language runtime features such as a GC, which are almost invisible except when you attend to the fact you’re not doing it yourself.

From there, we can extrapolate:

As software developer-facing services become more elaborate, they require less involvement and cost less to use.

As sock-washing services become more elaborate, they require less involvement and cost more to use.

I imagine we can all quickly understand now why asking your girlfriend to do your laundry is a bad idea, but I’m not sure what’s the software development lesson from all of this.

Geek
General

Comments (5)

Permalink

A first

I’m just writing this quick post to celebrate the fact that, today, for the first time in my life, after sitting at or being near computers for pretty much as long as I can remember being conscious, I have managed to successfully install a printer and use it to print a document without a defect, misaligned margin, glitch, blur, fault, smudge, error, discoloration, warning, beep, loose cable or irritating pop-up.

You wouldn’t believe that, but the feeling is quite underwhelming. It’s like waking up to the fact that you’re just yet another mediocre carbon-based organism spreading filth in a universe that doesn’t need any more of it. It doesn’t make you feel any special, but anyway, thanks Apple Bonjour: at least I’m now a filthy carbon-based organism capable of printing documents without having a nervous breakdown - just like everyone else.

Geek
General

Comments (2)

Permalink

Thoughts on my experiments with Io

After a fit of Smalltalk envy a while ago, I’ve been playing with the idea of having an instance of my VM being seemingly “always up” and adding more and more code to it in an iterative fashion as I went through developing a system.

On top of that, after looking at the Rails Migrations and other database refactoring tools, it occurred to me that I should be able to do something quite similar to what migrations do to databases in my own code: instead of trying to keep a very regular and smooth codebase, I’d keep track of the changes applied to an “empty” environment, each change providing some value and tests on its own. Also, I should be able to dump some of the VM’s contents back into a script that can be executed on a “clean” VM and the behaviour between both machines should be the same.

My current language of choice, the very small, elegant and simple Io, made it easy to test out the concept. As a prototype-based, extremely dynamic language, you can pretty much reopen anything you want and attach more behaviour to it at any point. So, here are the basic rules I chose to develop an application that looked for collocations in a body of text:

  • Every change script should live on a file of its own, sequentially numbered (like 012_add_foo.io), containing all the changes necessary to the system to implement a particular feature (or story).
  • Every change script should have a test for the new functionality in a separate file in the test/ directory. Preferably, new functionality should be driven by them.
  • The change scripts will be run in sequence by a loader. The loader may also execute unit tests in pair with the change scripts or after all change scripts are loaded, to verify later change scripts did not break any of the existing behaviour. After the loader runs, the system should be ready to use.
  • If the latest change script is causing the code to break, fix it, but scripts that have already been superseded by others shouldn’t be changed unless they stop development of new change script (with a syntax error, for instance). This makes more sense when change scripts are created by other tools instead of humans.

So far, it has worked quite well - I ended up with 25 change scripts, one patch to the runtime APIs (which got accepted, yay!), plus a pretty simplistic loader script:


Directory folderNamed(“src”) fileNames sort foreach(name,
	if(name != “main.io” and name endsWithSeq(“.io”),
		“Loading #{name}” interpolate println
		doFile("src/" .. name)
	)
)

Because of my unfamiliarity with Io, I ended up writing pretty brittle unit test suite and broke the “build” a lot (my colleagues would certainly point out here that I break the build a lot, even in other languages, too), and didn’t manage to integrate the test runs in the loader either.

Anyway, the whole point of this exercise was this: it’s possible to do some really cool, dynamic refactorings when developing software like this.

I’m about to write my little Refactoring object, which allows me to do things like:


Refactoring renameObject(Foo, Fubar)
Refactoring renameMethod(Foo, foo, fubar)

The renaming of objects and methods won’t happen instantly across the codebase, as you’d expect from IDEs like IntelliJ or Eclipse - instead, the method or object to be renamed gets replaced with a proxy to the new one and every time the proxy gets hit, the caller method gets its code dumped to a new change script, with the appropriate replacements.
This should give me 100% accurate refactorings with very little disturbance to my development flow (of course, I had to change the way my flow works, but I think that’s a good compromise).

Geek
General

Comments (1)

Permalink