Posts Tagged With: Usability

Submit forms using Javascript without breaking the Internet, a short guide

Do you write forms on the Internet? Are you planning to send them to your server with Javascript? You should read this.

The One-Sentence Summary

It's okay to submit forms with Javascript. Just don't break the internet.

What Do You Mean, Break the Internet?

Your browser is an advanced piece of software that functions in a specific way, often for very good reasons. Ignore these reasons and annoy your users. User annoyance translates into lower revenue for you.

Here are some of the ways your Javascript form submit can break the Internet.

Submitting to a Different Endpoint Than the Form Action

A portion of your users are browsing the web without Javascript enabled. Some of them, like my friend Andrew, are paranoid. Others are on slow connections and want to save bandwidth. Still others are blind and browse the web with the help of screen readers.

All of these people, when they submit your form, will not hit your fancy Javascript event handler; they will submit the form using the default action and method for the form - which, if unspecified, default to a GET to the current page. Likely, this does not actually submit the form. Which leads to my favorite quote from Mark Pilgrim:

Jakob Nielsen's dog

There is an easy fix: make the form action and method default to the same endpoint that you are POSTing to with Javascript.

You are probably returning some kind of JSON object with an error or success message and then redirecting the user in Javascript. Just change your server endpoint to redirect if the request is not an AJAX request. You can do this because all browsers attach an X-Requested-With: XMLHttpRequest HTTP header to asynchronous Javascript requests.

Changing Parameter Names

Don't change the names of the submitted parameters in Javascript - just submit the same names that you had in your form. In jQuery this is easy, just call the serialize method on the form.

var form = $("#form-id");
$.post('endpoint', $(form).serialize(), function(response) {
    // do something with the response.
});

Attaching the Handler to a Click Action

Believe it or not, there are other ways of submitting a form besides clicking on the submit button. Screen readers, for example, don't click, they submit the form. Also there are lots of people like me who use tab to move between form fields and press the spacebar to submit forms. This means if your form submit starts with:

$("#submit-button").click(function() {
    // Submit the form.
});

You are doing it wrong and breaking the Internet for people like me. You would not believe how many sites don't get this right. Examples in the past week: WordPress, Mint's login page, JetBrains's entire site.

The correct thing to do is attach the event handler to the form itself.

$("#form-id").submit(function() {
    // Write code to submit the form with Javascript
    return false; // Prevents the default form submission
});

This will attach the event to the form however the user submits it. Note the use of return false to avoid submitting the form.

Validation

It's harder to break the Internet with validation. To give fast feedback loop to the user, you should detect and prevent invalid input on the client side.

The annoying thing is you have to do this on both the client side and the server side, in case the user gets past the client side checks. The good news is the browser can help with most of the easy stuff. For example, if you want to check that an email address is valid, use the "email" input type:

<input type="email" />

Then your browser won't actually submit a form that doesn't have a valid email. Similarly you can note required fields with the required HTML attribute. This makes validation on the client a little easier for most of the cases you're trying to check for.

Summary

You can submit forms with Javascript, but most of the time you'll have to put in extra effort to duplicate functionality that already exists in your browser. If you're going to go down that road, please put in the extra effort.

Helping Beginners Get HTML Right

If you've ever tried to teach someone HTML, you know how hard it is to get the syntax right. It's a perfect storm of awfulness.

  • Newbies have to learn all of the syntax, in addition to the names of HTML elements. They don't have the pattern matching skills (yet) to notice when their XML is not right, or the domain knowledge to know it's spelled "href" and not "herf".

  • The browser doesn't provide feedback when you make mistakes - it will render your mistakes in unexpected and creative ways. Miss a closing tag and watch your whole page suddenly acquire italics, or get pasted inside a textarea. Miss a quotation mark and half the content disappears. Add in layouts with CSS and the problem doubles in complexity.

  • Problems tend to compound. If you make a mistake in one place and don't fix it immediately, you can't determine whether future additions are correct.

This leads to a pretty miserable experience getting started - people should be focused on learning how to make an amazingly cool thing in their browser, but instead they get frustrated trying to figure out why the page doesn't look right.

