Usability for programmers

I recently started learning Xamarin.  I should say I’ve started learning it again, because the first time I just couldn’t get into it.  This time it’s going better, although I’ve still been struck by something that’s surprisingly labour-intensive and so surprisingly annoying.  This made me think about the relatively cushy world I normally experience when I’m writing e.g. C#, where the technology doesn’t seem to get in the way as much.  This article will be about user experience, where the user is a programmer, and what they’re using is a combination of language, tools, frameworks and so on.

Frustration has long been the mother of invention

Programmers aren’t the first or only people to react to what they perceive as drudgery.  In the Disney film Fantasia, Mickey Mouse is a sorcerer’s apprentice.  The sorcerer gives him some chores to do, and instead of getting on with them Mickey tries to make them do themselves by magic.  This doesn’t end well.

Charles Babbage was fed up doing the tedious checking of calculations that had been done by hand.  Not only was the work hard and boring, he was finding too many errors in the calculations.  In his exasperation he said, “I wish these calculations had been executed by steam”, as steam power was the modern technology of his day.  This led him to design the Difference Engine (a mechanical calculator) and the Analytical Engine (a mechanical computer), although the Difference Engine was never finished, and the Analytical Engine was not built at all.

The basic problem

I think that in all these cases there is the same basic problem.  You want to make a change to the world, for instance create some code that does a particular task.  There are at least three things involved in this:

  1. The change, which in the picture below is represented by turning through some angle;
  2. The thoughts needed to fully specify that change – the green arrow;
  3. All the details out in the world that need to be affected by the change – the purple arrow.

A diagram showing how a change often takes less thinking about than doing

If you can operate at the level of your thoughts, there is relatively little effort needed to make the change.  The further towards the details you are forced to operate, the more work (and the more tedious) it is to make the same change.

The more details our working environment can take care of for us, the closer we can operate to the level of our thoughts.  This is usually quicker and more enjoyable than operating down in the details.  The world comes nearer to us, via the tools and other things that bridge gap between our thoughts and the details.

Is this desire to work up at the level of thoughts rather than coping with the messy detail laziness?  Is it a desire for labour saving and efficiency?  Is it exasperation at inadequate tools and abstractions?  It’s probably some combination of all of them.

Giving up control

One reason why people might want to work down in the level of the details is to have a feeling of control.  Allowing tools to elevate things to a more comfortable (i.e. higher) level of abstraction means relying on those tools.  I think it’s valuable to know what our tools do on our behalf, for when they go wrong or do things we don’t expect.

However, refusing to use tools because tools are for the weak, or because they can’t be as good as doing it all by hand yourself, and other reasons like that risk cutting off your nose to spite your face.  I’m not saying that you should cocoon yourself in a cosy highly abstract world, which means you stay ignorant of the detail and so are brittle to the tools failing.  Rather, misplaced ego can be counter-productive.

Unless you are writing machine code on a bare-metal machine, you already don’t have complete control over the code you write.  For instance, if you write in C#:

  1. You write C# source code;
  2. This is compiled into IL, along with the IL for any dependencies you have used in your source code e.g. system libraries;
  3. The IL is processed by the CLR;
  4. The CLR sits on top of the operating system, with its virtual memory, scheduling etc.

I’ve left out levels below the operating system, such as the BIOS, because that’s getting a bit silly.  The only thing you have direct control over is the source code in the first step.  The IL, the dependencies, the compiler, the CLR and the operating system are all outside your control.

Bridging the gap for programmers

There are a few things I’ve come across that help bridge the gap, for a given programming language such as C#:

  1. A looser coupling between source code and compiled code;
  2. Using other people’s code with little effort;
  3. AOP.

I won’t go into AOP here as I don’t have enough experience with it to do it justice.  If you’re interested I suggest you find out more about it elsewhere.

By a looser coupling between source code and compiled code I mean the compiler works harder on your behalf for a given amount of input source code.  The result is still deterministic, but more details are filled in for you by the compiler, i.e. more change to the output happens.  This is sometimes described as magic, as in ‘the compiler will do XYZ for you by magic’.  At the smaller end of the scale this can also be described as syntactic sugar, but at the larger end, e.g. LINQ, it is much more like magic.

