Making users happy by taking advantage of what you already have
I think Spotify is an amazing service! Spotify have millions of tracks available for you to start listening to over the internet for free! It’s very simple to use, very quick and has a great collection of music – it is now rare that I even have to access my local mp3 collection!
In the UK we have a Mercury Prize for album of the year. 12 albums are nominated, some of which I would have already have listed too but generally there are one or two bands I’ve never heard of. Previously, I would have had search (generally MySpace) to find out more information about these bands and listen to their music.
Today I was reading the Spotify blog and noticed they have put together a playlist of the albums nominated for the prize. Instantly I had a wow moment. They had taken their existing infrastructure and provided something cool, with very little effort or cost to themselves. I can now listen to the artists entire album instead of attempting to find one or two tracks!
The reason for the post is that sometimes you don’t need to implement massive, expensive, features to make users happy. Sometimes the little touches can make just as much impact. Having the playlist made me happy, it made it easier to access to music which I was interested in. As a result I was compelled to tell people.
If you look beyond making users happy, Spotify could now sell ads based on this playlist – promoting gigs for the artists or even just having the playlist ‘branded’ by Barclay who sponsor the prize.
I was a little disappointed to find that Florence & the Machine’s album was not included. Not sure the reasons behind this but it feels very strange. The label have an opportunity to reach new fans via a cool and growing service. More fans results in increased merchandise sales, increases gig ticket sales, more exposure which will increase the likely hood of people actually buying the album and spending money. It’s not always about direct album sales.
Labels: Spotify
IronRuby Session – Video and Slides
On Wednesday (15th July) I delivered my IronRuby presentation to the VistaSquad usergroup at Microsoft Victoria in London.
Big thank you to Ian who recorded and encoded the session, which I have embedded along with the slides below.
Vimeo video
SlideShare presentation
Labels: IronRuby, VistaSquad
Cancel a cancellation?
I’m currently on a cut-costing exercise and one of the items which needed to go was a premium Ning service. Priorities changed, aims changed and as such it was no longer required.
Finding how to cancel the service was pretty simple task. However, once I was there I felt something was missing. Notice anything from the screen below?
In my mind, Cancel is a way of backing out of a decision. In this case, it was a way to confirm.
Logically, it made sense – you are explicitly clicking cancel. However, based on how every other application works I was expecting an OK or Yes button to appear next to it.
It is important to think about what users are expecting to see together with how certain terms might have more than one possible meaning.
Asking is not a bad thing…
I’m all for applications providing users with a streamlined experience, reducing clicks and the amount of dialogs they have to confirm to get the job done. However, sometimes it can go a step too far.
Today, I had to buy a printer. Came home, plugged it in and Windows 7 happily installed the correct drivers – job done. Not quite. Sadly I had left Word open in the background. After continuing to do work on the document, AutoRecovery kicked in and saved the file. At this point I was shown the following dialog.
Instantly I had to stop, take a step back and wonder what I had done to cause this to happen. I was confused, and confusion is very bad for a user. I had no indication of what was happening, how long it would take or why it had happened in the first place. I can only assume it was related to the installation of the printer which caused Word to reconfigure itself.
To make matters worse, after it had completed I was then shown this dialog. There is no reason why Word should need me to reboot my machine.
Clicking no was my natural reaction given the choice as I was in the middle of working. Word had other ideas.
At this point it had back round the cycle at which point I caved and accepted the reboot. After receiving random errors, Word informed me it could not save my work resulting in a loss of work.
Lessons to take away from this.
1) If the action the application is taking is uncommon or could cause the user confusion – tell them. It would actually have been nice to have a dialog saying – “Sorry, we need to do some configuration as your printer settings have changed.”
2) At which point, I should have been given the option of ‘Now’, or ‘When I close Word’. Actions such as configuration are best performed when the user closes the application as they have finished their work and as such won’t mind the delay.
3) If they don’t want the action to happen – make sure you can cope. In this situation Word obviously couldn’t.
4) Finally, always think about how the user will feel when the dialog pops up or an action is taken without their consent.
Worse user experience ever! today so far today.
MEFUnit – Prototype of a MEF Unit Testing Framework
Recently I have been paying close attention to MEF, the Managed Extensibility Framework. MEF is an extremely powerful framework aimed at making parts (internal or external extensibility points) more discoverable.
While I was looking at this, it dawn on me. Unit testing frameworks main role is identifying and executing methods. If that is their main function – how could you use MEF to identify and execute those methods? The result of this pondering is MEFUnit. Like with xUnit.GWT this is located on GitHub and has been mentioned on twitter once or twice.
The Tests
The tests look very similar to any other kind of unit testing framework you might have used. The attribute [Mef] identifies which methods should be executed, and like with any other framework they can pass (no exception), fail (assertion exception) and be skipped (skipped exception).
public class Example
{
[Mef]
public void Test1()
{
throw new AssertException("Test Failed");
}
[Mef]
public void Test2()
{
throw new SkipException();
}
[Mef]
public void Test3()
{
}
}
Fundamentally, this is the main concept of most unit testing frameworks. Yes, some have parameterized tests and other such features which are great, but many people got by with just this. When you run the tests, you get the following output.
Executing Tests
Executing Test1... Test Failed
Executing Test2... Skipped
Executing Test3... Passed
Key implementations points of MEFUnit
But how are these methods actually turned into unit tests? The main point in the above example is the MEF attribute. This is simply a custom ExportAttribute. I could have wrote:
[Export("Mef", typeof(Action)]
public void Test() {}
However, I feel creating a custom attribute improves the readability and usability of my framework for the user. It also means if I need to change the contract I can do it without effecting my dependent exports. The second important fact is that the exports are of type Action. By storing the method references as Action I can executed them anywhere in my code. This is the trick which makes this all possible. It means I can execute each test as shown and report the result to the console.
public void RunMefs()
{
foreach (var mef in Mefs)
{
Console.Write("Executing " + mef.Method.Name + "... ");
try
{
mef();
Console.WriteLine("Passed");
}
catch (AssertException ex)
{
Console.WriteLine(ex.Message);
}
catch (SkipException)
{
Console.WriteLine("Skipped");
}
}
}
The Mefs collection is populated via the MEF framework and the use of an Import attribute. Within the class, the property looks like this: [MefTests]
public IEnumerable<Action> Mefs { get; set; }
As with the Export attribute, I wanted to hide the actual contract I used to import the Action methods. This allowed me to hide the fact I was using AllowRecomposition, enabling tests to be dynamically identify when new assemblies are loaded.
public MefTests() : base("Mef", typeof(Action))
{
AllowRecomposition = true;
}
When you combine this with the Compose method which hooks together the core parts of MEF you have the core concept of a unit testing framework.
I have to admit, I’m not expecting anyone to actually use this. However, I think it shows some of the interesting capabilities which MEF brings to the table.





Social networks
Twitter GitHub SlideShare