Let's Make Things A Little Less Awful

What can we do to help? The existing tools to help people catch HTML mistakes aren't great. Syntax highlighting helps a little, but sometimes the errors look as pretty as the actual text. XML validators are okay, but tools like HTML Validator spew out red herrings as often as they do real answers. Plus, you have to do work - open the link, copy your HTML in, read the output - to use it.

We can do better. Most of the failures of the current tools are due to the complexity of HTML - which, if you are using all of the features, is Turing complete. But new users are rarely exercising the full complexity of HTML5 - they are trying to learn the principles. Furthermore the mistakes they are making follow a Pareto distribution - a few problems cause the majority of the mistakes.

Catching Mistakes Right Away

To help with these problems I've written an validator which checks for the most common error types, and displays feedback to the user immediately when they refresh the page - so they can instantly find and correct mistakes. It works in the browser, on the page you're working with, so you don't have to do any extra work to validate your file.

Best of all, you can drop it into your HTML file in one line:

</p>
<script type="text/javascript" src="https://raw.github.com/kevinburke/tecate/master/tecate.js"></script>
<p>

Then if there's a problem with your HTML, you'll start getting nice error messages, like this:

error message

Read more about it here, and use it in your next tutorial. I hope you like it, and I hope it helps you with debugging HTML!

It's not perfect - there are a lot of improvements to be made, both in the errors we can catch and on removing false positives. But I hope it's a start.

PS: Because the browser will edit the DOM tree to wipe the mistakes users make, I have to use raw regular expressions to check for errors. I have a feeling I will come to regret this. After all, when parsing HTML with regex, it's clear that the <center> cannot hold. I am accepting this tool will give wrong answers on some HTML documents; I am hoping that the scope of documents turned out by beginning HTML users is simple enough that the center can hold.

Designing a better shower faucet

How should you design the controls for a shower? Let's take a quick look.

Affordance

a hammer

A device should make clear by its design how to use it. Take a hammer for example.

No one has ever looked at a hammer and wondered which end you are supposed to grab and which part you're supposed to pound nails with. This is an example of good affordance.

Some things do not have such good affordance, like the shower at my friend's house. It looked like this, except the handles were perfectly horizontal.

shower faucet and handles

The shower handles have one good affordance - you know where you are supposed to grab, and it's clear you are supposed to rotate the handles. However they leave the following questions unanswered.

  • Which one is hot and which one is cold?
  • How far do I have to turn the handles to reach the desired temperature?
  • What combination of hot and cold do I want?
  • Which direction do I turn the handles, up or down?

That's pretty bad for a device which doesn't need to do much. Maybe not as bad as this sink with two faucets, one for hot and one for cold:

sink fail

But it leaves a lot for the user to figure out, especially when there is usually a lag between when you move the handle and when the temperature changes, making it tough to figure out what's going on.

Designing a Better Showerhead

Functionally, a device should have two properties:

  1. Allow you to do the tasks you want
  2. Make it easy for you to do those tasks.

That's it - if the device is pretty on top of this, that's a big bonus. What do we want a shower to do?

  • Turn on hot water
  • Occasionally, make it even hotter
  • Turn off the water

That's it. These tasks don't map terribly well to the current set of faucets, which ask you to perform a juggling act to get water at the right temperature.

So how can we design a tool to do just this? I'll assume for the moment we have to stick with a physical interface - a tablet for a shower control would allow interesting choices like customizing the shower temperature per user, but would put this out of the reach of most homes. A good start would be a simple control to turn the water on and off. It's not necessary that the control shows the state of water, on or off, as you get that feedback from the hot water - it could just be a button that you press.

That's a good start, now how to control the temperature? I wasn't able to find good data, but my guess is that most people want showers in a 15 degree range of hot to very hot. Either way, there should be a sliding control that lets you select temperatures in this range.

The sliding shower handle comes close and this is one of the better designs I've seen:

Sliding shower handle

However it still has two problems. It shouldn't have a cold range at all, or select a temperature which will burn you.

Second, sliding the handle changes both pressure and temperature. You should get the best pressure available the moment you slide the handle a little bit.

