Archive for January, 2009

A Gallery of Bad Design

January 30, 2009

A large number of (what I consider to be) design errors:

Amazon

  1. Amazon has a list of books I’ve already bought from Amazon. It also has a list of books I intend to buy, courtesy of my (large) shopping cart. It also has a list of books I have no interest in, due to my clicking “Not Interested” where appropriate. Yet, throughout the site, it continues to recommend books from all three categories.

    The Little Computer Scientist’s recommendation: Amazon’s recommendation engine should not recommend books I already own or books that are already in my shopping cart. 
     

  2. I keep many books in my “Saved for Later” section of the Shopping Cart. It’s my “intend to buy when I have time to read” list. Every so often I bump a few books into the Shopping Cart proper and buy them. The UI for the “Saved for Later” does not support searching or efficient browsing. Furthermore, when I look at a book listing, there is no hint if that book is already in my cart.

    Recommendation: Allow searching in a cart. When I make a change in the cart, it should not cause a full page reload, nor lose my place in the paginated list. Integrate the cart with book listings, such that a listing for a book warns me if the book is already in my cart. 
     

  3. Amazon maintains a taxonomy of books. It allows a user to “Browse by Category.” But many books are in the wrong categories. There is also lots of overlap. For example, The Black Swan and The Adobe Photoshop CS4 Book for Digital Photographers top the Computer Science category. The Adobe Photoshop CS4 Book for Digital Photographers tops the Software Engineering category under Computer Science. What?

    Here are the categories for Adobe Photoshop CS4 Book for Digital Photographers:

    1. #1 in Books > Computers & Internet > Programming > Algorithms > Digital Image Processing
    2. #1 in Books > Computers & Internet > Computer Science > Software Engineering > Information Systems
    3. #1 in Books > Computers & Internet > Digital Photography & Video > Adobe Photoshop

      In an earlier revision of this post, I accused Scott Kelby, the author, of cheating the system, because I believed authors chose their categories. I shouldn’t have jumped to that conclusion—this is entirely Amazon’s fault. 

DrProject, del.icio.us, and others

  1. Do not break my browser’s password-save feature. Please. In DrProject’s case, the login form is in a JavaScript popup, unlike every other website that has a dedicated login page. Firefox is clever enough to offer to remember the password, but alas Safari is not.

    Del.icio.us just deliberately breaks password saving on its sign in page by specifying autocomplete=off in its form.

    I hate it when coders put effort into features that degrade the experience. You actually have to try hard and spend time to break the browser’s password-save feature. It doesn’t help anyone.

WordPress

  1. WordPress recently redesigned their interface. Presumably they tested it and found some advantages. Yet they have ignored the #1 rule of human-computer interaction: Responsiveness is king. The new interface is noticeably slower than the old one. The old one was already slow.

    Responsiveness lets users make mistakes without consequences and therefore without fear. Responsiveness allows experimentation, which gives a UI discoverability. Responsiveness compensates for many other design errors. Responsiveness is the most important UI principle in the world. 
     

  2. If I don’t give a post a category, it is placed in the Uncategorized category. If I later give it a category, it remains in “Uncategorized” as well. This is wrong. Posts should only be in Uncategorized if they’re uncategorized.
  3. Switching between the Visual and HTML views of the blog post editor loses whitespace information. Whitespace operations should be preserved between the two views of the same post.
Advertisements

PyVCAL

January 30, 2009

We wanted the name PyVCS for our project. It turned out it was already claimed on Google Code for a version control system written in Python. In a hurry, we picked up the PySync project on Google Code and tied ourselves to it with mailing lists and permissions.

It turns out that PySync is the name of an existing Python project that actually has something to do with syncing, unlike our project. PySync is also taken on PyPI, the Python Package Index.

So, after a quick discussion with Veronica and James, I reserved PyVCAL on PyPI, for Python Version Control Abstraction Layer, which has the advantage of describing what we want to build.

