Ryan’s Rules for Website Navigation

It should be intuitive.’   ‘The user should not have to hunt for information.’ Focus on the user.’

Yes.   So, ‘yes’.    If everyone can agree on these things, why don’t we see it in practice?    As usual, the Devil is in the details.    Making a website (or any other kind of software) usable is harder than it seems.     While you’d think great designer can handle all usability problems, it takes more than just usability ‘chops’ to create a great website.    Even with testing, there are a variety of factors that can influence a website’s design – even when everyone has the user at heart.    So, here are a few tips I have to help a little.    For the sake, of brevity I am going to focus in on navigation.

Fewer Labels is Always Better

It works like this:   if you see a relevant path on a website, you will click on it.    If you do not, you will take your next best guess.    Every label does not have to be as explicit as you think it does.   Remember always the Pareto Principle / The 80-20 rule.    Of all the content that gets submitted to a library website, only 20% is vital to the user.    That 20% needs clear, concise & obvious navigation.

Do not let the other 80% get in the way of the vital 20%.    If someone has to make a guess, a navigation system of 4-5 elements is much, much better than a navigation of 25+ items (number taken from a website I am currently responsible for – ‘do as I say …’ ).   You can cheat a little by having different levels of navigation (eg. About, Contact, Jobs etc. in small at the top or bottom), but most website navigations I see out there go way beyond cheat.

Text, Text, Text

Over and over again, people think that promotion via images is important.    It is, if your user base is 10 years of age or younger.   Images get ignored by the user, and often by search engines as well.   A single word or two, explaining where the link will take you is fine.

In fact, I once took an image link off the front page of a website, gave it a logical name and put it in a less obvious place and the use *increased*.

End the Drop-Down Madness!

WordPress.com, I’m talking to you!     Updating my blog has become hell ever since you changed the navigation to include drop-downs.    I click on the wrong things all the time, then I struggle to get back where I was.    Fortunately, this is only for the back-end interface.    For a front-page interface, drop-downs are even more hellish.

Drop downs came into existence because someone came up with the stupid ‘3 clicks or I’m gone’ axiom.     Everyone came to the conclusion that we needed to design sites to reduce clicks, and drop-downs reduced clicks.    However, the real problem was usability.    Drop-downs reduced clicks, but did not increase usability.    It was a zero-value trade-off.    Don’t use them.

Do Not Believe Everything You Read On the Internet

There’s alot of baloney on the internet, believe it or not.    Some people will tell you that your navigation should use verbs; others nouns.   Some people will decry scrolling; others will insist that the blog is the way to go.   Following anyone’s tips is fine, but they should not be used at the expense of common sense.    For instance, avoiding scrolling for the user may be impossible if you consider that some of your users may still be using 800 by 600 screen resolution or less.

A Link Should Send You to the Place You Expect It

If I click on a link that says ‘find a book’ it should help me find a book.    It should not be a list of tutorials on how to find books.    Call it ‘tutorials’ instead (and then do some serious thinking about whether this is a 20% or an 80% thing).

Don’t Be Cute

If you want to provide a way for people to contact you, call it “Contact” or “Contact Us” not, “Get the Skinny” or something else more barbarous.

The Designer Must Decide

In a profession of information experts, everyone thinks they know how best to design a website.    The problem is that each department sees a different user, and wants to make that user happy.    Reference desk people see the person struggling to access a database.    Cataloguers see the user that can get into the system and download every book they need like it was no tomorrow.   Community workers see people struggling to learn a new language or afraid to walk into the library in the first place.    All are important users.   All have unique needs.

Unfortunately, while we want to make these users happy, trying to make everyone happy at the same time results in a website that puts everything but the kitchen sink on the front page — confusing everyone and pleasing no one.    Alternately, we focus on the users who have a negative experience in brief moment in time – so many factors can play into that complaint (the user’s mood at the time, his or her expectations about library service vs what libraries actually offer etc.).     Of course, we need to take user complaints seriously – but is web design really about solving everyone’s unique problem?   I argue no.    Web design is finding out about how human beings interact with computers / digital media and applying that knowledge to improve access.    A good website cannot solve anyone’s particular information need.    It can, however, make the act of discovery more enjoyable.