Third, the feedback you get when you turn the shower off could be better. The device could offer a little resistance, and then slide into place when turning it on or off - this way you know that the shower is on or off, similar to the way stoves and iPhone headphones slide into place with a satisfying click.

A shower handle that gave resistance when turning it on or off, turned on full blast straight away, and only let you slide between various hot temperatures. That would be nice.

How to design your API SDK

I've worked with Twilio's client libraries pretty much every day for the last year and I wanted to share some of the things we've learned about helper libraries.

Should you have helper libraries?

You should think about helper libraries as a more accessible interface to your API. Your helper libraries trade the details of your authentication scheme and URL structure for the ease of "do X in N lines of code." If the benefits of a more accessible interface outweigh the costs, do it.

If people are paying to access your API (Twilio, AWS, Sendgrid, Stripe, for example), then you probably should write helper libraries. A more accessible API translates directly into more revenue for your company.

If you're two founders in a garage somewhere, maybe not. The gap between your company's success and failure is probably not a somewhat easier API interface. Writing a helper library is a lot of work, maybe one to four man-weeks depending on the size of your API and your familiarity with the language in question, plus ongoing maintenance.

You might not need a client library if your customers are all highly experienced programmers. For example the other day I wrote my own client for the Recaptcha API. I knew how I wanted to consume it and learning/installing a Recaptcha library would have been unnecessary overhead.

You may also not need a client library if standard libraries have very good HTTP clients. For example, the Requests library dramatically lowers the barrier for writing a client that uses HTTP basic auth. Developers who are familiar with Requests will have an easier time writing http clients. Implementing HTTP basic auth remains a large pain point in other languages.

How should you design your helper libraries?

Realize that if you are writing a helper library, for many of your customers the helper library will be the API. You should put as much care into its design as you do your HTTP API. Here are a few guiding principles.

  • If you've designed your API in a RESTful way, your API endpoints should map to objects in your system. Translate these objects in a straightforward way into classes in the helper library, making the obvious transformations - translate numbers from strings in the API representation into integers, and translate date strings such as "2012-11-05" into date objects.

  • Your library should be flexible. I will illustrate this with a short story. After much toil and effort, the Twilio SMS team was ready to ship support for Unicode messages. As part of the change, we changed the API's 'Content-Type' header from

application/json

to

application/json; charset=utf-8

We rolled out Unicode SMS and there was much rejoicing; fifteen minutes later, we found out we'd broken three of our helper libraries, and there was much wailing and gnashing of teeth. It turns out the libraries had hard-coded a check for an application/json content-type, and threw an exception when we changed the Content-Type header.

  • Your library should complain loudly if there are errors. Per the point on flexibility above, your HTTP API should validate inputs, not the client library. For example let's say we had the library raise an error if you tried to send an SMS with more than 160 characters in it. If Twilio ever wanted to ship support for concatenated SMS messages, no one who had this library installed would be able to send multi-message texts. Instead, let your HTTP API do the validation and pass through errors in a transparent way.

  • Your library use consistent naming schemes. For example, the convention for updating resources should be the same everywhere. Hanging up a call and changing an account's FriendlyName both represent the same concept, updating a resource. You should have methods to update each that look like:

$account->update('FriendlyName', 'blah');
$call->update('Status', 'completed');

It's okay, even good, to have methods that map to readable verbs:

$account->reserveNumber('+14105556789');
$call->hangup();

However, these should always be thin wrappers around the update() methods.

class Call {
    function hangup() {
        return $this->update('Status', 'completed');
    }
}

Having only the readable-verb names is a path that leads to madness. It becomes much tougher to translate from the underlying HTTP request to code, and much trickier to add new methods or optional parameters later.

  • Your library should include a user agent with the library name and version number, that you can correlate against your own API logs. Custom HTTP clients rarely (read: never) will add their own user agent, and standard library maintainers don't like default user agents much.

  • Your library needs to include installation instructions, preferably written at a beginner level. Users have varying degrees of experience with things you might take for granted, like package managers, and will try to run your code in a variety of different environments (VPS, AWS, on old versions of programming languages, behind a firewall without admin rights, etc). Any steps your library can take to make things easier are good. As an example, the Twilio libraries include the SSL cert necessary for connecting to the Twilio API.