§

If all goes well, by the end of today, we’ll have broken ground with some prototype git code from James and some throwaway code from Veronica and I. Why prototype throwaway code? Two reasons come to mind: First, we want to have a bit of “just do it” spirit. We’re nearing the end of January, after all. Second, we want to familiarize ourselves with the Google Code code review tool and also a Subversion branch-and-merge workflow. I think of this as an investment that will pay off quickly.

Hack Session 1

January 29, 2009

Andrew Trusty and I spent three hours this afternoon in a hack session. Reynold Xin was here for a bit but left because his laptop was unusable.

We built our first Google App Engine application: Idea Hat. It’s a little rough around the edges—we have ambitious goals for it—but it works and it runs at http://idea-hat.appspot.com. http://idea-hat.appspot.com/ideas/random.

Available on my GitHub or Andrew’s.

Now we’re hungry. Next week we finish this thing like Paris Hilton’s career.

Tabs In Computer Programs Must Die

January 29, 2009

I am ashamed to admit: This cost me more than an hour.

A tab that broke a program

After much effort at systematically debugging a mysterious problem, I isolated the troublesome code, yet nothing seemed wrong. Eventually I superstitiously decided to type it in again, verbatim. It started working. Now you can see the problem. 

This code is Arc. I often run it by copying-and-pasting bits and pieces into an Arc REPL in Terminal. Terminal removes all pasted tab characters. Thus the code Arc sees is (make-from-real-imaga b), at which point it complains of an undeclared identifier. Searching for that same identifier is fruitless in the text editor.

Gerald Weinberg On Programming Language Design

January 28, 2009

“When we assess a programming language, or a machine, from a psychological point of view, we cannot grant ourselves the luxury of putting all the burden of poor programming on the poor programmer. If the same programmers get consistently better results using language A than using language B, what good are arguments that they would have done better in language B, if only they had been smart enough to master it.”

Google Liskov

January 17, 2009

In the process of writing “Slippery Types” I searched Google for “Liskov”. I liked the result.

 

I'm flattered.

I'm flattered.

Slippery Types

January 16, 2009

Sometimes, you want to create new types with a constructor-like interface. Sometimes, inheritance doesn’t capture what you really want to do. In these cases, typical object-oriented programming languages get in your way.

A first example.

Let’s say you want to model an HTTP response object. Forgive my rusty Java. I would argue that the following represents the most natural way of expressing the object.

class HTTPResponse {
    int responseCode;
    Map<String, String> headers;
    String entityBody;
    ...
}

 

 

Now, you realize that an HTTP 201 (“Created”) response always has a Location header. You want to provide some programmatic support for this. There are many ways to model this, but let’s walk through the most intuitive thought process.

A Created response is a HTTP Response. This encourages us to use inheritance.

class HTTPCreatedResponse extends HTTPResponse {
...
}

 

 

All HTTPCreatedResponses have a responseCode of 201. This is a property of the HTTPCreatedResponse *class*.

class HTTPCreatedResponse extends HTTPResponse {
	protected static final int responseCode = 201;
}

 

 

But, but, but. responseCode is an instance variable of HTTPResponse. We don’t want to specify it in two places. Our intuitions have led us into a corner.

Note that I am not saying “YOU CANNOT MODEL THIS IN JAVA.” Instead I make the gentler claim that one cannot model this pattern intuitively.

The problem of slippery subtypes is common. Sometimes it manifests itself as a desire for polymorphic class variables:

class HTTPResponse {
	static int responseCode;
	int getResponseCode() { return responseCode; }
	int setResponseCode(responseCode) { this.responseCode = responseCode; }
	...
	public HTTPResponse(responseCode, ...) { ... }
}

class HTTPOKResponse extends HTTPResponse {
	static final int responseCode = 200;
	...
}

class HTTPCreatedResponse extendsHTTPResponse {
	static final int responseCode = 201;
	String location;
	public HTTPCreatedResponse(location, ...) { this.location = location; ... }
}