All this leads to my conclusion – let the designer decide.    He or she may make a mistake about a particular user’s need (and this will be evident through user testing etc.) but he or she will do a better job of improving access than a committee of people all trying to please their particular vision of the user.

Final Words

If you have been paying attention through the tips, you might have noticed a common thread – the problems website designs encounter are often not design problems at all – they are management, consensus-building and coordination problems.    There is always a delicate balance between alienating your stakeholders and having a process be so participatory that it kills the design.   I would argue that more good designs are killed than bad designs improved.     The killing happens over time as priorities change and band-aids are applied to address minor non-essential issues coming from a variety of different places.

What tips do you have to improve navigation of websites?

Part II: How not to Start Your Haskell Program

< Part I: Is There a Such a Thing as ‘Real World’ Haskell? Part: III   How Haskell Monads are Like a Muppet >

My last Haskell post had me thinking that I might as well create a really bad tutorial outlining my own strategies to deal with Haskell in the real world.    Some of the issues I outlined were:

  • Tutorials for Haskell focussed on solving problems, rather than getting it to ‘do stuff’ which is what alot of users expect from their computer software.
  • Haskell is emerging as an important player in the future of code.   Both as a type of code itself and as a way of improving skills in such languages as Java and Python.   However, it will not make the mainstream unless ‘regular folk’ start using it.
  • Functional programs (in theory) are apt to be more sustainable, less buggy and more consistently documented.   Regular folk, working with imperative and/or objective and pseudo objective languages probably don’t realize this -> not until their code breaks and they have to re-install the wheel.

While I have some experience in other languages like Ruby, and Python, I’ve decided to approach Haskell as if I were a PHP developer instead.     There are some very good reasons for this:

  • PHP is a ‘do something’ language.    Basically, it takes dynamic data and outputs it to a web page.   While math problems and recursion-like methods are possible – it’s usually input and output (ie. taking data in and out of a MySQL database) that is the most important.    Anyone expecting to use Haskell for primarily I/O related stuff is going to die from frustration.
  • PHP code can get very messy, even in the hands of an experienced coder.   Documentation of code is all dependent on comments and external manuals.     Haskell can help your average PHP coder, because its type-system offers a kind of in-source documentation.
  • PHP is a ‘regular peoples’ code.    It is adopted by alot of people with varying skills and experience with computer software, many of whom have very little understanding of its long run limitations.
  • Well into its 5th release, alot of the work has already been done for your average PHP coder.       It’s almost not even necessary to create your own objects and functions with all the pre-created libraries available.     Unfortunately, it’s also widely assumed that you are going to create a web application ->  what if you want to turn your code into an App?    or a desktop application that uses data from a php created api?   or an intense web universe ala Second Life or World of WarCraft?
  • As an interpreted program,   it’s pretty simple to solve problems through trial and error.    Just keep hacking away at php, and eventually you can make some convoluted function do what you want it to do (in an unscalable way, of course).

I am also going to make a number of assumptions:

  1. That you have read through at least some of the Haskell Wikibook.    I do not intend to explain what a Monad is, or impress everyone with my knowledge of complex mathematical theory.    This tutorial is an inquiry about how to approach a Haskell applications, not learning Haskell itself.
  2. You have a fair knowledge of some imperative-style computer language (possibly PHP).

As suggested, I am going to look at developing a one-level ‘rogue-like’ RPG game.      If I were to start such a game in php, I might start with something like:

$playerChar = array ("name" => 'Bob', "class" => 'fighter', "STR" => '18', "DEX" => '14', "WIS" => '11', "INT" => '15');

