User Experience Design

User experience (UX)

[…] is how a user interacts with and experiences a product, system or service. It includes a person’s perceptions of utility, ease of use, and efficiency. — Wikipedia

Where do you encounter UX (design) in your everyday life?

Overview

  • user research
  • visual design
  • interaction design / usability
  • standards
  • error handling

User Research

[…] focuses on understanding user behaviors, needs and motivations through interviews, surveys, usability evaluations and other forms of feedback methodologies. — Wikipedia

Who are typical users?

  • you
  • your peers
  • other scientists
  • you (but in two months from now)

Utility

is what makes a user want to use a product

User research tools

  • create Personas
  • talk to users
  • make a survey
  • observe the users

Visual design

Colors

  • use common color codes
    green = OK
    red = Problem
  • be inclusive (don’t rely on colors)
  • see also Apple Design Guidelines

Labview interface for
the AVAPS software

Typography

[…] is the art and technique of arranging type to make written language legible, readable and appealing when displayed. — Wikipedia

  • Use readable fonts and font sizes

Layout (plots)

Layout (plots)

Layout (web sites)

Templates

apply a consistent layout and visual design

Interaction Design

  • Goal-oriented design aims to satisfy the user’s needs and desires
  • Understand the cognitive dimensions to evaluate design solutions

Example: Git

git --help
usage: git [-v | --version] [-h | --help] [-C <path>] [-c <name>=<value>]
           [--exec-path[=<path>]] [--html-path] [--man-path] [--info-path]
           [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--bare]
           [--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>]
           [--config-env=<name>=<envvar>] <command> [<args>]

These are common Git commands used in various situations:

start a working area (see also: git help tutorial)
   clone     Clone a repository into a new directory
   init      Create an empty Git repository or reinitialize an existing one
...

'git help -a' and 'git help -g' list available subcommands and some
concept guides. See 'git help <command>' or 'git help <concept>'
to read about a specific subcommand or concept.
See 'git help git' for an overview of the system.

Example: Python function

def is_atlantic(lon=0, lat=0):
    return ((lon > 295) | (lon < 20)) & (lat > -30) & (lat < 30)

Use sensible defaults (if at all)

Example: Python function

def is_atlantic(lon, lat):
    return ((lon > 295) | (lon < 20)) & (lat > -30) & (lat < 30)

Don’t lie :)

Example: Python function

def is_tropical_atlantic(lon, lat):
    return ((lon > 295) | (lon < 20)) & (lat > -30) & (lat < 30)

Make it easy to do things right

Example: Python function

def is_tropical_atlantic(lon, lat):
    lon = lon % 360
    return ((lon > 295) | (lon < 20)) & (lat > -30) & (lat < 30)

Don’t lie

How do you get out?

Make bad usage difficult

Which button opens the door?

Usability

is what makes a user enjoy to use a product

[…] the capacity of a system […] to perform the tasks safely, effectively, and efficiently while enjoying the experience. — Wikipedia

Ease of use

  • funcionality matches anticipation
  • use of standards
  • logical flow
  • well-structured navigation system or documentation

The benefits of UX design

Why should we care?

  • lower risk of wrong usage and wrong results
  • saves time and resources and reduces information overload
  • a positive user experience can lead to collaborations

… and more fun! :)

Specific guidelines in Earth System Informatics

Standards

  • are well-known and widely accepted
  • help building usable products
  • help guiding intuition

Standards (Examples)

File formats

use standard formats, preferably machine readable

Input

Separate code and configuration

  • code defines the algorithm
  • configuration defines run-time settings and options

What is configuration?

Hierarchy of configurations

Configurations can usually be set on different levels

  1. System config (/etc)
  2. User config (~/.config)
  3. Project config (usually placed in the project directory)
  4. Environment variables
  5. CLI/API

Parsing command line arguments

Parsing command line arguments

  • getopt - program for parsing arguments in shell scripts
  • getopt exists also in C/C++ and many other languages
  • argparse - parsing arguments in Python scripts

Hands-on

Rewrite safe_copy.py1 to use intuitive argument names, then make it more intuitive.

import argparse
import os
import shutil