...

HTTPOKResponse(...).getResponseCode() /* 200 */
HTTPCreatedResponse(...).getResponseCode() /* 201 */

 

 

Consider modeling symbols in a parser. It is common to see code like:


STATEMENT_TERMINATOR = new Symbol(";");
BLOCK_OPEN = new Symbol("{");
BLOCK_CLOSE = new Symbol("}");

Having done this, we might wish to later instantiate these symbols when we encounter them, as if new STATEMENT_TERMINATOR(line, column) were possible. But it is not. It’s not quite inheritance. We don’t want actually care too much about subtype substitutability. A functional programmer might think of this as a desire to curry types, in a way. A programmer in a prototype-inheritance language would just chuckle condescendingly and be on her way.

Python Version Control Abstraction Layer

January 16, 2009

We have a Google Code project set up under the name “pysync.” It’s a start!

JavaScript Negative Array Indexes

January 15, 2009

Is nothing sacred?

~ aran$ js
Rhino 1.7 release 1 2008 03 06
js> var x = [1,2,3]
js> x[3] = 4
4
js> x
1,2,3,4
js> x[-1] = "what?"
what?
js> x
1,2,3,4
js> x.length
4
js> for(var i in x) {
> print("x[" + i + "] = " + x[i]);
> }
x[0] = 1
x[1] = 2
x[2] = 3
x[3] = 4
x[-1] = what?

Reading Groups Are Hard

January 8, 2009

In September we were all eager and hopeful little students. They stood up and told us how important we were to the department. They told us how much fun we would have, and how much they looked forward to our insightful contributions to human knowledge. They advised us, “Get Involved! Join the student society! Start reading groups with your new peers! Network!” 

Well, I listened. I started three reading groups, in fact. These groups are no longer active.

They fibbed. It was a happy and comforting piece of advice, meant to make us feel good about our new intellectual environment without any expectation that we would follow it. 

It’s hard to find a meeting time for a group that allows all the keen to participate. It’s hard to motivate people to keep up with readings without any external incentive. It’s hard to balance a regular hunk of reading with shifting priorities and irregular deadlines. It’s hard to stay one step ahead, choosing insightful readings when you know no more about a topic than anyone else.

Ignore Their banalities. There is little correlation between involvement in a graduate student society and success. Reading groups are hard and rare. Without a proper context and culture, energetic networking remains awkward even in an intellectual environment like ours. 

Paul Buchheit claims, “Limited Life Experiences + Overgeneralization = Advice.” The advice we were given follows a different and also common equation: “Idealized View of the World + Lack of Thought = Advice.”

In this case, the idealized view of grad school involves lots of stimulating conversation with a variety of brilliant intellects. The reality is that most of our time is spent on independent learning. This isn’t a value judgement—I’m personally happier than ever. I just want to point out the discrepancy.

Don’t Put Reset Buttons in Your API

January 7, 2009

A corollary to Don’t Put Reset Buttons on Forms

Reset buttons save time in a tiny minority of cases. Actually, I can’t think of any good uses for reset buttons, but I’m sure they’re out there. I’m sure there’s some person out there who looks good in white pants, but I’ve never seen one. Maybe in Australia. Yet people who really ought to know better persist in wearing white pants and people who really ought to know better still put reset buttons on forms.

API designers, take heed. Insofar as an API makes some end-product designs easy and other designs hard, it should make good designs easy and bad designs hard.

The “API” of HTML makes reset buttons as easy as Submit buttons. Reset buttons are usually bad design. Trouble lurks.

The Wandering Programmer wants to make a volunteer application form for his super-awesome conference in Vancouver. He comes across an HTML forms tutorial and sees code for a reset button. It’s easy. The Wandering Programmer puts a reset button in his form. Why not?