How should you test your library?

The Twilio API has over 20 different endpoints, split into list resources and instance resources, which support the HTTP methods GET, POST, and sometimes DELETE. Let's say there are 50 different combinations of endpoints and HTTP methods in total. Add in implementations for each helper library, and the complexity grows very quickly - if you have 5 helper libraries you're talking about 250 possible methods, all of which could have bugs.

One solution to this is to write a lot of unit tests. The problem is these take a lot of time to write, and at some level you are going to have to mock out the API, or stop short of making the actual API request. Instead we've taken the following approach to testing.

  1. Start with a valid HTTP request, and the parameters that go with it.
  2. Parse the HTTP request and turn it into a piece of sample code that exercises an aspect of your helper library.
  3. Run that code sample, and intercept the HTTP request made by the library.
  4. Compare the output with the original HTTP request.

This approach has the advantage of actually checking against the HTTP request that gets made, so you can test things like URL encoding issues. You can reuse the same set of HTTP requests across all of your libraries. The HTTP "integration" tests will also detect actions that should be possible with the API but are not implemented in the client.

You might think it's difficult to do automated code generation, but it actually was not that much work, and it's very easy if you've written your library in a consistent way. Here's a small sample that generates snippets for our Python helper library.

def process_instance_resource(self, resource, sid, method="GET", params=None):
    """ Generate code snippets for an instance resource """
    get_line = '{} = {}.get("{}")'.format(self.instance_name, self.base, sid)
    if method == "GET":
        interesting_line = 'print {}.{}'.format(self.instance_name,
            self.get_interesting_property(resource))
        return "\n".join([get_line, interesting_line])
    elif method == "POST":
        update_line = '{} = {}.update("{}", {})'.format(
            self.instance_name, self.base, sid, self.transform_params(params))
        interesting_line = 'print {}.{}'.format(
            self.instance_name, self.get_interesting_property(resource))
        return "\n".join([update_line, interesting_line])
    elif method == "DELETE":
        return '{}.delete("{}")'.format(self.base, sid)
    else:
        raise ValueError("Method {} not supported".format(method))

Generating code snippets has the added advantage that you can then easily embed these into your customer-facing documentation, as we've done in our documentation.

How do people use helper libraries?

While pretty much every resource gets used in the aggregate, individual accounts tend to only use one or two resources. This suggests that your API is only being referenced from one or two places within a customer's codebase.

How should you document your helper library?

Per the point above, your library is probably being used in only one or two places in a customer's codebase. This suggests your customer is hiring your API to do a specific job. Your documentation hierarchy should be aligned around those jobs. Combined with the integration test/code snippet generator above, and you should have a working code example for every useful action in your API. You will probably also want to have documentation for the public library interface, such as the types and parameters for each method, but the self-service examples will be OK for 85% of your users.

Bash user? Try Zsh, the more usable terminal shell

On most operating systems, the default command line shell is Bash. Bash is a perfectly good shell. However there are a number of tasks that are slow or annoyingly time-consuming in Bash, particularly relating to the shell history. It's like using your phone to complete tasks, instead of a laptop.

Zsh is a newer terminal shell with slightly different syntax than Bash. Zsh makes many smart usability decisions where Bash fails, helping you get work done faster. I thought I'd highlight some of the best examples.

ZSH skips repeat commands in history. Let's say I run our unit test suite 20 times in a row. With Bash, if I wanted to get the command I ran just before that, I'd have to hit the up arrow 21 times to get the previous line. Zsh combines all the duplicate commands into one history item, so you only have to press 'up' twice to get that old command.

Ctrl+U deletes the whole line, no matter where the cursor is. In Bash Ctrl+U will delete everything left of the cursor. I have never wanted to delete everything left of the cursor without also deleting the whole line.

Command sensitive history. In Zsh if I type git and then press 'up', Zsh will cycle through all of my latest git commands, skipping any non-git commands. This is especially useful with a few infrequent commands I run that take many command line options, such as our configuration scripts.