def parse_args():
    parser = argparse.ArgumentParser()
    parser.add_argument("-I", "--outfIle", help="Where to copy")
    parser.add_argument("-O", "--sOurce", help="Source file")
    args = parser.parse_args()
    return args


def copy_file(args):
    if not os.access(args.outfIle, os.F_OK):
        shutil.copyfile(args.sOurce, args.outfIle)


if __name__ == "__main__":
    args = parse_args()
    copy_file(args)

A somewhat improved version

import argparse
import os
import shutil


def parse_args():
    parser = argparse.ArgumentParser()
    parser.add_argument("-i", "--infile", help="Where to copy from", required=True)
    parser.add_argument("-o", "--outfile", help="Where to copy to", required=True)
    args = parser.parse_args()
    return args


def copy_file(args):
    if not os.access(args.outfile, os.F_OK):
        shutil.copyfile(args.infile, args.outfile)


if __name__ == "__main__":
    args = parse_args()
    copy_file(args)

What changed?

    parser.add_argument("-i", "--infile", help="Where to copy from", required=True)
    parser.add_argument("-o", "--outfile", help="Where to copy to", required=True)
  • -i with long version --infile for the input file
  • -o with long version --outfile for the output file
  • required=True triggers error message when called without arguments

Further improvements

import argparse
import os
import shutil


def parse_args():
    parser = argparse.ArgumentParser()
    parser.add_argument("infile", help="Where to copy from")
    parser.add_argument("outfile", help="Where to copy to")
    args = parser.parse_args()
    return args


def copy_file(infile, outfile):
    if not os.access(outfile, os.F_OK):
        shutil.copyfile(infile, outfile)


if __name__ == "__main__":
    args = parse_args()
    copy_file(args.infile, args.outfile)

What changed?

    parser.add_argument("infile", help="Where to copy from")
    parser.add_argument("outfile", help="Where to copy to")
  • No -- in front of the argument, and no short version means these arguments become positional and are required by default.
  • The new syntax is copy_file.py INFILE OUTFILE (just as cp)

While running

Escalate Errors

    if not os.access(args.outfile, os.F_OK):
        shutil.copyfile(args.infile, args.outfile)

What could go wrong?

Raise exceptions

  • Programming languages use exceptions to signal problems
  • Functions higher up in the call stack can decide how to respond
  • A program will generally exit if an uncaught exception occurs

Exception handling

The try-except-else statement lets you handle exceptions

try:
    res = do_risky_thing()
except Exception as exc:
    handle_exception()
    raise exc  # optional (!), re-raise the exception
else:  # optional, if no exception in try:
    work_with_result(res)
finally:  # will be executed, no matter what
    clean_up()

move_on_with_normal_flow()

Write decent error messages

  • Tell what happened and why
  • Use proper exception types in Python
  • Exit with non-zero exit code (for Shell scripts)
  • Make sure things can’t continue (if that’s relevant)

Hands-on

Take safe_copy.py and add useful error messages and return codes.

A possible solution

If the target file exists, we raise a FileExistsError.
The caller can decide whether that’s a problem or not.

def copy_file(infile, outfile):
    if not os.access(outfile, os.F_OK):
        shutil.copyfile(infile, outfile)
    else:
        raise FileExistsError(f"File {outfile} already exists.")

An uncaught exception will end the program with return code 1.

Take home messages

  • take a user’s perspective!
  • apply to standards
  • be consistent and intuitive in your style
  • “Don’t lie” :)

Further reading

What’s your UX with this lecture series?

Annex I: safe_copy.py explanations

argparse

Create a parser for command line arguments

parser = argparse.ArgumentParser()
parser.add_argument("-i", "--infile", help="Where to copy")
args = parser.parse_args()

shutil

Call shutil.copyfile() to do the actual copying

def copy_file(args):
    if not os.access(args.outfile, os.F_OK):
        shutil.copyfile(args.infile, args.outfile)

Script execution

This code is only executed, when run as a script (e.g. by using python3 safe_copy.py), but not when loaded with an import safe_copy.

if __name__ == "__main__":
    args = parse_args()
    copy_file(args)