It doesn’t have to be easy to use

When people are specifying software one often hears the phrase ‘It must be easy to use’.

I rather think this is jumping the gun… the first and most important requirement should be more along the lines of ‘It must make the users life easier’ or ‘It must add new value to a users world’.

And if we think hard enough about it then ‘add value’ is really just an extension of ‘makes easier’… how so?

The ‘added value’ always has a goal, whether it be peer recognition, money, or sex appeal the user is still trying to achieve something by adding value to their lives and if the software enables that then it is in fact making their lives easier.

Without that (often ignored) step the product is doomed… no matter how easy the software is to use if it doesn’t make the users life easier then why are they going to use it in the first place?

This also helps explain why some dire products are actually successes. They may be an utter pain the behind to use and they may crash 50 times a day but if I take all that into account they still make my work possible or easier then I will still use them.

‘Easy to use’ is by far the secondary consideration.

Of course… once you have a product that makes the users life easier or better then ‘easy to use’ becomes much more important… after all who would voluntarily opt for something harder to use?

Oh, right, Power Users would. These folks will trade ‘easy to use’ for ‘makes my life even easier’ in a heartbeat.

Power Users seem to prefer consistency and predictability over mere ease of use. They will gladly invest hours of learning provided a) their lives get easier to use, and b) the effort is rewarded by unlocking even more potential.

Ordinary Users however will not invest hours of learning… in fact for a large majority if it isn’t obvious in a few seconds how to achieve something it is already too complex.

I’ve watched people type in a word and then click the ‘bold’ button… when nothing happens their first thought isn’t “Oh, I forgot to select the text” it’s more like “Hmmm… the bold feature doesn’t work”.

Of course what we have is a gradient of users from the most disinterested all the way up to the ‘expert power user’.

However they all have one thing in common… they are trying to make their lives easier by getting something done.

I believe this then is the baseline from which all software development must begin…

Who are the users and how does this software make their life easier?

see also

You must be logged in to post a comment.

community content (2 approved comments so far)
Click to expand

Personal Storage is Nigh
Click to expand

This is an idea that pops up every so often but I think we are close to seeing it become reality.

Stop and think for a moment about your gadgets. Maybe you have a desktop at work, one at home, a business laptop, a netbook you take on holiday, a Kindle for reading and an iPad for the couch. Possibly you’ve got an iPhone and a fridge that plays tunes in your kitchen.

As a consumer you are constantly being told that you need bigger, faster, more, better. Faster CPU’s, better graphics, longer games, more information, more storage.

But really that’s all just marketing.

I’m willing to bet that what you really want is more gratification, to be more lazy, to get the hotter girls, to have more fun.

We see from the iPhone that the multi-gigabyte HD games we have been sold on the PC for years are often outperformed in terms of fun by games targeted at small screens, consisting of a few tens of megabytes.

We watch videos on our iPads and find it fine. We watch terrestrial TV and the most annoying thing is rarely the quality of the image but more often than not the content or the impossible to follow sound.

We surf the web everywhere and almost every device lets us store bookmarks, leaving our history fragmented and broken.

We listen to audio all over the places and painstakingly replicating our music libraries from device to device. Often a track is on one device but not another, or you get two copies of it.

Every gadget we buy pushes us to have extra hard drive for extra cost.

But wouldn’t it be better to have a single device that stores all our data and allow all our other gadgets to hook up to it and access whatever is needed?

Funny enough we already have such a device.

The SmartPhone.

We carry smart phones with us everywhere, they come equipped with wireless communications, batteries, loads of Flash storage, and we are already used to charging them every night.

Imagine if you will that your iPhone has all your data on it… why then can your iPad not stream the files it needs to and from? Why can’t your fridge or your laptop?

Imagine one set of bookmarks you share everywhere, one place to hunt for that important letter, one music library to maintain.

Wouldn’t that be easier? more sensible? better for our environment?

I think so.

Sure the technology needs some work to add a little more storage, a little more battery capacity, better wireless serving. But the basics are there and as smart phone makers search for differentiating factors I’m pretty certain this is one area that will be discovered.

Personal Storage will blow away your reliance on the ‘Cloud’. Why trust a 3rd party with your data? Why put your data in place you can’t get to if the internet goes down? Why pay for storage you already have that works slower and with less reliability?