Shared history across tabs. With Bash, using the 'up' arrow to access previous commands only gives you access to the history of the current tab. This is like having Chrome only remember your history for one given tab, instead of sharing it across all your tabs.

Smarter tab completion out of the box. Zsh is smart about figuring out which filenames you actually want. There's a good list of tab completion examples here, the two that stand out for me are:

  • Typing

    rm foo*<tab>
    

    will expand to

    rm foo.txt foo.txt.swp foo.o foo.c
    

    or however many files beginning with foo there are in the directory.

  • Typing

    vim zzz<tab>
    

    will match in the middle of files, for example blah-blah-blah-zzz.txt.

You should give it a try - it may be a little unfamiliar at first, but you'll save a lot of time and annoyance by completing tasks more quickly with Zsh. You can switch by typing at the Bash command prompt:

$ zsh

That will load Z Shell in the current window. You can change your shell permanently by running:

$ chsh -s $(which zsh)

Let me know what you think!

Virtualenv is an anti-pattern (for beginners)

Every time I do a user test with a beginning programmer, I remember how hard computers are, how unforgiving the tools are, and end up wanting to apologize for how annoying and strict programming is. We are making progress with teaching people how to code, but it's still really hard.

For example, if you are just getting started with Python, here's a short list of problems you might face when trying to set up Flask, which is by far the easiest Python web server to set up.

  • Learning how to cd in the terminal
  • How URL's requested by a user map to actual code
  • HTML, CSS and Javascript, because you actually want it to be pretty.
  • How to read and write things from a database
  • Installing Flask, so learning how to use pip or easy_install
  • Python telling you your file is no good because it mixes tabs and spaces.
  • How to run Flask locally

How to draw an owl: 1. Draw some circles 2. Draw the rest of the fucking owl

And that's not even counting the stuff that's so obvious to us we forget to mention it. Most quickstart guides also fail to help people make incremental progress.

Game designers are great at teaching new, hard things. They have to be, or no one will play their games. You will notice that games don't start with you battling Ganon in an epic death match; they start with you learning how to use the character and perform actions like make a kick, or open a door. Through a series of incremental successes you become an expert in the game and can tackle more and more complex tasks.

It bugs me to see so many Python tutorials mention virtualenv as a requirement to get started. (virtualenv is a tool for sandboxing your Python apps, so each Python project on your computer is using its own set of packages). The biggest advantage of virtualenv is that you can have different versions of the same Python package (like Flask or requests) that are required by different projects, whereas if you install them system-wide you can't.

However, recommending virtualenv just adds another thing you have to do before you can see pretty lights on the screen, and represents another possible opportunity for people to lose interest, and start doing something else instead of learning how to get a web server set up.

It also introduces a significant opportunity for confusion; the "It was working yesterday, why isn't it working now?" problem. You need to remember to source your virtualenv file in every Terminal shell where you're running Python, or your terminal will tell you it can't find the library you literally just installed. Needless to say this is confusing, the Terminal won't tell you how to solve the problem, and Googling for the answer isn't likely to give you the solution you need, because it's such a generic error message.

I've never seen beginners run into the problem of needing conflicting versions of a Python package for two different projects. I was comfortable dumping everything into site-packages for over two years of Python development; only when I started working at Twilio did I need to start installing virtualenvs for every project.

As a community, I believe we should stop recommending that beginners install virtualenv. The faster we can get beginners to a Holy Shit, I Wrote Code That Made Something Happen moment, the better, and virtualenv is a big block for getting to that point. Instead I'd recommend installing pip using the one line curl program in the second paragraph here. virtualenv is something that's more appropriate to learn about and use once you have a few Python projects under your belt.

Stop hurting my browser

I love Tweetdeck. Well, I love parts of Tweetdeck. Specifically the side-by-side view makes it really easy to see my stream, my replies, people linking to my website and people talking about Twilio on one screen and I haven't found another tool that can do it. But Tweetdeck also breaks my browser in really annoying ways. Here are the most annoying examples.

Use of outline:none on buttons.