I suggest this because PHP coders want to get to the action as fast as possible.   The PHP coder (let’s call her PHiP) will know that her first problem is making data output in some consistent manner, so will create a variable that mimics a possible set of data that will eventually be displayed to the screen (likely a webpage).   Knowing that things like the name and class of the character will change, PHiP will put some variables inside the array.    Then PHiP will include some other ideas about what a character will need, and a print_r statement to watch the action as she lashes out blindly for the right outputs:

$playerChar ['traits'] = ("name" => $name, "class" => $class ...); $playerChar ['equip'] = ("weapon" => $weapon, "armour" => $armour ...); print_r ($playerChar);

If you are a Haskell coder, you probably already see countless disasters in store for PHiP if she uses this approach with Haskell.    Here are a few:

  • variables in Haskell are always constant.     Once called, the values will not change.   Believe it or not, functional programmers will see this as a good thing (see side effects in Wikipedia).
  • playerChar [‘traits’] would be seen as a function with an input [‘traits’] that, using Haskell syntax, is a list containing one string value ‘traits’.   Haskell would be wondering what to do if it encountered other lists containing one or more other string value(s).
  • All of the variables inside the associative array $playerChar  are irrelevant in Haskell.  Unless they are constant.
  • Deciding what to do with the array would be overwhelming.    A list could be used, but would require that all values inside be strings.   Or it could be a huge tuple of various kinds of values, or a list of tuples.
  • Without being sure what types of values are needed to create the playerChar, there are almost sure to be problems letting PHiP’s player character switch its weapon from a sword to a mace and back.

In short, PHiP is using the wrong paradigm to code effectively in Haskell.    The issue is not a problem of syntax, or even understanding a problem.   The issue is the approach.

As the tutorial goes along, we will deal with PHiP’s player character.    But, to work in Haskell, I propose that you do not start with the data you want to put in and out.    Instead, you start with input and output itself – inside main – like this:

main :: IO() main = do x <- getChar if x == 'q' then putStrLn "Thanks for Playing" else pmove x >> main move :: Char -> String move a |  a == 'w'       = "UP!" |  a == 's'       = "DOWN!" |  a == 'a'       = "LEFT!" |  a == 'd'       = "RIGHT!" |  otherwise      = "HANG AROUND AND DO NOTHING!" pmove = print . move

Right now, this code is pretty useless, but it offers a few nice things to help make sure you don’t lose steam in your coding.

  • It creates an output that will work (sort of) like PHiP’s print_r string.
  • It offers a practical demonstration of point notation, which, in laymen’s terms creates a function pmove that prints (using print) the results of move.    Essentially, it keeps me from having to write “print (move x)” all the time.
  • I accepts an input ‘a’ that is a character.
  • It creates a strongly typed function ‘move’ that takes a Character and returns a String.   As we move forward, we can chain a series of functions together that will help PHiPs make her Haskell program to do more interesting things such as fight a monster.

(as it turns out, this code works slightly differently in Windows than it does in Linux.    Use the Linux version, because it makes me seem a little more competent.   If anyone can explain why Windows wants the CR for the getChar command, please  add it to the comments.)

I am not absolutely sure this is the very best approach to a rogue-like game, but I can guarantee it is better to start this way than it is to begin with creating variables.     As you read this tutorial, I hope you continue to use other documentations elsewhere to help you get your mind around my use of ‘do’, ‘getChar’, ‘putStrLn’ and guards ‘|’ here (pretty rudimentary Haskell code right now).

The next tutorial will look at shaping our dungeon and establishing where our player as he or she moves across the board.

Incidentally, as of writing this, I am working on a rogue-like game with my son called Rasghiosse (my son named it).    I have a public Darcs repository on Patch-Tag that you are free to join in on if you like.   As of writing this tutorial, I am not much further ahead than the above code, so I would appreciate your help.

Part I: Is There a Such Thing as Real World Haskell?

Part II:   How not to Start Your Haskell Program >

Here’s a bit of sardonic code, that I’d like to propose to any Haskell advocate out there.