Why install your software multiple times? Why not have it on your smart phone to be pulled off and run on your other computers as needed?

This brief dalliance with software as a service will go the way of the dodo, it’s only benefit is in charging you more and making our unreliable power and internet infrastructures even more critical.

No, the future as I see it has my smart phone acting as my personal storage module and software repository and all my other gadgets as simple (potentially amazing) clients onto it.

My world, my pocket, with me everywhere.

You must be logged in to post a comment.

community content (no approved comments so far)
Click to expand

Using Generic Types for MVVM
Click to expand

The MVVM pattern seems to have become the defacto standard for implementing cool WPF applications.

Rob Eisenberg suggested using Conventions to help enforce a separation of View and ViewModel. This to me smacks of Magic Strings which is just not nice.

Lately I’ve been playing with a different method of doing this using XAML Generics.

I’d like to share this with the community and see how you all feel about this approach.

The basic idea is that all Views should derive from a ViewBase where T specifies the type of ViewModel they should be built against.

For example:

Assume we have a ViewModel of type SomeViewModel and we want to create a view that represents it, all we have to do is create the following XAML:

<ve:ViewRoot x:Class="app.SomeView" x:TypeArguments="vm:SomeViewModel"
   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
   xmlns:ve="clr-namespace:ViewEngine;assembly=ViewFramework"
 >
</ve:ViewRoot>

and a Code Behind file:

public partial class SomeView : ViewRoot<SomeViewModel>
{
    public SomeView()
    {
        InitializeComponent();
    }
}

And bingo… our application will use SomeView everywhere SomeViewModel occurs in the visual tree.

Because of the data binding system we can now build our view referencing the view model, so assuming there is a Title property in the view model we can write this to a label like this:

<ve:ViewRoot x:Class="app.SomeView" x:TypeArguments="vm:SomeViewModel"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:ve="clr-namespace:ViewEngine;assembly=ViewFramework"
 >
      <Label Content="{Binding Title}"/>
</ve:ViewRoot>

No naming conventions, no DataTemplate writing, just completely transparent intent.

Framework Wire-Up

Of course this doesn’t happen out of the box and requires a framework and a little global wiring up.

Let’s start with the simple bit, wiring it up, and then get to explaining how this works behind the scenes.

To make it simple I did away with the App.xaml startup system and went back to the old static main in Program.cs approach… I have no doubt it could be integrated into the app.xaml system if needed.

[STAThread]
public static void Main()
{
    var app = new Application();
    ViewEngine.Initialise(app, Assembly.GetExecutingAssembly());
    ViewEngine.Run(new WindowViewModel());
}

Simple huh?

Framework

Of course all the magic and challenge happens in the framework itself.

The basic principle is straightforward:

  • Scan the provided assembly and find all subclasses of ViewRoot.
  • Set up mappings between the ViewClasses and their models.
  • Wrap those in DataTemplates.
  • Load the data templates into the applications root ResourceDictionary.

The rest is handled by WPF for us.

There are however a couple of challenges to using Generics in WPF that make this more complex than one might expect.

Access to Properties

Not being able to access things like ResourceDictionary properties on the children of a generic type.

Fix: Create a 2 stage derivation of ViewRoot, the first called ViewRoot and the second called ViewRoot. This allows us to use the convention in the XAML and keeps the established XAML conventions runnings.

    public class RootView<T> : RootView { }
    public class RootView : ContentControl { }

Top Level Windows

Of course top level windows cannot be derived from ContentControl and must be derived from Window so we have to introduce some special case handling.

Its own assembly

As I discovered in one of my earlier posts on XAML it is important to build the ViewEngine in a separate assembly.

View Engine

Still it’s pretty plain sailing, in fact a whole ViewEngine class can be presented here. Obviously this isn’t commercial ready but it gives you a base to play with.

public interface IView { }
internal interface IViewRoot : IView { }
public class ViewRoot<T> : ViewRoot { }
public abstract class ViewRoot : ContentControlIViewRoot { }
public class WindowRoot<T> : WindowRoot { }
public abstract class WindowRoot : WindowIView { }


public static class ViewEngine
{
    private static Application sApp;