When you tab through a form, Tweetdeck doesn't show you which button is currently focused on the screen. I tend to stay on the keyboard wherever I can because switching to the mouse is so slow. It's much faster to fill out forms tabbing with the keyboard than clicking around with the mouse.

Operating systems have highlighters that show you which button is currently focused - on Mac OS X they show a blue glow around the box that's currently focused, like this:

Focused text box

Clearly you can see the US Dollar field is focused. Now if I tab again, the "Measurement Units" button is focused:

Focused select box

Tweetdeck doesn't like having outlines on their buttons. This is what you get if you tab from the "Password" field:

Focused password field

See how the focus disappears:

Focus disappears

It's not that annoying there. Where it's really annoying is when you are trying to post a new tweet. In GMail when I press Tab from the message body, the focus jumps straight to the "Send" button:

Gmail focused send button

This is perfect because it makes sending emails really fast - I just hit Tab, Enter and the email's sent and I'm back in my inbox.

When you press Tab + Enter from the "Tweet" field in Tweetdeck, instead of posting your Tweet, they jump you to the Camera button:

tweet text focus, tab reveals..

tweetdeck camera upload page

Normally this is annoying, but it's not that annoying; I can just Tab multiple times to get to the button. But Tweetdeck also hides the focus with outline:none in their CSS, so you can't actually tell which button is currently focused. This means you can't figure out how many times you need to Tab through to get to the Tweet button.

It's really not that hard to fix, and it won't make a lick of difference to the mouse-clicking hoi polloi. Just change the HTML tabindex of the form, and add a focused style for the button.

Using target=_blank for links.

When I read my stream, I read through all the Tweets first, opening up interesting links in new tabs to read later. I don't want to constantly be jumping back and forth between my stream and articles, because I lose my place in the stream.

Fortunately, browsers offer two methods for opening new tabs in the background. One is to hold Cmd while clicking on a link. The second is to right click and press "Open in new tab."

Neither of these is good enough for Tweetdeck; they force you to immediately switch out of your stream into new articles by adding a target="_blank" attribute to all links in the app. target="_blank" links override your browser's default behavior and switch your focus immediately to the new tab or window.

The reason they attach target=_blank attributes to their URL's is so that all of their links open in a different tab, instead of the same and Tweetdeck stays open in the browser. But that's also evil, because it breaks a user's expectation about what's going to happen when they click on the link. I want to open links in a different tab, I just don't want them to be focused, and Tweetdeck makes this impossible.

Completely breaking when Javascript is disabled.

Lately I've been playing with disabling Javascript in my browser. Mostly I am disappointed in how much of the Internet breaks when you disable Javascript, especially pages that only show content like news articles or blog posts.

It's nice at least when a site includes a <noscript> tag telling you that you need to enable Javascript for the site to function. Tweetdeck doesn't even do this. Here is what you get if you browse to web.tweetdeck.com with Javascript disabled:

Empty Tweetdeck screen with Javascript disabled

That's a blank screen, with no notice or indication that your browser didn't crap out.

They also detect your user agent, and error out if you try to access Tweetdeck with Firefox or Opera, without even making an attempt to display the page. I can understand not supporting IE, but I don't understand why they can't even try Firefox.

Unsupported browser

Conclusion

Tweetdeck is good enough that I'll continue to use it, but there are some simple things that make my experience a little miserable every time I click on a link or try to write a new Tweet. I wish Twitter as a whole cared more about accessibility and usability for all of its users (here's another example); with an estimated 100 million active users, even a small percentage of users who lack the fine motor control to use a mouse (or even a keyboard) is still a large number of people that are affected by problems like this.

Better to prevent mistakes than to fix them quickly

Friday one of my favorite teams, St. Mary's, dropped an extremely close game to Purdue. They were up one point with 31 seconds to go when one of their senior players tried to run the baseline, something you can only do after you have scored a basket. Purdue took the ball and went on to win the game.

Client Steindl hangs his head