On the eve of the application deadline, The Dawdling Student painstakingly fills out a well-crafted application, full of witty turns of phrase and intriguing commentary on the scintillating world of academic conferences. The seconds hum along to the deadline, but the Student broods over each word before finally! It is time for submission. By now it is near midnight and the Student’s hourly double-espresso is beginning to wear off and in a twitch the RESET button is struck, just millimeters away from the goal, and all is lost.

A long time ago, many programmers worked late nights to bring their boring crufty Desktop Applications to the Web. Most of the Web copies were worse than the Desktop versions, just as you might expect. But some of the Applications were easier to use!

In the world of Desktop Applications, platform makers like Microsoft and Apple created wonderfully rich, powerful and complicated widgets programmers could use in their software. They made it easy. And Programmers used them, often when they shouldn’t. Then, the Horde of Hapless Users came along and were confused.

When the move to the web happened, the Programmers found it difficult to copy their complicated widgets. They were forced to express their programs in simple controls. When the Horde of Hapless Users came to the Web applications, they were not confused any more. The simple Web programs were better than the complicated ones they replaced.

Programmers will go with the grain of an API. The API of desktop application makers make it as easy to use complicated widgets as it is to use simple widgets, so programmers sometimes use complicated widgets when a simple one would be better. The grain of HTML makes it easy to stick a Reset button on your form.

An API designer should always think about the grain of the API.

Don’t Put Reset Buttons on Forms

January 7, 2009

The student volunteer application form for ICSE 2009 contains seventeen form fields. At the bottom, you find this:

reset-button

Why would anyone want to clear out seventeen fields worth of information?

There’s no reason. 

But someone might miss “Send” and click “Reset” instead.

It just so happens that HTML makes it easy to put in Reset buttons. Lots of people do, just because. It’s a bad reason. Just because you can, doesn’t mean you should.

As it turns out, Jakob Nielsen, user interface expert extraordinaire, agrees.

Holiday Reading 2008

January 5, 2009

The Definitive Guide to Django, Adrian Holovaty and Jacob Kaplan-Moss

Available free online!

I wanted to learn Django, a Python web development framework. This book was the direct introduction I needed.

The online documentation for Django is a necessary supplement. Thanks to Agile Web Development With Rails, I have high expectations of a book introducing a web framework, and The Definitive Guide had holes. The book doesn’t say anything about testing Django sites, for example.

Outliers, Malcolm Gladwell

Malcolm Gladwell has knack for telling me things I already know and making me enjoy it. Outliers covers the role of practice and circumstance in the creation of extraordinary achievers. The 10,000-hour rule and other topics are old news to a former cognitive science student like me but the stories made an enjoyable read. My political side is intrigued by Gladwell’s emphasis of the real-world consequences of cultural values. It’s a tightrope topic to talk about because culture correlates with race but he does a great job of staying politically correct while making his point.

JavaScript: The Good Parts, Douglas Crockford

A concise introduction to JavaScript.

Crockford develops a library of useful JavaScript tools and presents arguments against the use of many language features.

The best summary I can come up with is “Use JSLint.”

Pro JavaScript Techniques, John Resig

Resig is a young (low twenties) JavaScript expert who has earned gobs of credibility thanks to jQuery. I can’t touch his JavaScript hackery but his book doesn’t live up to its title. The topics choices feel haphazard. There is some coverage of JavaScript events, a bit about CSS, some extended examples, and an appendix with a JavaScript reference. 

He builds up a library that is similar to jQuery. Frustratingly it isn’t, so I still needed to go learn jQuery separately. Some of the extended examples contained errors. To top it off, the book is badly edited: 

“The result is rather interesting and, albeit, quite complex.”

Glory.

The book is saved by its excellent selection of external links. Resig is plugged in to the JavaScript world, so there were great reading recommendations throughout the book.

Profrank

To learn Python, JavaScript, Django and jQuery by doing, I built Profrank, an idea I had early last semester. Next step: Demos and iterations. 

Not Quite Done Yet…