    public static void Initialise(Application app, params Assembly[] assembliesWithViews)
    {
        sApp = app;
        CreateViewViewModelMapping(assembliesWithViews);
    }

    public static Window Run(object viewModel)
    {
        var rootWindow = CreateRootWindow(viewModel);
        sApp.Run(rootWindow);
        return rootWindow;
    }

    private static void CreateViewViewModelMapping(IEnumerable<Assembly> assembliesWithViews)
    {
        foreach (var assemblyWithViews in assembliesWithViews)
            AddViewTypesToTemplates(assemblyWithViews.GetTypes());
    }

    private static void AddViewTypesToTemplates(IEnumerable<Type> potentialViewTypes)
    {
        foreach (var potentialViewType in potentialViewTypes)
            if (TypeImplementsValidViewInterface(potentialViewType))
                AddViewTypeMapping(potentialViewType);
    }

    private static bool TypeImplementsValidViewInterface(Type potentialViewType)
    {
        if (typeof(IView).IsAssignableFrom(potentialViewType))
            return potentialViewType.BaseType.GetGenericArguments().Length > 0;

        return false;
    }

    private static void AddViewTypeMapping(Type viewType)
    {
        var modelType = viewType.BaseType.GetGenericArguments()[0];

        if (typeof(IViewRoot).IsAssignableFrom(viewType))
        {
            var template = new DataTemplate(modelType);
            var visualFactory = new FrameworkElementFactory(viewType);
            template.VisualTree = visualFactory;

            sApp.Resources.Add(template.DataTemplateKey, template);
        }
        else
            sApp.Resources.Add(modelType, viewType);
    }

    private static Type FindViewForModelType(Type modelType)
    {
        return sApp.Resources[modelType] as Type;
    }

    private static Window CreateRootWindow(object viewModel)
    {
        Type viewType = FindViewForModelType(viewModel.GetType());
        if (viewType == null)
            throw new Exception(string.Format("No View for ViewModel type: {0}",
                         viewModel.GetType().Name));

        var view = Activator.CreateInstance(viewType);
        var window = view as Window;

        if (window == null)
            throw new Exception(string.Format("Could not initialise root WindowView({0})",
             viewModel.GetType().Name));
        window.DataContext = viewModel;

        return window;
    }
}

In case you also need an example MainWindow it is straightforward:

<ve:WindowRoot x:Class="app.MainWindow" x:TypeArguments="WindowViewModel" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:ve="clr-namespace:ViewEngine;assembly= ViewEngine " 
        Title="{Binding TitleProperty}" Height="300" Width="300"
        Content="{Binding ContentProperty}"
 >
    <ve:WindowRoot.Resources>
    </ve:WindowRoot.Resources>
</ve:WindowRoot>

Have fun and do let me know if you find any way to make this better…

see also

You must be logged in to post a comment.

community content (1 approved comment so far)
Click to expand

Designing for a Touch World
Click to expand

In this series I plan to explore some of the issues of Touch UI’s, this is as much a documentation of my learning experiences as it is anything else. The content will be based primarily on observation and conjecture so while I find the information helpful it is up to you to verify its suitability to your situation.

If you have contradictory viewpoints, additional ideas/information, or real ‘study results’ please chime in in the user content section – the more we talk about these things the better our UI’s will get.

Ok, on to the first installment…

Smart phone touch

When you think of modern smartphones you probably expect a Touch Screen. Seems that touch would be an easy medium to design for, after all your user can see and interact directly with the content.

As it turns out this isn’t actually the case…

Fingers are big, fat, clumsy pointing devices and the point of contact between your finger and the screen is not at all easy to determine. Worse, once you touch the screen you completely obscure whatever it was you were trying to interact with. People tend to judder and bounce (especially on the train or tram) and it is very easy to end up with accidental touches. Add this to the seriously limited screen space, potential for unwanted palm contact, and the extremely limited range motion available (try using a mobile device one handed) and it begins to seem that creating a good experience is almost impossible.

Thankfully this extreme is also not the case.