data Works = Works | Does_not
computerApp a ::  Maybe a -> Works
computerApp a
     | isJust a = Works
     | otherwise = Does_not

I have been playing around with functional programming in Haskell.    I have to say that it has more than certainly improved my ability to code in other languages, and probably has reduced the number of bugs I have to fix after the fact.    On the other hand, it has driven me absolutely batty.

To be fair, I need to say that I am not a computer engineer.    I have a BA in English.    My Masters are in Public Administration and Information Management.      I engaged in Haskell code simply as a curiosity and a challenge.    I love math, and became curious about Monads and Lambda calculus.    I am probably not smart enough to be a great Haskell programmer.   However, I do understand two things.    1)  Not-smart-enough people can and want to participate in application development   2)  Coders, while making apps that do what they expect them to do, do not always understand (or care) about the sustainability and/or scalability of their code.

Web Development is an important test case.      Just about anyone, with a reasonable amount of time and effort, can learn to develop a website in PHP, probably supported by some content management system as Drupal or ModX.    Somewhere, their development goes overboard, the system does an upgrade to support some security risk or vulnerability, and ‘pop’ –>  all that likely un-documented and messy code goes nowhere and wheels need to be reinvented.

That’s why learning Haskell is probably a good idea.    Without getting into the code itself, it insists that a function always causes the same result to happen with any given input(s).    Once developed, the documentation pretty much always exists in a minimal form (via Type declarations).    So many bad habits would disappear if only people were forced into developing this way.

The problem, unfortunately, is that Haskell coding is confusing.     There is no popular development framework to use it.     Once you try to apply the examples provided in text books to real world development, things go wonky.    I won’t go into the many reasons why, but I do have an observation based on what I’ve seen in responses from various gurus to newbies like me.

It’s this ->   Users think computers do things.    Computer engineers think computers solve problems.     In Haskell terms, any interaction between users and engineers results in a type error.    Somewhere along the line, an IO() monad needs to be created to turn what engineers like about Haskell into something that users will like about it.

I would like to propose a management framework, similar to extreme programming, to manage the development of functional code for regular people.   While Programming it in Haskell is not a bad start, it uses a problem solving model, rather than a ‘how do you make the software do x’ model.    It focuses on mathematical abstractions rather than simple actions.     For instance, I would like to see a book that uses the development of a rogue-like rpg game in Haskell as an example.    Instead of worrying about efficient computation, abstractions about ‘laziness’ and recursive factorial examples, the writer would have to focus on managing complex (a tuple of a lists of tuples) types, worrying about random numbers and IO issues that are inherent to Haskell.   In approaching such a game, should I worry about creating newtypes first, or work from what I want main to do and fill in the gaps?

But while I make this suggestion, I really have no idea of what kind of advice I can offer your typical new-to-haskell coder.     But I have some hypotheses:

  • work from the main :: IO() first and build a framework of functions to develop your outputs.
  • possibly create type variables for each of your functions, making it equal in Type to a typical output you would like to see.    Then work backwards from there to create a lazy output, then involve possible recursion and so on.
  • use generic types (eg. Int, String, Char etc.) with comments first, then develop types to make your code more clear.
  • unit tests should include the System.IO.Unsafe module (cheating should be allowed when you are testing your code – let the learning happen when you are developing real code)

I’ll add what I can as I continue to learn more about coding in Haskell.    The bottom line is that I think more people should be coding in a language like Haskell, but they are unlikely to work with it if they end up spending a bajillion hours just to get it to choose randomly from a list of monsters (for example).   Especially when they can learn how to do the same in three minutes using an imperative language like Python.

For the greater good and more sustainable code overall, what high-level tips or approaches can you offer any newbie coders of Haskell, so they can develop without becoming absolutely bogged down in failure with their Haskell programs?

UPDATE:   After writing this, I found a great powerpoint tutorial by Graham Hutton that uses Hangman as an example of interactive Haskell code development.