Obviously it was a bad mistake for the player to make in that situation. But there's another person who is to blame: the referee. Before inbounding the ball, the referee will signal to the player that they either can or cannot run the baseline. Sure, the referee can blow the whistle every time there is a violation, but it's better to prevent the error in the first place. It would be like letting players line up for a free throw in the wrong order, letting the player shoot and then blowing the whistle for incorrect order.

Ultimately the blame belongs with the player who made the mistake; he should have known better. But it was an awful way to decide the game; on a technicality instead of through the actions on the court.

It's a known law of websites that any type of mistake that can be made by your users (entering a username instead of an email address, entering a wrong phone number, etc) will be. For those cases we write error handling code and prevent incorrect data from being written to our database. But it's better to prevent the error as quickly as you can - as soon as they make the mistake, if it's possible. The more time that elapses between the error occurring and the time you tell them about it, the more frustrated they are likely to be. Even better is to design your form in a way that prevents them from making the mistake in the first place.

Pretty much every site needs to validate form data on the server to make sure it's correct. But the best sites will also validate data on the client side, e.g. when the user is typing it into their computer. This way they can prevent users from making dumb mistakes.

How beginning programmers should read a quickstart guide

Programming is hard. Especially when you are just getting started, there are a lot of things, in Donald Rumsfeld's words, that you "don't know that you don't know." Lots of quickstarts for beginners assume the reader knows things about how the command line works that my experience shows they don't. I do lots of user tests with people new-to-programming and see these errors again and again.

I thought I'd put together a short list of things quickstart writers leave out, that will still leave you totally stumped.

  • Most of the time if you see an indented block of text in a fixed width font, like this:

    $ foo baz bang
    

    It usually means you're supposed to do something with the text in the box.

  • If the text in the box has a dollar sign at the beginning of it, it represents a command you are supposed to enter in your Terminal. If you get an error that looks like this:

        bash: $: command not found
    

    It means you aren't supposed to copy the dollar sign. Just type foo baz bang and hit <Enter>. Unfortunately it's hard to Google for dollar signs, so you can't really figure out what you did wrong.

  • If there's a dollar sign, followed by some more text on the lines below the dollar sign, the lines below represent the output of running the command correctly. For example:

        $ python run.py
         * Running on http://127.0.0.1:5000/
         * Restarting with reloader
    

    You are only supposed to type in python run.py into your Terminal. The rest of that stuff is the output of running the command correctly.

  • If the block of text doesn't have a dollar sign, it's probably a snippet of code you are supposed to copy into a text editor and save into a file (On Mac, use TextWrangler; on Windows use Notepad++). Hunt around the quickstart for a filename you should use.

  • If they don't tell you where to save the files, create a new folder and save all of the files in there, in the top level.

  • If the command line mentions a file you've recently created, like this:

        $ python run.py
    

    You need to run the command from "inside" the same folder as the file. The terminal has a notion of being "in" a directory (Directories and folders are the same thing). Here's a short guide:

    • To figure out which directory you are in, type pwd and press Enter. (pwd stands for "print working directory").

    • To list all files and folders in the current directory, type ls -al and press Enter.

    • To go into a folder below the current one, type cd Documents (or whichever folder you are trying to navigate to). To do more than one type cd Documents/code.

    • To go up a level type cd ..

    Once you're "in" the right place you should be able to run the command properly.

  • If you feel like you are spinning your wheels, ask for help! It's important to know how to ask. Make sure to tell people a) what you are trying to do, b) what you expected to happen, and c) what actually happened. Bonus points if you can talk about things you tried previously and why they failed to do what you wanted.

As an author of a quickstart myself, I feel like I owe an apology to users who are just getting started, for not including this information along with our guide. Sadly the terminal is just about the least beginner-friendly piece of software I can think of, and when you are just getting started, so-called "simple" errors can totally derail you and make you want to go outside and play Frisbee or roller blade.

Hopefully these tips will help you get started doing that cool tutorial you've always wanted to do.

CMC’s website shows vast improvements

Last summer I tore into CMC's website redesign, saying that the new design emphasized looks over function and did a poor job of explaining what made CMC special. I recently visited the site and they've made a bunch of usability improvements.