I think mostly because they are obscuring the screen (or more importantly desperately trying not to obscure the screen) most people seem to touch the screen slightly below their point of attention. Android devices seem to struggle a lot with taking this into account, Apple’s iPhone on the other hand excels at it. At times the iPhone seems almost psychic in its ability to correctly identify the part you were trying to touch. So this variation is something to take into account when developing UI’s on these mobile platforms… on Android aim to have a bigger touch target and require less precision.

Side Note: In some ways it is a shame that all the excitement over capacitative touch screens and finger input has completely sidelined the stylus… sure the stylus isn’t ideal for everything but for some tasks it beats the hell out of fingers and has the added benefit of mostly leaving the screen visible. I for one am hoping to see the stylus make a return at some point in the near future.

The availability of touch.

There are only a limited number of touch gestures available. More with multiple fingers obviously but the more fingers your are trying to interpret the great the chance you will get incorrect inputs.

What are the types of touch input you can reasonably expect from a user using one finger and holding the phone in their hand at the same time?

  • Tap

    This one is pretty obvious to most users, touch and release without movement (or at least very little movement – no one can hold perfectly still). Contact times vary depending on the user – some people press firmly and hope for some feedback, others stab at it quickly and with force hoping for a better result, some touch it as if it is fragile. Your UI probably shouldn’t discriminate between these actions.

  • Swipe

    Touch and drag the finger across the screen in a more or less constant line. Also pretty much an expectation.

    The easiest swipes are in order: sweep an approx 1/4 arc (for right-handers from mid-right to top-left or vice-versa), top-to-bottom, left-to-right, right-to-left, bottom-to-top.

    Other swipes such as on the diagonal are possible but markedly harder to perform.

  • Drag

    Touch and drag the finger across the screen in a variable line… potentially with many changes in direction. Obviousness depends on the context but with appropriate cues most people will get it.

  • Flick

    The ‘flick’ is also fairly intuitive, however it seems that when a user is about to flick the screen they subtly change their grip on the device leading to a difference between the Flick and the Swipe.

    Ease of flicks in order: top-to-bottom, bottom-to-top, left-to-right, right-to-left (harder). Other flicks are possible but non-obvious and require much more dexterity and conscious attention.

  • Long Press

    Less obvious but once learned becomes second nature. The press, hold, release without moving the finger to get a long press. Expect to have to explain to the users how this one works if you are overloading the Tap gesture on the same ui element.

  • Circulate

    If you figure that most people holding a device one handed will be interacting with it using their thumb another relatively easy gesture is to touch and circulate your finger as if rotating around a clock face. This one doesn’t see much use and is less obvious than the above. For right-handers anti-clockwise motion is marginally easier. Expect to have to explain to the users how this one works.

  • Others

    You might imagine other things such as double-tap but due to the screen obscuring issue getting in the way of user feedback such gestures are less reliable/obvious. You can of course use them, but think long and hard first.

Next time I’ll look at multi-touch gestures, and then follow up with some information about using these gestures and what the user means when they touch your screen.

Computing is personal… touch even more so 🙂

You must be logged in to post a comment.

community content (1 approved comment so far)
Click to expand

Conflate with care
Click to expand

One of the worst user interface design errors is the conflation of two unrelated concerns. Unfortunately it is depressingly common.

Take for example Back and Up. Frequently these are conflated into a single button leading to unexpected user behaviour. This is currently bugging me on my Android phone… I use an app that opens a screen that then sends me to my e-mail, I press ‘Back’ expecting to go back to the app but instead the ‘back button’ is overloaded to mean ‘up to parent’ by the mail app so I actually end up in the inbox. It may seem a small thing but believe me it is absolutely infuriating.

Unfortunately for designers precisely the converse is also true… one of the best UI design ideas is to conflate related ideas. Yes, mutual contradiction at work.?

Consider e-mail and facebook messaging, both are basically the same and wrapping them all up in the same ui would make most users pretty happy.

The challenge for the designer then is to locate ideas that seem related not only to the designers of the world but to everyone who will pick up their creation. When they succeed the user sees the world as simpler, more obvious, and less stressful. When they fail the UI seems to be a nightmare to use, a frustration, and often reason enough to seek alternatives.

Moral: Conflate with care!

see also

You must be logged in to post a comment.

community content (no approved comments so far)
Click to expand
Design and Content © Copyright Duncan Kimpton 2010