Some examples from C# where magic happens are:

  1. using (calling dispose)
  2. foreach
  3. yield return
  4. async / await
  5. Auto-properties (the automatic creation of backing variables, and the generation of default getters and setters)
  6. Lambdas and anonymous types
  7. LINQ

Using other people’s code with little effort

One design pattern that helps with this is: convention over configuration.  The idea is that some things will just happen by default (or convention), rather than nothing happening until you fill in all the detail.  If the default isn’t what you want, you have at least some ability to override the default.

The result of this pattern applied well is:

  • Simple things are easy (where simple is as defined by the author of the conventions);
  • Complicated things are still possible, but take more work.

The tactics you might use to achieve this are things like naming conventions, reflection and attributes.

Examples of using other people’s code with little effort include things like:

In EF, linking a class and a database table can be as simple as adding an attribute to the class that includes the table’s name.  EF will assume that every property of that class maps to a database column of the same name.  If I want it to ignore a property (because I know that it’s e.g. a computed value and so there’s no corresponding database column), I add an attribute to that property saying it should be ignored.  If I want the property to have a different name to the column, I add an attribute to the property that gives the column’s name.

In ASP.NET MVC, it needs to find a method in my code to call in response to receiving an HTTP request to the URL myhost.com/abc/xyz.  By default, it will assume that there is a class called abcController in a top-level folder called Controllers.  In that class it will look for a public method called xyz.  If I want something different to this I can tell ASP.NET MVC how to override this default behaviour.

Xamarin usability problem

So, with all this preamble, what triggered this article?  What annoyed me?  I think it’s a general problem of XAML (the user interface technology used in Xamarin and elsewhere), but I will concentrate on how it is in Xamarin.

Xamarin uses an MVVM (Model, View, View Model) approach to structure things.  Views are what make up the user interface – collections of buttons, text boxes etc.  View models are lumps of data behind the scenes that a view can read and update.  The process of linking view and view model is called binding.

Rather than go through all the details here, I suggest you look at the Microsoft documentation for binding, which includes a decent video.  There’s also a good blog post on just the binding part, and some of the details needed by it.

I have experience of the corresponding task in web programming (binding a view to a view model) using AngularJS.  This can be relatively straightforward – the view just says which bit of the view model it wants by specifying it via {{}}, e.g. {{Customer.FirstName}}.  It can get more complicated than that if you want to do more complicated things.

In Xamarin, the big missing piece is to do with automatically telling the code that processes the view that data in the view model has changed.  In AngularJS this happens by magic, via the AngularJS library.  In Xamarin there’s no corresponding magic, so you must roll your own notification.

I was expecting to be able to tag a property in the view model with an attribute saying that updates to it should trigger a response in the view, but I haven’t found this.  I understand that life can get more complicated than this simple case – the example in the blog post of the computed FullName property updating whenever the underlying property FirstName changes is a good one.  But the design seems to miss support for the simple case and give you the tools you need for only the more complicated cases.

If you look back to the description of convention over configuration, you’ll see that part 1 of its benefits is what’s missing here.  Simple things aren’t as easy as they should be.

What makes this more jarring is the care that Microsoft seems to take in making the developer experience a good one.  As C# has developed, features have been added because they take away the tedious stuff.  I recommend you read Jon Skeet’s C# book for a good description of this, as he goes through a before/after comparison for the features.

I remember hearing on a podcast the justification for the slightly odd order of things when you query e.g. a database table in LINQ.  Unlike in e.g. SQL, the source of the data comes first, and then the operations (filtering, projecting etc.) you do on it come after.  If you’re used to SQL this seems backwards and therefore wrong.  This order is so that the context for the query, i.e. the tables involved, is established as soon as possible.  Having the context means that IDEs can start to be helpful as soon as possible, by suggesting columns / properties of those tables as you type the rest of the queries.

I hope that the development of Xamarin follows that of C#, where later versions make it easier to use.

Summary

Programmers are users too, which means there are UX questions to address.  When you are creating something for programmers to use – a tool or some code – please consider usability as well as features.  Cater for simple cases as well as complex ones.  Your users will be happier and more productive as a result.

 

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s