Principle Of Least Astonishment

The Principle of Least Astonishment states that the result of performing some operation should be obvious, consistent, and predictable, based upon the name of the operation and other clues.

For example, the name of a function should reflect what it does. Otherwise, a user of the function will be unpleasantly surprised:

Bad:

 int multiply(int a, int b)
 {
   return a + b;
 }
Better:
 int multiply(int a, int b)
 {
   return a * b;
 }
Or:
 int add(int a, int b)
 {
   return a + b;
 }
Also bad:
  int write_to_file(const char* filename, const char* text)
  {
    printf("%s\n", text);   /* Note that 'filename' is unused */
  }

In addition to function naming, the principle applies to user interface design. Menu items and other controls should have an effect that is obvious based upon their text labels and placement relative to other controls.


This principle seems highly dependent upon the culture of a language, domain, and product. I suspect it rather strongly subject to psychology, fad, idioms, etc. That doesn't (by itself) make it a bad principle, but it does make it a difficult principle to apply in any meaningful long-term sense, especially in such long-lived entities as language design and language standard libraries. Things that astonish programmers today might not astonish them in a decade... and vice versa. In thirty years, perhaps they'll be teaching rings in high school math courses, and it won't be at all to think of add as a 'multiply' for a particular topology in a ring of numbers.

I would suggest there are much better principles for user interface design than attempting to minimize astonishment. I don't mean that you should maximize astonishment, just that one could rank it much lower than most other features. Having a system that is 'transparent' in the sense used by EricRaymond in TheArtOfUnixProgramming (chapter 6) is probably more relevant: Software systems are transparent when they don't have murky corners or hidden depths. Transparency is a passive quality. A program is transparent when it is possible to form a simple mental model of its behavior that is actually predictive for all or most cases, because you can see through the machinery to what is actually going on.


The examples above are a little weak, as they are about a very simple function which has one obviously right behaviour and one obviously wrong behaviour. Perhaps an example of the GUI case that was mentioned would be more useful.

I'll keep an eye out for surprises and jot them down here when i find them. -- TomAnderson

All of the major Smalltalk language bugs are violations of the principle of least astonishment. Smalltalk spends a lot of time building up expectations in users that the system will behave in a certain way. The major language bugs are where it violates its own expectations.

For example,

there's a couple more like that.

Now meditate on the fact that Smalltalk's violations of the principle of least astonishment are actually enumerable.


Joel Spolsky has written a text about user interface design in which he refers to this principle.

http://www.joelonsoftware.com/uibook/chapters/fog0000000057.html

-- JanPersson


An example of a function that does not follow this principle is the standard C++ remove() function template. When applied to a collection, someone who has not studied the documentation might expect it to "remove" (that is, delete) things from the collection. But it doesn't--remove() (and remove_if()) instead reorder elements so that the "unremoved" elements are at the head of the collection, and the size of the collection does not change. It makes sense if you read the docs, but it can be astonishing to those who haven't.

C++ is astonishing in that Stroustrup wrote a book (TheDesignAndEvolutionOfCpp) full of examples where PrincipleOfLeastAstonishment is violated, yet after reading it they mysteriously make sense...


Violating the PrincipleOfLeastAstonishment leads to odd questions. A "real world" example of such questions is W. C. Fields, "Who put pineapple juice in my pineapple juice?"


Real example, from real code:

 xor ax, ax    # put 1 in ax

This puts 0 in ax, not 1; the code is correct but the comment is wrong. I was fortunate enough to be privy to the etymology of this snippet. ax held a command code: 0 did one thing, 1 did another. The line originally read "mov ax, 1" but later it was decided to use the other command code. It was changed to "mov ax, 0", and in a criminal bit of neglecting documentation, the comment was left. Later, an Old School Hacker saw the "mov ax, 0" and changed it to "xor ax, ax", because old 8086 machines could do it in 1 clock but the mov took 2 clocks. Never mind that it violates the RulesOfOptimization (since the days of the 386 "mov register, immediate" took 1 clock), that comment is terrible (we tend to believe documentation no matter what). Since the comment tells you what the code is doing and not what it's supposed to be doing or why, I decided the correct action was to remove the comment entirely. -- DavidBrady

Note that using xor to zero a register is still an optimization: the instruction itself takes up less space. (for Intel CPUs)


EditText of this page (last edited November 26, 2014) or FindPage with title or text search