Why Early UX Should Scratch Deeper than the UI

uxThe early stages of software engineering projects aiming to expose anything more than a trivial User Interface (UI) quite sensibly begin with a heavy focus on the User Experience (UX), as this dictates a great deal of what the software needs to do. This is usually a stage of the project that produces many wireframes, mockups, and a sense of what the user — or different user “personas” — will be attempting to achieve with the software.

This UX-centric approach undeniably works really well, and tends to result in software that delivers a strong, usable user experience.

However, I’ve seen a UX-/UI-only focus in the early stages of some projects lead to blind spots and incorrect assumptions which can force costly rework later in the project. For this reason, I’d assert that early UX work should scratch deeper than just the UI, if only to validate assumptions and, in-particular, to confirm what’s actually possible in terms of the underlying data and services.

Server-Side Constraints

Too often, in UX-centric early project stages, the assertion is that the server-side data, APIs and services are much less relevant than the UI. This is often correct as it can distract from the goal of designing usable software, but there’s an underlying assumption that needs validating: That the server can deliver anything the UX/UI work dictates it needs.

This is often not the case… If the server-side data model is built on serious data modelling or clever algorithms, those services and that model are often constrained in terms of what they can provide. There may be heavy computational costs involved in exposing certain data in a timely manner, if it’s even possible.

As always, using specific examples of server-side data in UX work can really help to clarify what’s possible. Even just involving a few token Data / Server-Side engineers can be enough to verbally “sign off” that the server will be able to support what’s required.

This form of early full-stack validation can prevent costly rework later, and can even help to direct server-side work appropriately by providing added context about what the UI needs.

Server-Side Data Model and User Mental Model

An added benefit in considering the server-side data model during UX work is that the user’s own mental model of what they are trying to achieve when they use the software is so often a version of that server-side model.

Considering, albeit leanly, how we might model data on the server can help to clarify the ways in which a user might expect (via their own mental model) to visualise, interact with and modify that data. After all, this is effectively what they’re going to be doing by using the software; accessing and manipulating server-side data and services indirectly via a UI.

Even just tying together the correct terminology, so UX and server-side work are talking the same language, can prevent costly disconnects between different parts of the team.

Again, precise examples of server-side data, or a little involvement of the relevant engineers, can really help here.

Lean Approach to Scratching the Full Stack

But doesn’t involving server-side engineers and data scientists in UX discussions slow down those discussions? Doesn’t it negate the value of considering the software purely from the point of view of the user at first?

I’d say not, but only if it’s clear that the focus of this stage is still primarily UX, and that any deeper layers in the stack are to be validated only. Crucially, any details of how the eventual UI will interact with the server should be avoided, unless they too dictate what is possible in the UI. No-one needs to build the server at this stage (though that work might be proceeding in parallel), so long as they can talk in as much detail as required about what it, and its services, will look like.

 

I think this is another example of how, in software engineering, regularly considering the bigger picture, even when performing early focussed work, can avoid costly mistakes. In complex systems, the bigger and the smaller views are often related or constrained in unexpected ways.

Distil Complexity, Nail Theory, Build Software… Just Not All at Once

questionmark

Trying to pat your head whilst rubbing your stomach is the standard way to demonstrate that we, as humans, find it difficult to perform certain activities concurrently.

The software project equivalent is attempting to overlap activities that teams find it difficult to handle in combination. It’s just a reality that some things are hard enough on their own, and so we hamper our efforts if we attempt to combine them.

It’s been my experience that projects where there is at least an attempt to separate, as much as possible, the following activities are those that experience fewer hiccups. It may still be necessary to iterate through these activities regularly, and they are not waterfall-style one-offs, but being aware of the complexity of doing more than one of them at once can help to simplify things for teams and to ensure one flows into the other:

  • Distilling Domain Complexity – Every software product is built to deliver a solution in a unique problem domain. Often, there is much to clarify in this domain, and much complexity to unravel and distil. This can be something of a voyage of discovery, particularly if it takes a while to extract that knowledge from a domain expert and to figure out which aspects of it the project will require. As building products for a market can be like chasing a moving target, it is highly likely that this domain-related activity will be revisited many times during a project;
  • Nailing Academic Theory – Beyond well-worn Software Architecture and Computer Science principles, a project may rely upon deeper academic theory, such as Artificial Intelligence, Machine Learning, Big Data… or non-tech project-specific areas such as psychology, natural language, etc. Each of these alone are huge fields, full of theory. The problem is, you can’t build software with theory, and so we need to pin down practical forms of that theory that will be implemented in software. This may involve prototyping, comparative analysis of different approaches, and finally a choice between palatable options.
    There is a tendency to linger over these decisions, and an attractiveness in remaining in that land of possibilities. However, software engineering requires knowns, not possibilities, and the sooner theory is nailed down — for this project or iteration anyway, as we can always make different decisions next time — the better.
  • Building Software – Software engineering is concerned with building stable, scalable, understandable software to meet a need. There is sufficient difficulty in doing that in isolation, without overlapping with the previous activities. For large chunks of time, teams need to focus on building software, unencumbered by academic theory or domain ambiguities. It is almost an unwritten assumption on some projects that most of the difficulty lies in the previous two activities (problem domain and academic theory), and that building the resulting software solution will be comparatively easy or, at least, will be more of a known activity. However, the complexities and practicalities of building software require that teams focus on the activity where possible.