Here are some of the highlights. Again, I offer these up with the caveat that, I haven't done any testing or looked at any data, but I do have a lot of experience in this area.

  • The old homepage, with only 14 links, call to action button that looked like an ad, and incredibly-difficult-to-change photo content, is gone. Instead users are redirected straight to http://cmc.edu/discovercmc, which is a much better page.

  • The Discover CMC page has lots of dynamic content that promises to be much easier to update; photos of speakers, links to events, a Twitter widget and a sliding bar. It also has an updated meta description, so a Google search for "Claremont McKenna" returns more contextual information about CMC.

  • Static assets (images, CSS, Javascript) are being cached with a Last-Modified and an E-Tag header, so that browsers will not re-request the same images and CSS every time a user requests the homepage. This will help with page load times.

  • There's a call to action button on the homepage: "Plan your Visit to Claremont McKenna today."

  • The "Student Gateway" replaced all of the stock photos with links to useful content, like the login form for your email account, which used to take around four clicks. That is outstanding. (For the record, http://bit.ly/cmcmail will take you right to the old form - I set up that link junior year :)) It looks like a page I would actually use to find things I was looking for - the maintenance request page, the Collins menu, etc.

  • The calendar on the Student Gateway page uses Google Calendar, instead of the old ASPX event calendar that no one used.

  • The "Prospective Students" page has an explanation of why you should apply to CMC.

  • Skip links for disabled users!! These will help people skip to the main page content and help CMC, a nonprofit, meet government standards for website accessibility.

  • The professor home pages, which I singled out for SEO improvements, have gotten about halfway there; it's clear someone is thinking about improvements in that area. Pages now contain an h1 tag and some keywords describing what the professor does; it's a lot of work, but the pages would be best with a unique <title> attribute and a meta description, however.

These add up to amazing improvements in usability and discoverability; they've addressed most of the problems with the old site. It also represents a tremendous amount of effort on the website and whoever is responsible should be proud.

That said, it's still not perfect, and there are some more quick usability/SEO wins to accomplish. Here's a shorter, less urgent, list of areas they could still improve upon:

  • You can access the Discover CMC page from eight distinct URL's:

    • www.cmc.edu/discovercmc
    • cmc.edu/discovercmc
    • claremontmckenna.edu/discovercmc
    • www.claremontmckenna.edu/discovercmc
    • www.cmc.edu/discovercmc/index.php
    • cmc.edu/discovercmc/index.php
    • claremontmckenna.edu/discovercmc/index.php
    • www.claremontmckenna.edu/discovercmc/index.php

    Google will sometimes interpret duplicate content as a sign that you're trying to farm for content by placing the same text at different URL's. It also means Google is unsure which version of the page to point people to. It's better for Google rankings to redirect all duplicate content to one canonical domain/URL with a 301 (and better still to serve it at the root - shorter URL's rank more highly).

  • It feels odd to have distinct pages for Admission and for Prospective Students; those two have a ton of overlap and it might be best to merge them. Prospective students are the only group interested in Admissions information, and the Admission pages may get more love (see the outdated Twitter feed on the Prospective students page).

  • The dropdown menu is great and includes a ton of links to useful content. However, I expected that when I hovered over the menu item, the menu would appear automatically. Instead I had to click to make the menu appear. Normally I expect when I click on something that looks like a link, I will be taken to a different page, so I was hesitant to click on the link.

    Dropdown menus have a usability problem where users scrolling the mouse from above the menu to below the menu trigger the flyout, even though they don't mean to. The best practice here is to have the menu only appear after the user has hovered over the item for around half a second, so that transient mousers don't trigger the flyout.

One of the reasons I set up Good Morning CMC was to provide students with an actually useful calendar and a more accessible view of the information that we needed on a daily basis. With these changes Good Morning CMC is becoming close to redundant.

The number of CMC students interested in different tech fields - web design, marketing, entrepreneurship - has been on the rise recently. I wouldn't be surprised if the web team and some smart interns couldn't continue to improve the site, boosting application rates, prospective student contact rates, and alumni giving rates, through iterative improvements to the current site.

PS Sorry I didn't include images or links - I am trying to blog more often and cut down on the amount of time it takes to do so.