Although we may revisit each of these activities many times during a project, identifying and managing the boundaries between them helps to isolate them from one another. One great way to do that is by creating and maintaining great team documentation: Domain knowledge and concrete decisions based upon academic theory are perfect examples where documentation can form a neat output from one activity (albeit perhaps occasionally updated), to be consumed by another. Documentation needn’t be heavy and cumbersome and writing just enough, but before it is needed, should be encouraged.

I wonder, how many times that we’ve seen projects go awry could we identify examples of these activities bleeding into one another too much? And, where projects have gone comparatively smoothly, I’d be interested in hearing whether it was because these activities were understood to be complex in combination.

I guess it’s all part of improving the task of building complex software, with a human team.

Software Frameworks: Occasionally, Reject or Reinvent the Wheel

moonSoftware frameworks are everywhere, and rightly so: Spring, Grails, Angular, Knockout, Backbone… the list is endless.

In essence, a framework is an abstraction upon which we write our app-/product-specific code. We use them to enable reuse of well-worn functionality and, like all abstractions, to hide the implementation and underlying complexity.

Use of frameworks allows us to simplify and speed up development efforts. It’s rather a no-brainer, hence their proliferation.

But under what conditions would we choose not to use a framework or to write our own? Surely we’d just be reinventing the wheel? Perhaps, but just occasionally, maybe the wheel doesn’t fit or we need a better wheel.

Framework Fitness

To be used on a project, a framework must at least be:

  • Functional – It goes without saying that a framework must do what we need it to do; delivering the functionality we require. There must be a clear benefit in using it;
  • Configurable / Customisable – It must be possible configure or extend that functionality (via customisation or plugins), tailoring it to our specific needs, and perhaps even turn off portions of it if we don’t need them or if they are inappropriate;
  • Documented – There must be up-to-date documentation, to make the above possible. We mustn’t need to dig to discover how to use the framework;
  • Efficient – The framework must not introduce performance problems of its own. If there is a convenience in writing our app using a framework, that must not be paid for via a performance degradation we aren’t willing to accept.
    (Anyone who has seen the numerous levels in a Spring stack trace will know how intriguing it is to see just how much is going on behind the scenes, and will occasionally have wondered about the potential performance impact of it all);
  • Proven & Stable – Once we commit to a framework, we are essentially relying on it. The stability of our app / product is directly affected by the stability of the framework. If we want to deliver cast-iron stability to our end users, then we’d better use a framework that itself offers cast-iron stability! At the very least, a framework must have been proven to be robust in production, preferably by someone else, before we choose to launch a product with it;
  • Owned & Supported – If there are unforeseen problems, or bugs — and there are always bugs — it helps if the framework is supported either by a company or an active development community. It is no good waiting six months for a fix to a framework problem that can’t otherwise be worked around.

If a candidate framework is missing or weak in one or more of the above, we might need to look elsewhere or choose to develop the functionality we’re looking for ourselves, perhaps itself in the form of a framework for reuse elsewhere. The cost of ditching or switching frameworks if we don’t assess the suitability up-front can be significant.

Healthy Curiosity

Whether or not a particular frameworks suits our needs, I think there’s educational value in knowing at least a little about the technology that lies beneath that framework. Such knowledge of the foundations upon which it is based may help us to debug problems or, if appropriate, to invent a replacement for the framework ourselves.

Without knowledge of what the framework is doing, we won’t know whether it is doing any good. It is always worth having an idea of whether our own efforts would be better, if only to confirm that they wouldn’t be!

Healthy Skepticism

Blind use of frameworks because other similar projects are using them, or use of them on projects where we use a mere fragment or sliver of their functionality, should be discouraged. The risks probably outweigh the benefits. I think we always need to look at the upside of using a particular framework, specifically for this project.

 

In conclusion, frameworks are largely a huge benefit in software development, but only if we know why we’re using them, when we’re sure that they fit our purpose, and when we understand (at least at a high level) what they are doing beneath the hood.

Just occasionally, omission of the framework or use of own implementation may be a more sensible option. It’s worth remembering that.