Better Software — No Matter What: The Most Important Design Guideline
CC Attribution - NonCommercial - ShareAlike 3.0 Unported:
You are free to use, adapt and copy, distribute and transmit the work or content in adapted or unchanged form for any legal and non-commercial purpose as long as the work is attributed to the author in the manner specified by the author or licensor and the work or content is shared also in adapted form only under the conditions of this
Meyers, Scott
At last year’s NDC, Scott Meyers devoted an entire day to guidelines for improving the quality of software, regardless of the application, the language in which it's written, the platform on which it runs, or the users it is intended to serve. This year, by popular demand, Scott isolates the single most important guideline from last year’s talk and focuses on it in this session. The guideline is Make interfaces easy to use correctly and hard to use incorrectly. Scott explains how this applies to both user interfaces and APIs, and, with specific advice and countless examples, shows how to employ it to improve the quality of the many interfaces in your software.
 All right, well, welcome to the last session of the day. At least the last session of the day for me. I'm amazed that there's this many people at the end of the day. So if you just stumbled in here thinking, well, maybe this is a good place to rest, I'll try not to wake you. My name is Scott Myers, and I want to talk about what I consider to be the single most important design guideline in working in software development. And I'll get right to it. Single most important design guideline, in my opinion, is to make interfaces easy to use correctly and hard to use incorrectly. Now, the reason I think it's the single most important design guideline is because this is not a user interface guideline. This is not an API guideline. This is both. It applies both to people implementing user interfaces, and it also applies to people who are implementing things that are being used by programmers, because there are a lot of interfaces in software. In fact, interface design in one form or another is one of the most common activities that we have as software developers. Now, often when people talk about interfaces, they're thinking about user interfaces. Could be a graphical user interface. Could be a gesture-based user interface. Could be a textual-based user interface. Those are all interfaces. But it also could be the kinds of interfaces that are used by software developers. So we have library interfaces. We have class interfaces. We have function interfaces. We have module interfaces. We have generic interfaces. We have template interfaces. There are lots and lots of interfaces. So a very common activity by software developers either is designing and implementing interfaces in one form or another, either for end users or for other developers or for both, or is consuming those interfaces, either as end users or as developers, people using APIs and things like that. It is because interfaces are, by its very nature of the word, they are literally the way that we interact with part of a system. A well-designed interface can make things go really smoothly, can make it very satisfying, can make it a very pleasant experience, either as an end user or a programmer. And a poorly designed interface, either at the application level or at the user level, can make things really a very miserable existence. Because it is so central to both using software and to developing software, this is why I think it is the single most important guideline that I know of. So I start as a point of departure with some assumptions. So the assumptions that I make are, first off, the people who are using software, either developers or end users, the first thing is they've used some software before. I think that's a reasonable assumption. They've interacted with some kind of a system before. So they have some idea what should be going on. The second thing is I believe that they are willing to read at least some documentation, not necessarily a lot of documentation. But they are willing to at least try to follow the rules. And most importantly, I believe that people who interact with interfaces, either as users or as developers, they want to succeed. They want things to work correctly. I do not know many software developers or many users who say, you know, I'm going to work today and I'm going to do a really bad job. That's my goal for today is to fail as many times as possible. I just don't think that's very common. So if these things are true, if people have some experience with software, if they're willing to read some documentation to figure out what the rules are, if they want to succeed, you can't ask them to bring anything more to the table. They're already pulling up their end of the bargain, which means if, for some reason, despite all these things, they use some software, they use an interface, and they fail. They do not do what they want to do. It's not their fault. It's your fault. Or in particular, it is the developer of the interfaces fault for having designed an interface that an experienced person willing to read some documentation who wants to succeed failed to succeed at. That's the sign of a bad interface. So as a result, software should be easy to use correctly and it should be hard to use incorrectly. So if it is possible to perform an action, and by perform an action, I could mean do a gesture on some kind of a handheld device, or do something with a mouse or a keyboard, or type in some kind of commands, or call a function interface, or instantiate a class or a template. These are all acts of interacting with an interface. If it is possible to do something through the interface, it should almost always do what the person who's doing it wants it to. And if somebody could try to do something which would not yield the desired behavior, then that action should typically not even be possible. You want to have an interface that fulfills what Rico Mariani has called the pit of success. The pit of success is if you are doing something and you trip and you fall, you accidentally land doing something that you wanted to do. So if you accidentally succeed with an interface somehow, it means that it just does the right thing. Because the things that we're not going to do the right thing aren't possible, and the things that are possible almost always do the right thing. That is the goal. What I want to do for the remainder of this presentation is try to give you more specific ideas on how you can implement easy to use correctly and hard to use incorrectly. I mean, it's one thing to say, well, this is what you should do, but the question is, how do you do it? What are the specific practices that you can adopt that will help make interfaces have this particular characteristic? And the first thing I want to talk about is adhering to what I call the principle of least astonishment. Everybody who comes to an interface, they have some expectations. They have some background. They have some experience, which means that they have expectations about how that interface is going to work. So your job as an interface designer is to maximize the likelihood that their expectations are correct. In many cases, they're going to guess at how to use the interface. Your job is to maximize the likelihood that the guesses are going to be correct. And I want to emphasize again, this is not a user interface guideline. This is not an API guideline. This is for both kinds of interfaces. So this should be true across the board. So if users know what they want to do, then they should be able to figure out how to do it. Now, this doesn't mean there's no innovation in interfaces. So if you come up with some clever new way to let people accomplish a particular task that's better than previous ways of doing it, that's fine. Even if people don't know how to use it initially, once they've learned how to use it, they should go, oh, now I understand. And their expectations from that point forward should now be something which is going to make it easy to use correctly and hard to use incorrectly. So this does not mean you have to stick with old ideas for interfaces. But it does mean that once you've gotten across the basic ideas, people should be able to figure out how things work. Now, over the years, I have collected a large number of examples of either interfaces that work or more frequently interfaces that do not work. I'm going to be showing a lot of examples. Some of them will be user interfaces. Some of them are going to be APIs. Some of them are going to be relatively old. Some of them are going to be relatively new. So in this case here, I just want to talk about some basic ideas of avoiding astonishment. So as an example, a lot of people don't even think about it anymore. And now that we're at Windows 8, maybe it doesn't even work this way. But for many, many years, if you wanted to shut down your Windows computer, you would click on Start. Now, I have actually read the blog entry where they described how they did a lot of user testing and how they finally came up with that clicking on Start was the right way to shut down the machine. This is stupid. Clicking on Start is not the right day to shut down the machine. And I've had to field more than my share of questions from people like my parents saying, so how do I shut down the machine? I'd say, you click on Start. And there's dead silence at the other end of the phone. No one wants to click on Start to stop something. I'm sorry, this does not make sense. Now, as I said, I read the blog entry describing how they came up with this. And what it boils down to was we tried a whole bunch of different approaches, and this one sucked the least. Guess what? Sucks least doesn't mean that is the best way to do things. So many, many years ago, and excuse me, I'm not a Mac user right now, but when I was using Macs from time to time, if you wanted to do things like get a DVD out of the drive or get a CD out of the drive, what you would do is you would drag it to the trash. Who thought this was a good idea? Who wanted to equate, destroy this forever with ejecting it? Now, when I learned about this, which was a number of years ago, quite a number of years ago, I was in graduate school, you don't always trust your colleagues in graduate school. They don't always have your best interests at heart. So at one point, I said, OK, how do I get this out of the machine? And somebody said, you drag it to the trash. And I said, you are lying to me. It cannot possibly be true. Windows XP, which is going back a while, but there will be newer examples, I promise. Windows XP had the option that you could choose your font size. Now, there were two selections by the operating system for the font size in Windows XP. Two selections, they ship with Windows XP. There was normal and large fonts. Those were your choices. And what I discovered one time, having tried to use large fonts, is large fonts breaks everything. Large fonts simply does not work. So I've got a couple of screenshots here. So you can see that, for example, in Excel, you'll notice that the baselines don't line up here. Notice that the name of the band here, this is Sponge, but the P in the GR, the descenders have been cut off and the CDs cut off on the back here. Basically, nothing displays correctly with large fonts. Call me naive. I was astonished that using one of two choices for the operating system font size made everything display incorrectly. Now, maybe I'm a little bit too picky, but it seems to me that you shouldn't get 50% of the choices wrong. I mean, there's two choices. And what I found from talking to Windows developers was it was widespread acknowledgement that it just did not work. I want to point out now that I'm going to be giving lots of different examples. Every single example that I'm going to be giving you is the result of somebody who said, let's ship this software, this is ready to go. I mean, it's easy to pick on things that people put together, they throw together in their backyard. But for example, regardless of what you think of Microsoft and Windows, it is a professional software product that a lot of people put spent money on. Somebody said, ship that baby, it's ready to go. Everything I'm going to be showing you here is the result of somebody having saying, I now believe this is a professional software product that has the appropriate level of quality and which will satisfy our users. On this slide, we've only seen user interfaces. It's going to get to APIs, I promise. This is not the kind of problem that is limited to just user interfaces. So now let's deal more with a developer level kind of thing. So this happens to be an example from QT 4.8. It's a Windows GUI kit that can be installed. So and what it says is the install path must not contain any spaces. Really? On an operating system that by default has program files and my documents, the installation path can't have any spaces. This is an example of people who develop some software on Unix where spaces are legal but almost never used. And then they said, now we'll port it over to Windows and we will bring our collective Unix baggage with us and we will then impose it on all our users. Now it goes the other direction as well. For example, it is not uncommon for people to take Windows software which is not case sensitive and then port it over to Unix and suddenly guess what? Everything starts breaking because it is case sensitive. When you move from one environment to another environment, the expectations that people have are going to change, which means what it means to make things easy to use correctly and hard to use incorrectly are going to change as well. You can't simply take your conception of what's a good idea and move it someplace else and expect that community of people to adapt to your way of doing things. You have to adapt to their way of doing things. Someone sent me this and it's so wonderful that I don't think anybody is ever going to beat this for the worst possible user interface design. Now this happens to be a calendar program. Oh, it's worse than you think. So this happens to be a calendar program. So if you have a recurring meeting on your calendar, like every Monday we have a meeting. And then let's suppose on some Monday you don't want to have the meeting. Maybe you're going to be on vacation. Maybe it's a holiday. Maybe the meeting got canceled for some other reason. So what you say is great. I want to delete the meeting. Now when you say that you want to delete the meeting, there's actually some inherent ambiguity here because you could be saying, I want to delete the meeting forever. We don't ever need to have it again. It's moved to Tuesdays. Or you could be saying, no, this one particular Monday is the day that it needs to go away. So all right, there needs to be some way to disambiguate between the two. So as you can see here, it says delete this single item. No to delete all. Now without even going any further, I have no idea what that means. So that's no to delete all, followed by um, abtzebrach, and tipensie, alf, x. And then two choices, ja and nine. You know, I didn't know what it meant in English. And putting it in German is not improving matters any. But I want to point out, professional software. Somebody shipped this, they thought this would be a great way to satisfy their customers. I'd call that fairly astonishing. So there are some things you can do to avoid astonishing people. One of the things is you want to avoid gratuitous incompatibilities with the surrounding environment. People are working in some environment, some kind of a social environment, some kind of a computational environment, some kind of a commute environment. They have expectations, they have normal standard practices. Your goal is to seamlessly work with those things that people are already used to doing. Basically, you want to take advantage of what people already know. That makes it easier for them to use your software. Again, whether they're end users or whether they're API users, as long as people's habits and expectations correspond to what should be done, you will have a higher rate of success with people doing things correctly. Now, the natural syntax for doing these things can vary depending on the environment. So for example, if I want to find out whether two objects in a programming language have the same value, it's a reasonable thing to want it, is this thing have the same value as this thing? But the way that you say that depends on the programming environment that you're dealing with. So for example, in C++, use operator equal equal, that's what is used in that programming language. Now, in Java, use equals with a lower case e. And in C sharp, use both equals with an upper case e and operator equal equal. So the way that you accomplish the same thing depends on the particular community that you are targeting. So this is why you need to adapt what you are doing to the community of people who are going to be using it. You also want to offer intuitive semantics. What I normally tell people is, if there's not a good reason to diverge from what people are used to, then you want to do what people are used to. So in C++ or other languages, when in doubt, do is the ints do. Everybody knows how an int behaves. So if you don't have a good reason for your type to not behave like an int, make it behave like an int. People know what that means. In GUIs, if you have mouse clicks or you have gestures, make those things mean whatever they normally mean in other programs that people use. Don't come up with your own special way of doing things unless there's a particular advantage associated with doing that. Again, I don't want to rule out interface innovation. That's clearly something we need to be able to experiment with. But in some cases, people just change things because they can change things and there's no obvious advantage. And that to me is a good way to astonish people. Anybody who is a software developer, anybody who is a programmer, at some point early in their career, early in their education, they were told, you need to choose good names. Yet they choose really good names. It's the most important thing, choose really good names. And every single person who has been given this advice has learned that all the good names were taken in the 1960s. There are no good names left. And yet, that's no excuse because names are, especially for APIs, they literally are the interface. The very first thing people see when they're dealing with an API are things like class names, module names, function names. The minute they see a word, they are going to go, oh, and an idea is going to spring to mind. And if the idea that springs to mind is not the right idea, you are going to be fighting them every step of the way because they have the wrong conception of what is going on. So it actually is really important to choose good names. And it's very hard. One of the reasons it's hard is because all the good names were taken in the 60s. But the second thing is there are so many things that have to be named. I mean, choosing one good name is hard. But we have to do things like choose names for libraries, modules, namespaces, generics. I'm not going to read the whole slide to you, but that's a lot of things that need names. Every one of them is supposed to be a good name. If all you did was pick names all day long, you'd go crazy. And yet, the fact that it's hard doesn't change. It's the fact that that is literally the interface for any kind of text-based system. The commands that people type on Unix, which is not setting any records in terms of beauty, the kinds of things people type in APIs, library names, commands to programs, the names are the interface for those kinds of interfaces. And to say things like, well, people will get used to it. Yeah, they will get used to it. But they'll make a lot of mistakes along the way. So it really is important to choose good names. I know it's hard. Doesn't mean it's not something we should all be aspiring to all the time. So here's a couple of counter examples. So this one happens to be from Adobe Acrobat 9, but it's actually standard for the Windows platform. So basically, let's suppose I create a document, I do some edits to it, and then I want to close the program without saving it. So now I have a document that's about to be destroyed without being saved. So the program thinks, all right, we should probably warn you about this. So what it says is, do you want to save the changes to the document? Yes, I know what that means. No, I know what that means. Cancel, I never have any idea what that means. I have to always think and go, what's the difference between no and cancel again? And I go, all right, cancel means I actually want to cancel the request to close the program. So that doesn't help me too much. But that's OK. We have interface innovation. So open office, I downloaded the most recent version of that. Open office, not constrained to do things like everybody else does. If you do the same thing in open office, it asks you the same question. So do you want to save the dot? Do you want to, what does it say? Do you want to save your changes? Well, it doesn't have yes, no, and cancel. That's too complicated. It has save. Well, I actually knew what yes meant, so that doesn't help me too much. And then it has discard. Well, OK, but I knew what no meant. And then we have cancel. That's what I had trouble with in the first place. So it's different, but I don't happen to think it's any better. Now, there is this notion in the interface community of what is known as the Gulf of Execution. The Gulf of Execution is the distance between conceptually what I wish to be able to do and the means I have to take in order to get it done. The distance between what I want to express and the way that I go about expressing that. And so anytime the Gulf of Execution is large, it increases the likelihood that somebody's going to do the wrong kind of thing. So for example, somebody might click on either discard or no when they should have clicked on cancel, because they really didn't want to lose the document. It is interesting from time to time to think about how we could avoid the problem. As an example, one could imagine that rather than even presenting this dialogue in the first place, if you try to exit a program and you hadn't saved the document, automatically it would just be saved behind the scenes. You wouldn't have been asked, it would just be there. And then we'd have to have some kind of interface that would let people go, oh, right, I wanted that document. Oh, you saved it for me? That's so nice. Why don't you give it to me? Other interface questions come up, but the point is that there are other ways to approach the problem. For example, rather than saying, I'm about to throw your document away, how about don't throw the document away? And then as I said, there has to be some other kind of interface which would let us get back at those kind of old documents. But by trying to reduce the gulf of execution between, oh, I just want to get out of the program and I'm about to throw a bunch of work away, by adopting a different approach, we can possibly make that tension be lessened. The other thing I would ask about this particular kind of thing, and this is designed for a desktop environment, so this is not designed for a small screen, I'm trying to figure out why it is in 2014 where we have these giant monitors with huge numbers of pixels, we're still following the convention that we can't have more than one short word on the button. For example, instead of cancel, something like don't exit program, I bet that would fit, in which case a lot of the confusion about what it means would go away as well. So this is an example of an interface in my mind that was designed in the late 1990s and has not been updated since then. So we've seen too many GUI examples, let's talk a little bit about API examples, and this has to do again with choosing good names. Now, in the C++ standard library, there are two different ways to determine if objects are the same. One of them is called equality, one of them is called equivalence, doesn't even matter what the difference is. But the point is, there's two ways to say, is this object equal to this object? There's two ways to say that. One of them is to use equality and one of them is to use equivalence. So it turns out that they have a function called equal range. Takes a bunch of objects in a range and says, I want you to bunch all of them together, whose values are equivalent. So the name of the function is equal range, but it doesn't use equality. It uses equivalence and it does make a difference sometimes. And people do get misled into thinking, oh, now I have all the values that are equal to something else, but actually they don't. They have the values that are equivalent to something else, not always the same. So the question really is, why did they call it equal range and not equivalent range, since it's not using equality? Another thing you can do to avoid astonishing people, one of the most important things is, you can embrace consistency. You can have consistency in the wording that you use, in the way that you lay things out, in the way you report errors, things like that. So this is an example that was sent to me a while ago. This happens to be from an ATM. And what you will notice in this ATM is that there's two things you can deposit. You can do a cash deposit and you can do a check deposit. Notice that on the screen, the cash deposit's on the left and the check deposit's on the right. And now notice that underneath where you actually do the depositing, so the cash deposit is on the right and the check deposit is on the left. Or as I like to say, you know, they had a 50% chance of getting it right, which means they had a 100% chance of getting it wrong. But, I mean, this was only rolled out to probably tens of thousands of places around the world. So, really? I mean, is that so complicated to make sure that things are consistent in terms of their visual, their spatial layout? Also, in terms of consistency, in Java, if you would like to find out how many elements are in a container, there's three ways to do it. So, if you have an array, use the length property. If you have a string, use the length method. And if you have a list, use the size method. Three different ways to get the same kind of information. That's Java. So, Microsoft looked at Java and said, man, this is crazy. Three different ways to get the same information. What kind of loser company would have three ways to get the same information? So, when they invented.NET, they said, we will not have three ways to get the same information. We'll have two. So, if you want to know how many elements are in a container, you have the length property for arrays, and you have the count property for array list. You also have a count method on Ianuma. Pardon me? You also have a count method on Ianuma, so it's actually the same. I'm sorry, one more time? The count method also exists. On what? On Ianuma. Oh, count method or count property? Method. OK, all right. So, on Ianuma, then, so there actually are three different ways? Cool. I'll just make a little note here. You think I'm making it up? Ianumerable? Count method. OK, remember, professional released software products. These are people who are doing the best that they possibly can. But that now is withstanding. So, we have a situation now. Sometimes when I talk to people, they say, look, you know, especially in.NET, everybody's using Visual Studio, and it's got completion, so all you have to do is type the first letter of the method name or the property name. It'll tell you what it happens to be. So my first observation is, number one, L and C are not the same letter. So you actually have to find out what that's going to be. The other thing is this makes the assumption that you're always using an IDE. But these kinds of languages also have reflection-based code. With reflection-based code, you can actually be generating and processing code at runtime. And guess what? At runtime, there's no IDE. Instead, what you have to do is take a look at something and then query its interface to find out what kinds of things it supports. And guess what? That querying becomes a lot more complicated and error-prone if you have to check for two or three different possibilities. So the excuse of, well, we have an environment that makes these problems go away, bad news. It doesn't make the problems go away. It might reduce the severity in some cases, but it doesn't solve them completely. Again, on the topic of consistency, this is from the C standard library. So we have three different functions here. We've got F scan F, we have F get pause, and we have F seek. Notice that all three of them take a file pointer parameter as the first parameter. All right, so we notice a pattern here. When you're dealing with files, you will pass in a file pointer as the first parameter. All right, that's easy to remember. Oh, wait. It turns out there's also F get, F put C, and free open. It also takes a file pointer as the last parameter. I have talked to several extremely experienced C programmers, people who do this for a living. They've done it for decades. And they will all say they have to look it up every single time. I mean, they simply cannot memorize this stuff. And there's a lovely quote here that has been said, this is something which I think is important to keep in mind. This inconsistency has frustrated millions of developers for more than 30 years. And the reason I point this out is, if you are involved in the development of an interface that is so successful that it is used by millions of people for decades, wouldn't it be nice if one of the things that is remembered for is how easy it was to use and how you didn't have to look up the details every single time you wanted to use it? Now, most of us will never be sufficiently lucky to develop an interface that has that kind of widespread use. But shouldn't you aspire to something which can stand the test of time and which people are going to look back and say, you know, that was a really nice interface. That's supposed to look it up every single time I want to make a function call. It's kind of crazy. So this is a different kind of consistency. This is from the C++ standard library. And again, I'm trying to mix up API things and GUI things. There's a number of standard containers in the C++ standard library. So let's suppose you have a container. And what you want to do is you want to get rid of all the elements of the container that have a particular value. I want to get rid of all the 10s. Or I want to get of, I don't know, all the colors that are blue, whatever it happens to be. So if it's a set, you call erase. If it's a multi-set, you call erase. If it's a map, if it's a multi-map, you call erase. If it's an unordered set, unordered multi-set, unordered map, unordered multi-map, you call erase. I'm beginning to notice a trend here. If it's a list, you call remove. And if it's a forward list, you call remove. By the way, they do exactly the same operation. They're just named differently. And what's important to notice about these kinds of examples, the thing about consistency, usually things that are inconsistent, it's an utterly arbitrary decision. You cannot argue that these names had to be different for some compelling technical reason. They're just different because they probably were developed independently. And then when somebody noticed that they were inconsistent, they didn't bother to fix it. They didn't say, now, now, before we standardize this, let's make sure that they actually behave in a consistent fashion. So some problems have technical justifications. This is not one of them. I've talked about consistency in layout, spatially in a GUI, for example. I've talked about consistency in terms of calling forms. But there's a different kind of consistency I want to mention now because consistency is across the board. It should occur in many different domains. So again, this is from the C++ standard library. So there is a function sort. If you call sort on a collection of values, either it will sort it in n log n time or it will not compile. So for example, if you have a doubly linked list, which cannot be sorted using this algorithm in n log n time, and you try to sort the doubly linked list, it will not compile. So the philosophy there is if we can't do this efficiently, we won't even support it. Your program won't compile. That's the philosophy. Now, there is another function. It's called binary search. Binary search in the same standard library. It will run in log n time, which is what you'd expect from binary search if it can. And if it can't run in log n time, it will run in linear time. You can invoke binary search on a linked list. This is an inconsistency in philosophy because this philosophy says if there's any way to do this, we will do it, even if it's really slow. But what that means is that the library is a whole for your typical developer working in C++. It means that when they make a function call, they don't know if it's going to compile. And if it does compile, they don't know if it's going to be fast or slow in general. Because the people designing the library didn't have a consistent set of philosophies about what it would mean to have performance guarantees. So this is not a syntactic constraint. This is more of a philosophical conceptual inconsistency. And that kind of inconsistency is no better or worse than any other kind of inconsistency. Another thing from the C++ standard library, and some of you may not know, that I sort of live in the C++ world. So that's why some of the examples are coming from that. There is a function called sort. When you sort values, the sort technique can either be stable or unstable. It doesn't matter what the words mean. But the point is there's two ways to do it, stable or unstable. The sort algorithm is not guaranteed to be stable. But that's OK. If you need stability, there's another algorithm. Stable sort, which is guaranteed to be stable. Well, this makes sense so far. Sort, not guaranteed to be stable. Stable sort, guaranteed to be stable. However, there is also a special algorithm for sorting doubly linked lists. It is called sort, and it's guaranteed to be stable. So we've now talked about consistency. We've talked about avoiding surprising people. I want to now talk a little bit about progressive disclosure. Remember, the high level goal we're trying to achieve here is interfaces that are easy to use correctly and hard to use incorrectly. When you get to an interface of a particular level of complexity, and again, whether it's a user interface or an API, once there are a whole bunch of choices that people can make, a whole bunch of possible things they can do, the likelihood of them doing the wrong thing increases. If you're faced with a whole wall of buttons, the chances of hitting the wrong button go up. So what we'd like to do is find a way to reduce the likelihood that people are going to hit the wrong button. And one of the ways to do that is what is known as progressive disclosure. What progressive disclosure does is it says, listen, of all these choices that people have, of all the things that they could do, these are the ones they probably want to do, and these are the ones that they are much less likely to want to do. Now, we need to make all of them available all the time, but what we can do is make it easy to hit the buttons or use the levers that we want people to use, because it's likely to be what they want, and harder to use it some other ones. So what you can do is distinguish normal from expert or advanced level kinds of commands. So this is something that happens to be from the most recent version of Firefox, but you've got some choices here, but notice there's an advanced button, and when you click on the advanced button, it brings up a whole bunch more options. The idea here is that for most people when they're in, well, which section is this? Content, it looks like. When you're in the content section here, these are the things that you probably want to work with, but there are some other options for people who are more advanced, in which case they can click on the advanced button and then some more options pop up. The idea is to minimize the likelihood that somebody's just clicking on buttons and gets themselves all messed up by having the user interface designer distinguish between the elementary stuff and the more advanced stuff. I want to point out that progressive disclosure is not the same as categorizing things. So this is from a different program called super. This is a fairly complicated looking interface with all kinds of options, and they're separated in the colors and dissections, but the point is all the options are still there on one screen. There's nothing there which says this is probably what you want to do, and this is probably not what you want to do. So there's nothing wrong with categorization. Categorization serves a lot of really useful purposes, but just bear in mind categorization is not the same as progressive disclosure. Progressive disclosure is a way of hiding things from people initially because they are unlikely to want to use them. It's a way of making things harder to get at. And it's not something which is limited to user interface design. So if I have an object which has, let's say, 100 methods, number one, I've got a problem already, but I've have an object with 100 methods, and 20 of them are likely to be used a lot, and the other 80 are for very specialized cases, rather than having a single 100 method object, what I can do instead is break it into two objects where one object has the 20 methods that I probably want to use, and the other object actually holds the other 80 methods, so I have to ask for that sub-object in order to get access to those methods. Now, a number of years ago, Ken Arnold, actually almost 10 years ago, wrote an article called Programmers Are People Too, and it was based on the observation that a lot of work is put into user interface design to make it easier for people to use programs, but at the underlying programming level, people are often presented with these very large, complicated APIs that are easy to use incorrectly, and his observation was, why don't we do the same kind of thing with programmers that we do with regular end users? Let's also shield them for this kind of complexity. So the example he talked about was Java Swing's JButton class, which he says it offers over 100 methods, but he pointed out of those greater than 100 methods, about maybe 15 are the ones that most people dealing with buttons most of the time are likely to want to manipulate, and all the other buttons just get people in trouble and lead to a lot more debugging for their programs, so he proposed a better design, which essentially involved taking the JButton class, breaking it into smaller pieces, and the smaller pieces would then be used as sub-objects, so if you wanted to get access to some of these lesser used options, you actually would have to ask for a sub-object, which meant that it was less likely that casual users were going to get themselves into trouble. It's progressive disclosure, but it's at the API level. Another thing you can do to make interfaces easy to use correctly and hard to use incorrectly is simply to document them before you implement them. If you write up the documentation for interface, whether it's a user interface or whether it's an API, before you've actually implemented the interface, you are likely to find problems of the kind we've talked about so far. For example, if things are inconsistent, when you start writing about it, you begin to notice that they're inconsistent. If things are overly complicated to try to explain to people, then they probably need to be simplified. So if there are bad names, so if a name seems to say one thing but actually says something else, you have a chance to change the name. And this whole idea of writing documentation before you actually write the code is completely consistent, for example, with test-driven development, where you are writing the test cases before you're writing the code itself. But it turns out that the very low-tech approach of documenting an interface before you've implemented the interface has the nice side effect of making the interface better in most cases. Assuming you are working in a strongly typed programming language, something which actually does enforce typing, if that is a reasonable assumption, then it's important to understand that the type system is one of the most powerful tools that you have at your disposal. So by using the type system, you can prevent people from making certain kinds of likely mistakes. So let's suppose I have a date class, and here's a date class. It takes an integer month, an integer day, and an integer year. Now, one of the reasons I chose the date class is because the conventions for expressing dates, at least colloquially, in the United States are different from the way that they're expressed pretty much every place else in the world. So there is sort of the inherent possibility of people expressing a date incorrectly. But there's actually a more general observation I want to make. But the first thing is, so if we take the int month, the int day, and the int year, then if somebody doesn't pay close attention, they might say, well, I'm going to pass it in the day, and then the month in the year, or even the year, and the month in the day, which arguably is the most reasonable way to do things. But the interface can't tell the difference. From the interface point of view, they're all just integers. So it has no way of knowing that the wrong things are being passed in. And there is a more generalized observation here. Any time you have an API, which has two parameters next to one another with the same type, there is the inherent possibility that they can be flipped, and the type system won't be able to tell. So any function taking parameters of the same type that are adjacent to one another, you have just eliminated the possibility of the type system being able to tell you when people pass them in the wrong order. But let's talk about this idea of a date class here. So this date class here, this is an interface that is easy to use incorrectly. People could easily pass in things that they don't pass in the day, month, and year in the proper order. So well, OK, what we can do, assuming we have a strong type system, is we can create a type for day, a type for month, and a type for year. So now there are actually three different types. Well, now that I've got three different types, I can say, OK, here's my date class. You've got to pass in the month first, the day second, and the year third. So now if you do not pass them in the right order, the compiler through strong type checking can ensure that your code does not compile. This means we've just eliminated a whole class of errors. People can't pass these things in the wrong order. So that's a nice improvement. Now, it also means that the code is clearer. So if I say, all right, I want to have a date D with 4, 8, and 2005, somebody reading that code could easily misinterpret, OK, is that April 8th or is that August 4th? It's not quite clear from looking at it. When you spell out the types, it's quite clear exactly what's going on. So that's an improvement. So it's easier to read as well as being harder to make mistakes. I want to point out that the technique of introducing new types for strong type checking only works if you actually are introducing new types. So if you're working in languages with type aliases, where you can create another name for an existing type, c and c++ are the examples that come to mind, if I say, OK, day is a synonym for int, month is a synonym for int, and year is a synonym for int, and then I say, here's my date class, which takes a month, a day, and a year. This is a beautiful looking interface. The problem is, as far as the compiler is concerned, it's date of int, int, int. This is what I call programming to make you feel better about yourself. I mean, it looks beautiful, but the problem is you can now say I'm going to pass in a day, a month, and a year, which is the wrong order here, and the code continues to compile. So if you're going to use the type system, you actually have to use the type system, not the apparent type system. That doesn't do you any good. And if you want to know why my fixation is with April 8, 2005, that's the day we brought our puppy home. That's Darla. Now, Darla is adorable, needless to say. But since we're focusing on interfaces, it's important to recognize, even with what we've talked about so far, there are still ways to make mistakes with this kind of an interface. So what I could do is I could say, OK, I want to have the month m, but the month is minus 4. Now, why would you type minus 4 as a month? Nobody would type minus 4 as a month. However, let's suppose you're supposed to be calculating the month. And instead of saying something like a plus b, you accidentally said a minus b. People have been known to make those kinds of mistakes. So you might accidentally compute the month incorrectly. Now, in this particular case, last I checked, there are only 12 valid months. So if there's only 12 valid months, it doesn't make a lot of sense to me to represent them by probably an integer which could represent 4 billion possible values. When you have a constrained set of values, in many cases, you are better off designing an interface that constrains the values to only the ones that are known to be legitimate. So what we could do is we could say, all right, I've only got 12 month values that make any sense. So what I'm going to do is I'm going to create 12 month objects, give them the appropriate name, and make it so nobody can create any other month objects. So for example, I might say, here's my class month, and then I've got objects for January, February, all the way down through December. In this case here, I am making the constructor for months private, which means nobody can create any other month objects. So I've said, here are the 12 month objects that you're permitted to use, and you can't create anymore, which means that now it's essentially impossible to create invalid months. You've eliminated a whole class of errors. So if I try to say month M minus 4, this won't compile because this is trying to create a brand new month object, and we've made construction illegal for those kinds of things. But I could say, the month is month colon colon April, that'll work. So that's nice. That's an improvement. Well, the problem now is, OK, so I could say, all right, the day D is 71. Well, last I checked, there are not any months with 71 days in them. So it's interesting, though, to think about what we can do about dealing with that problem. I believe it is an extremely useful exercise when looking at any interface to always ask yourself, how could this interface innocently be misused? No one's going to type 71, but again, a formula might yield something which isn't valid. So the question is, how could we prevent these kinds of mistakes? Now, what we could do in this particular case is I could say, well, all right, if I know what year it is, and I know what month it is, I now know how many days there exist in that particular month. So one could imagine an API where you first you create a year object, you go to the year, you then have it give you month objects, and once you've got a month, it will then give you day objects, and then it would be impossible to specify the wrong day, or at least an invalid day. You can specify the wrong day, but you can't specify a day that does not exist. Once you've come up with a possible way to prevent people from making certain kinds of mistakes, then you can say, all right, what is the likelihood of making the mistake, and how serious will it be if somebody makes it? And how much work is it going to be for me to prevent people from making that mistake? Once you have those two pieces of information, you can start doing an engineering judgment for the trade-offs. You can say, all right, this is how likely it is, and this is what it's going to cost me if I do it, and this is how much work it is to prevent people from making that kind of mistake, is it worth it or is it not worth it? I can't tell you the answer to that question, but what I can tell you is that in my experience, most people don't do the analysis in the first place. They simply decide, all right, this is what we're going to implement for an API, and we're not going to worry about the kinds of mistakes that people can make. That's what I just said. Now, constraining values is not always the best way to go. So this happens to be, this is from a couple of years ago, Lonely Planet has changed its website, which will become relevant in a moment. But so this says, all right, so I've specified, as I recall here, so the month has been specified to be June, but notice I can choose June 31st. So this is an example of an interface that makes the interface designer feel like they're really doing a great thing, they're constraining the values. The problem is they're not making it impossible to choose illegal values. So this is an example of an interface that looks like it's constraining values for a reasonable case, but it actually doesn't solve the problem. What would be a better way to solve this problem? Pardon me? Have someone have a calendar widget so you'd only be able to click on the appropriate things in the first place. So this problem can literally be designed out of existence. What struck me when I did this a couple of years ago, so I went to Lonely Planet where if you want to fly, then you go to their flight logger. Now, with the flight, you actually do have a calendar that you choose. And in fact, there's no drop downs. On the other hand, if you wanted to do a hotel, then you had drop downs and you had widgets. But if you wanted to rent a car, you only had drop downs. And the reason I bring this up is because, remember, inconsistency is one of the things that makes an interface easy to use incorrectly and harder to use correctly. So this is an example of them having three different approaches to solving the same basic problem. So this is from about a year and a half ago, I think. I actually checked shortly before I came here. And right now they have a uniform interface. At least they did when I left. But they have right now, I don't know. The last thing I want to mention is to avoid over reliance on string. So if I have an integer in my program, that is almost a meaningless piece of information. That is not a useful type. And int, what does that mean? A street number and age, number of microseconds since, I don't know, January 1, 1970, number of people who attend this conference. And int is almost useless information. String is similar. If you have a type that is a string, that does not help the compiler help you. So for example, if I have a file name, a file name is a completely different kind of thing, for example, from a customer name. And both of those are really different from, for example, a regular expression. If I have different types for things that are conceptually different, that means that the compiler can make sure I only use them in correct ways. I can do much better validity checking on them. I can also format them for printing things out, stuff like that. I dealt with a client one time, and they had to deal with printer names and with printer driver names. They were both file names, so they just had a string which represented the name. And they actually spent a fair amount of really unpleasant debugging time trying to figure out why their program was not working, because they passed in a driver name when they should have passed in a printer name. Because the type system did not realize that these are two completely different kinds of things that are not substitutable to one another. So the summary of what I have to say here is I do believe that the single most important design guideline is to make interfaces easy to use correctly and hard to use incorrectly. And we talked about some specific ways that you can try to implement that basic idea. One of them is to adhere to the principle of least astonishment. And you can do things like avoid gratuitous incompatibilities with things that are in the surrounding environment, choose good names, which are still really hard to choose and still extremely important, and be consistent in whatever choices you make, whether it's for layout or for naming or for concepts behind things so that people can figure out what you're doing. We talked about progressive disclosure, which is a mechanism that discourages people from going into the places that will probably get them in trouble and encourages them to stay in the areas where they're probably going to get the results that they want. We talked about the very simple approach of documenting interfaces before we actually implement them. And then under the assumption you are working with a programming language which has some kind of strong typing, talked about introducing new types to prevent errors. And I emphasize that you have to be types, not type synonyms, so the type system can help you out. Talked about possibly explicitly defining all the values for that type so that people can't create invalid values. And then I concluded by saying you should avoid over reliance on string. If you are interested in more information on any of these kinds of topics, there's some references here on especially interface and API design, some stuff on user interface design, and that's the end of that. So are there any questions? Yes? What type of APIs do you like? What kind of APIs do I like? I like you are looking up to because they are well designed. So the question is to name an API that I like because I think it's really well designed. Unfortunately, most of my time is spent in the world of C++ and I don't know of any APIs in that world that I would really hold up and say this is a great example of API design. I wish I had some. I mean, there are some in that realm that I would say are pretty good, but I wouldn't call them great. So actually, because it's very late in the day, so I'm going to say thank you very much. You can ask a question later. That'd be fine. So thank you very much for coming. And on your way out, please be sure to pick up the little colored pieces of paper and put them in the bin. So thanks very much. Thank you.
 All right, well, welcome to the last session of the day.  At least the last session of the day for me.  I'm amazed that there's this many people at the end of the day.  So if you just stumbled in here thinking,  well, maybe this is a good place to rest,  I'll try not to wake you.  My name is Scott Myers, and I want  to talk about what I consider to be the single most important  design guideline in working in software development.  And I'll get right to it.  Single most important design guideline, in my opinion,  is to make interfaces easy to use correctly  and hard to use incorrectly.  Now, the reason I think it's the single most important design  guideline is because this is not a user interface guideline.  This is not an API guideline.  This is both.  It applies both to people implementing user interfaces,  and it also applies to people who are implementing things that  are being used by programmers, because there  are a lot of interfaces in software.  In fact, interface design in one form or another  is one of the most common activities  that we have as software developers.  Now, often when people talk about interfaces,  they're thinking about user interfaces.  Could be a graphical user interface.  Could be a gesture-based user interface.  Could be a textual-based user interface.  Those are all interfaces.  But it also could be the kinds of interfaces  that are used by software developers.  So we have library interfaces.  We have class interfaces.  We have function interfaces.  We have module interfaces.  We have generic interfaces.  We have template interfaces.  There are lots and lots of interfaces.  So a very common activity by software developers  either is designing and implementing interfaces  in one form or another, either for end users  or for other developers or for both,  or is consuming those interfaces, either as end users  or as developers, people using APIs and things like that.  It is because interfaces are, by its very nature of the word,  they are literally the way that we interact  with part of a system.  A well-designed interface can make things go really smoothly,  can make it very satisfying, can make it a very pleasant  experience, either as an end user or a programmer.  And a poorly designed interface,  either at the application level or at the user level,  can make things really a very miserable existence.  Because it is so central to both using software  and to developing software, this is why I think it is  the single most important guideline that I know of.  So I start as a point of departure with some assumptions.  So the assumptions that I make are, first off,  the people who are using software, either developers  or end users, the first thing is they've used some software  before.  I think that's a reasonable assumption.  They've interacted with some kind of a system before.  So they have some idea what should be going on.  The second thing is I believe that they are willing to read  at least some documentation, not necessarily  a lot of documentation.  But they are willing to at least try to follow the rules.  And most importantly, I believe that people  who interact with interfaces, either as users or as developers,  they want to succeed.  They want things to work correctly.  I do not know many software developers or many users who  say, you know, I'm going to work today  and I'm going to do a really bad job.  That's my goal for today is to fail as many times as possible.  I just don't think that's very common.  So if these things are true, if people  have some experience with software,  if they're willing to read some documentation to figure out  what the rules are, if they want to succeed,  you can't ask them to bring anything more to the table.  They're already pulling up their end of the bargain,  which means if, for some reason, despite all these things,  they use some software, they use an interface, and they fail.  They do not do what they want to do.  It's not their fault.  It's your fault.  Or in particular, it is the developer of the interfaces  fault for having designed an interface that an experienced  person willing to read some documentation who  wants to succeed failed to succeed at.  That's the sign of a bad interface.  So as a result, software should be easy to use correctly  and it should be hard to use incorrectly.  So if it is possible to perform an action,  and by perform an action, I could mean  do a gesture on some kind of a handheld device,  or do something with a mouse or a keyboard,  or type in some kind of commands, or call a function  interface, or instantiate a class or a template.  These are all acts of interacting with an interface.  If it is possible to do something through the interface,  it should almost always do what the person who's doing it  wants it to.  And if somebody could try to do something  which would not yield the desired behavior,  then that action should typically not even be possible.  You want to have an interface that fulfills what  Rico Mariani has called the pit of success.  The pit of success is if you are doing something  and you trip and you fall, you accidentally land doing  something that you wanted to do.  So if you accidentally succeed with an interface somehow,  it means that it just does the right thing.  Because the things that we're not going to do the right thing  aren't possible, and the things that are possible  almost always do the right thing.  That is the goal.  What I want to do for the remainder of this presentation  is try to give you more specific ideas on how you can  implement easy to use correctly and hard to use incorrectly.  I mean, it's one thing to say, well, this is what you should  do, but the question is, how do you do it?  What are the specific practices that you  can adopt that will help make interfaces have  this particular characteristic?  And the first thing I want to talk about  is adhering to what I call the principle of least  astonishment.  Everybody who comes to an interface,  they have some expectations.  They have some background.  They have some experience, which means  that they have expectations about how that interface is  going to work.  So your job as an interface designer  is to maximize the likelihood that their expectations are  correct.  In many cases, they're going to guess  at how to use the interface.  Your job is to maximize the likelihood  that the guesses are going to be correct.  And I want to emphasize again, this  is not a user interface guideline.  This is not an API guideline.  This is for both kinds of interfaces.  So this should be true across the board.  So if users know what they want to do,  then they should be able to figure out how to do it.  Now, this doesn't mean there's no innovation in interfaces.  So if you come up with some clever new way  to let people accomplish a particular task that's  better than previous ways of doing it, that's fine.  Even if people don't know how to use it initially,  once they've learned how to use it,  they should go, oh, now I understand.  And their expectations from that point forward  should now be something which is going to make it easy to use  correctly and hard to use incorrectly.  So this does not mean you have to stick with old ideas  for interfaces.  But it does mean that once you've  gotten across the basic ideas, people  should be able to figure out how things work.  Now, over the years, I have collected  a large number of examples of either interfaces that  work or more frequently interfaces that do not work.  I'm going to be showing a lot of examples.  Some of them will be user interfaces.  Some of them are going to be APIs.  Some of them are going to be relatively old.  Some of them are going to be relatively new.  So in this case here, I just want  to talk about some basic ideas of avoiding astonishment.  So as an example, a lot of people  don't even think about it anymore.  And now that we're at Windows 8, maybe it  doesn't even work this way.  But for many, many years, if you wanted to shut down  your Windows computer, you would click on Start.  Now, I have actually read the blog entry  where they described how they did a lot of user testing  and how they finally came up with that clicking on Start  was the right way to shut down the machine.  This is stupid.  Clicking on Start is not the right day  to shut down the machine.  And I've had to field more than my share of questions  from people like my parents saying,  so how do I shut down the machine?  I'd say, you click on Start.  And there's dead silence at the other end of the phone.  No one wants to click on Start to stop something.  I'm sorry, this does not make sense.  Now, as I said, I read the blog entry describing  how they came up with this.  And what it boils down to was we tried  a whole bunch of different approaches,  and this one sucked the least.  Guess what?  Sucks least doesn't mean that is the best way to do things.  So many, many years ago, and excuse me,  I'm not a Mac user right now, but when  I was using Macs from time to time,  if you wanted to do things like get a DVD out of the drive  or get a CD out of the drive, what you would do  is you would drag it to the trash.  Who thought this was a good idea?  Who wanted to equate, destroy this forever with ejecting it?  Now, when I learned about this, which  was a number of years ago, quite a number of years ago,  I was in graduate school, you don't always  trust your colleagues in graduate school.  They don't always have your best interests at heart.  So at one point, I said, OK, how do I get this out  of the machine?  And somebody said, you drag it to the trash.  And I said, you are lying to me.  It cannot possibly be true.  Windows XP, which is going back a while,  but there will be newer examples, I promise.  Windows XP had the option that you could choose your font size.  Now, there were two selections by the operating system  for the font size in Windows XP.  Two selections, they ship with Windows XP.  There was normal and large fonts.  Those were your choices.  And what I discovered one time, having tried to use large fonts,  is large fonts breaks everything.  Large fonts simply does not work.  So I've got a couple of screenshots here.  So you can see that, for example, in Excel,  you'll notice that the baselines don't line up here.  Notice that the name of the band here, this is Sponge,  but the P in the GR, the descenders have been cut off  and the CDs cut off on the back here.  Basically, nothing displays correctly with large fonts.  Call me naive.  I was astonished that using one of two choices for the operating  system font size made everything display incorrectly.  Now, maybe I'm a little bit too picky,  but it seems to me that you shouldn't get 50%  of the choices wrong.  I mean, there's two choices.  And what I found from talking to Windows developers  was it was widespread acknowledgement  that it just did not work.  I want to point out now that I'm going  to be giving lots of different examples.  Every single example that I'm going to be giving you  is the result of somebody who said,  let's ship this software, this is ready to go.  I mean, it's easy to pick on things  that people put together, they throw together  in their backyard.  But for example, regardless of what you think  of Microsoft and Windows, it is a professional software  product that a lot of people put spent money on.  Somebody said, ship that baby, it's ready to go.  Everything I'm going to be showing you here  is the result of somebody having saying,  I now believe this is a professional software product  that has the appropriate level of quality  and which will satisfy our users.  On this slide, we've only seen user interfaces.  It's going to get to APIs, I promise.  This is not the kind of problem that  is limited to just user interfaces.  So now let's deal more with a developer level kind of thing.  So this happens to be an example from QT 4.8.  It's a Windows GUI kit that can be installed.  So and what it says is the install path must not contain  any spaces.  Really?  On an operating system that by default has program  files and my documents, the installation path  can't have any spaces.  This is an example of people who develop some software on Unix  where spaces are legal but almost never used.  And then they said, now we'll port it over to Windows  and we will bring our collective Unix baggage with us  and we will then impose it on all our users.  Now it goes the other direction as well.  For example, it is not uncommon for people  to take Windows software which is not case sensitive  and then port it over to Unix and suddenly guess what?  Everything starts breaking because it is case sensitive.  When you move from one environment to another environment,  the expectations that people have are going to change,  which means what it means to make things easy to use correctly  and hard to use incorrectly are going to change as well.  You can't simply take your conception of what's  a good idea and move it someplace else  and expect that community of people  to adapt to your way of doing things.  You have to adapt to their way of doing things.  Someone sent me this and it's so wonderful  that I don't think anybody is ever going to beat this  for the worst possible user interface design.  Now this happens to be a calendar program.  Oh, it's worse than you think.  So this happens to be a calendar program.  So if you have a recurring meeting on your calendar,  like every Monday we have a meeting.  And then let's suppose on some Monday  you don't want to have the meeting.  Maybe you're going to be on vacation.  Maybe it's a holiday.  Maybe the meeting got canceled for some other reason.  So what you say is great.  I want to delete the meeting.  Now when you say that you want to delete the meeting,  there's actually some inherent ambiguity here  because you could be saying, I want to delete the meeting  forever.  We don't ever need to have it again.  It's moved to Tuesdays.  Or you could be saying, no, this one particular Monday  is the day that it needs to go away.  So all right, there needs to be some way  to disambiguate between the two.  So as you can see here, it says delete this single item.  No to delete all.  Now without even going any further,  I have no idea what that means.  So that's no to delete all, followed by um,  abtzebrach, and tipensie, alf, x.  And then two choices, ja and nine.  You know, I didn't know what it meant in English.  And putting it in German is not improving matters any.  But I want to point out, professional software.  Somebody shipped this, they thought  this would be a great way to satisfy their customers.  I'd call that fairly astonishing.  So there are some things you can do  to avoid astonishing people.  One of the things is you want to avoid gratuitous incompatibilities  with the surrounding environment.  People are working in some environment,  some kind of a social environment,  some kind of a computational environment,  some kind of a commute environment.  They have expectations, they have normal standard practices.  Your goal is to seamlessly work with those things  that people are already used to doing.  Basically, you want to take advantage  of what people already know.  That makes it easier for them to use your software.  Again, whether they're end users or whether they're API users,  as long as people's habits and expectations  correspond to what should be done,  you will have a higher rate of success  with people doing things correctly.  Now, the natural syntax for doing these things  can vary depending on the environment.  So for example, if I want to find out  whether two objects in a programming language  have the same value, it's a reasonable thing to want it,  is this thing have the same value as this thing?  But the way that you say that depends  on the programming environment that you're dealing with.  So for example, in C++, use operator equal equal,  that's what is used in that programming language.  Now, in Java, use equals with a lower case e.  And in C sharp, use both equals with an upper case e  and operator equal equal.  So the way that you accomplish the same thing  depends on the particular community that you are targeting.  So this is why you need to adapt what you are doing  to the community of people who are going to be using it.  You also want to offer intuitive semantics.  What I normally tell people is,  if there's not a good reason to diverge  from what people are used to,  then you want to do what people are used to.  So in C++ or other languages,  when in doubt, do is the ints do.  Everybody knows how an int behaves.  So if you don't have a good reason for your type  to not behave like an int, make it behave like an int.  People know what that means.  In GUIs, if you have mouse clicks or you have gestures,  make those things mean whatever they normally mean  in other programs that people use.  Don't come up with your own special way of doing things  unless there's a particular advantage  associated with doing that.  Again, I don't want to rule out interface innovation.  That's clearly something we need to be able to experiment with.  But in some cases, people just change things  because they can change things  and there's no obvious advantage.  And that to me is a good way to astonish people.  Anybody who is a software developer,  anybody who is a programmer,  at some point early in their career,  early in their education, they were told,  you need to choose good names.  Yet they choose really good names.  It's the most important thing, choose really good names.  And every single person who has been given this advice  has learned that all the good names were taken in the 1960s.  There are no good names left.  And yet, that's no excuse because names are,  especially for APIs, they literally are the interface.  The very first thing people see when they're dealing  with an API are things like class names, module names,  function names.  The minute they see a word, they are going to go,  oh, and an idea is going to spring to mind.  And if the idea that springs to mind is not the right idea,  you are going to be fighting them every step of the way  because they have the wrong conception of what is going on.  So it actually is really important to choose good names.  And it's very hard.  One of the reasons it's hard is because all the good names  were taken in the 60s.  But the second thing is there are so many things  that have to be named.  I mean, choosing one good name is hard.  But we have to do things like choose names for libraries,  modules, namespaces, generics.  I'm not going to read the whole slide to you,  but that's a lot of things that need names.  Every one of them is supposed to be a good name.  If all you did was pick names all day long, you'd go crazy.  And yet, the fact that it's hard doesn't change.  It's the fact that that is literally the interface  for any kind of text-based system.  The commands that people type on Unix,  which is not setting any records in terms of beauty,  the kinds of things people type in APIs, library names,  commands to programs, the names are the interface  for those kinds of interfaces.  And to say things like, well, people will get used to it.  Yeah, they will get used to it.  But they'll make a lot of mistakes along the way.  So it really is important to choose good names.  I know it's hard.  Doesn't mean it's not something we should all  be aspiring to all the time.  So here's a couple of counter examples.  So this one happens to be from Adobe Acrobat 9,  but it's actually standard for the Windows platform.  So basically, let's suppose I create a document,  I do some edits to it, and then I  want to close the program without saving it.  So now I have a document that's about to be destroyed  without being saved.  So the program thinks, all right,  we should probably warn you about this.  So what it says is, do you want to save the changes  to the document?  Yes, I know what that means.  No, I know what that means.  Cancel, I never have any idea what that means.  I have to always think and go, what's  the difference between no and cancel again?  And I go, all right, cancel means I actually  want to cancel the request to close the program.  So that doesn't help me too much.  But that's OK.  We have interface innovation.  So open office, I downloaded the most recent version of that.  Open office, not constrained to do things like everybody else  does.  If you do the same thing in open office,  it asks you the same question.  So do you want to save the dot?  Do you want to, what does it say?  Do you want to save your changes?  Well, it doesn't have yes, no, and cancel.  That's too complicated.  It has save.  Well, I actually knew what yes meant,  so that doesn't help me too much.  And then it has discard.  Well, OK, but I knew what no meant.  And then we have cancel.  That's what I had trouble with in the first place.  So it's different, but I don't happen to think it's any better.  Now, there is this notion in the interface community  of what is known as the Gulf of Execution.  The Gulf of Execution is the distance  between conceptually what I wish to be able to do  and the means I have to take in order to get it done.  The distance between what I want to express  and the way that I go about expressing that.  And so anytime the Gulf of Execution is large,  it increases the likelihood that somebody's  going to do the wrong kind of thing.  So for example, somebody might click on either discard or no  when they should have clicked on cancel,  because they really didn't want to lose the document.  It is interesting from time to time  to think about how we could avoid the problem.  As an example, one could imagine that rather than even  presenting this dialogue in the first place,  if you try to exit a program and you hadn't saved the document,  automatically it would just be saved behind the scenes.  You wouldn't have been asked, it would just be there.  And then we'd have to have some kind of interface  that would let people go, oh, right, I wanted that document.  Oh, you saved it for me?  That's so nice.  Why don't you give it to me?  Other interface questions come up,  but the point is that there are other ways  to approach the problem.  For example, rather than saying, I'm  about to throw your document away,  how about don't throw the document away?  And then as I said, there has to be some other kind  of interface which would let us get back  at those kind of old documents.  But by trying to reduce the gulf of execution between, oh,  I just want to get out of the program  and I'm about to throw a bunch of work away,  by adopting a different approach,  we can possibly make that tension be lessened.  The other thing I would ask about this particular kind  of thing, and this is designed for a desktop environment,  so this is not designed for a small screen,  I'm trying to figure out why it is in 2014  where we have these giant monitors with huge numbers  of pixels, we're still following the convention  that we can't have more than one short word on the button.  For example, instead of cancel, something like don't exit  program, I bet that would fit, in which case  a lot of the confusion about what it means  would go away as well.  So this is an example of an interface in my mind  that was designed in the late 1990s  and has not been updated since then.  So we've seen too many GUI examples,  let's talk a little bit about API examples,  and this has to do again with choosing good names.  Now, in the C++ standard library,  there are two different ways to determine  if objects are the same.  One of them is called equality,  one of them is called equivalence,  doesn't even matter what the difference is.  But the point is, there's two ways to say,  is this object equal to this object?  There's two ways to say that.  One of them is to use equality  and one of them is to use equivalence.  So it turns out that they have a function  called equal range.  Takes a bunch of objects in a range  and says, I want you to bunch all of them together,  whose values are equivalent.  So the name of the function is equal range,  but it doesn't use equality.  It uses equivalence and it does make a difference sometimes.  And people do get misled into thinking,  oh, now I have all the values that are equal to something else,  but actually they don't.  They have the values that are equivalent to something else,  not always the same.  So the question really is,  why did they call it equal range and not equivalent range,  since it's not using equality?  Another thing you can do to avoid astonishing people,  one of the most important things is,  you can embrace consistency.  You can have consistency in the wording that you use,  in the way that you lay things out,  in the way you report errors, things like that.  So this is an example that was sent to me a while ago.  This happens to be from an ATM.  And what you will notice in this ATM is that  there's two things you can deposit.  You can do a cash deposit and you can do a check deposit.  Notice that on the screen, the cash deposit's on the left  and the check deposit's on the right.  And now notice that underneath where you actually do the depositing,  so the cash deposit is on the right  and the check deposit is on the left.  Or as I like to say,  you know, they had a 50% chance of getting it right,  which means they had a 100% chance of getting it wrong.  But, I mean, this was only rolled out to probably tens of thousands  of places around the world.  So, really?  I mean, is that so complicated to make sure that things are consistent  in terms of their visual, their spatial layout?  Also, in terms of consistency, in Java,  if you would like to find out how many elements are in a container,  there's three ways to do it.  So, if you have an array, use the length property.  If you have a string, use the length method.  And if you have a list, use the size method.  Three different ways to get the same kind of information.  That's Java.  So, Microsoft looked at Java and said,  man, this is crazy.  Three different ways to get the same information.  What kind of loser company would have three ways  to get the same information?  So, when they invented.NET, they said,  we will not have three ways to get the same information.  We'll have two.  So, if you want to know how many elements are in a container,  you have the length property for arrays,  and you have the count property for array list.  You also have a count method on Ianuma.  Pardon me?  You also have a count method on Ianuma,  so it's actually the same.  I'm sorry, one more time?  The count method also exists.  On what?  On Ianuma.  Oh, count method or count property?  Method.  OK, all right.  So, on Ianuma, then, so there actually  are three different ways?  Cool.  I'll just make a little note here.  You think I'm making it up?  Ianumerable?  Count method.  OK, remember, professional released software products.  These are people who are doing the best  that they possibly can.  But that now is withstanding.  So, we have a situation now.  Sometimes when I talk to people, they say, look,  you know, especially in.NET, everybody's using Visual Studio,  and it's got completion, so all you have to do  is type the first letter of the method name or the property  name.  It'll tell you what it happens to be.  So my first observation is, number one, L and C  are not the same letter.  So you actually have to find out what that's going to be.  The other thing is this makes the assumption  that you're always using an IDE.  But these kinds of languages also have reflection-based code.  With reflection-based code, you can actually  be generating and processing code at runtime.  And guess what?  At runtime, there's no IDE.  Instead, what you have to do is take a look at something  and then query its interface to find out  what kinds of things it supports.  And guess what?  That querying becomes a lot more complicated and error-prone  if you have to check for two or three different possibilities.  So the excuse of, well, we have an environment  that makes these problems go away, bad news.  It doesn't make the problems go away.  It might reduce the severity in some cases,  but it doesn't solve them completely.  Again, on the topic of consistency,  this is from the C standard library.  So we have three different functions here.  We've got F scan F, we have F get pause, and we have F seek.  Notice that all three of them take a file pointer parameter  as the first parameter.  All right, so we notice a pattern here.  When you're dealing with files, you  will pass in a file pointer as the first parameter.  All right, that's easy to remember.  Oh, wait.  It turns out there's also F get, F put C, and free open.  It also takes a file pointer as the last parameter.  I have talked to several extremely experienced C  programmers, people who do this for a living.  They've done it for decades.  And they will all say they have to look it up  every single time.  I mean, they simply cannot memorize this stuff.  And there's a lovely quote here that has been said,  this is something which I think is important to keep in mind.  This inconsistency has frustrated millions of developers  for more than 30 years.  And the reason I point this out is,  if you are involved in the development of an interface that  is so successful that it is used by millions of people  for decades, wouldn't it be nice if one of the things that  is remembered for is how easy it was to use  and how you didn't have to look up the details every single time  you wanted to use it?  Now, most of us will never be sufficiently lucky  to develop an interface that has that kind of widespread use.  But shouldn't you aspire to something which  can stand the test of time and which people  are going to look back and say, you know,  that was a really nice interface.  That's supposed to look it up every single time  I want to make a function call.  It's kind of crazy.  So this is a different kind of consistency.  This is from the C++ standard library.  And again, I'm trying to mix up API things and GUI things.  There's a number of standard containers  in the C++ standard library.  So let's suppose you have a container.  And what you want to do is you want  to get rid of all the elements of the container  that have a particular value.  I want to get rid of all the 10s.  Or I want to get of, I don't know, all the colors  that are blue, whatever it happens to be.  So if it's a set, you call erase.  If it's a multi-set, you call erase.  If it's a map, if it's a multi-map, you call erase.  If it's an unordered set, unordered multi-set,  unordered map, unordered multi-map, you call erase.  I'm beginning to notice a trend here.  If it's a list, you call remove.  And if it's a forward list, you call remove.  By the way, they do exactly the same operation.  They're just named differently.  And what's important to notice about these kinds of examples,  the thing about consistency, usually things  that are inconsistent, it's an utterly arbitrary decision.  You cannot argue that these names  had to be different for some compelling technical reason.  They're just different because they probably  were developed independently.  And then when somebody noticed that they were inconsistent,  they didn't bother to fix it.  They didn't say, now, now, before we standardize this,  let's make sure that they actually  behave in a consistent fashion.  So some problems have technical justifications.  This is not one of them.  I've talked about consistency in layout, spatially  in a GUI, for example.  I've talked about consistency in terms of calling forms.  But there's a different kind of consistency  I want to mention now because consistency is across the board.  It should occur in many different domains.  So again, this is from the C++ standard library.  So there is a function sort.  If you call sort on a collection of values,  either it will sort it in n log n time  or it will not compile.  So for example, if you have a doubly linked list, which  cannot be sorted using this algorithm in n log n time,  and you try to sort the doubly linked list,  it will not compile.  So the philosophy there is if we can't do this efficiently,  we won't even support it.  Your program won't compile.  That's the philosophy.  Now, there is another function.  It's called binary search.  Binary search in the same standard library.  It will run in log n time, which is what you'd expect  from binary search if it can.  And if it can't run in log n time,  it will run in linear time.  You can invoke binary search on a linked list.  This is an inconsistency in philosophy  because this philosophy says if there's any way to do this,  we will do it, even if it's really slow.  But what that means is that the library  is a whole for your typical developer working in C++.  It means that when they make a function call,  they don't know if it's going to compile.  And if it does compile, they don't  know if it's going to be fast or slow in general.  Because the people designing the library  didn't have a consistent set of philosophies  about what it would mean to have performance guarantees.  So this is not a syntactic constraint.  This is more of a philosophical conceptual inconsistency.  And that kind of inconsistency is no better or worse  than any other kind of inconsistency.  Another thing from the C++ standard library,  and some of you may not know, that I sort of live  in the C++ world.  So that's why some of the examples are coming from that.  There is a function called sort.  When you sort values, the sort technique  can either be stable or unstable.  It doesn't matter what the words mean.  But the point is there's two ways to do it, stable or unstable.  The sort algorithm is not guaranteed to be stable.  But that's OK.  If you need stability, there's another algorithm.  Stable sort, which is guaranteed to be stable.  Well, this makes sense so far.  Sort, not guaranteed to be stable.  Stable sort, guaranteed to be stable.  However, there is also a special algorithm  for sorting doubly linked lists.  It is called sort, and it's guaranteed to be stable.  So we've now talked about consistency.  We've talked about avoiding surprising people.  I want to now talk a little bit about progressive disclosure.  Remember, the high level goal we're  trying to achieve here is interfaces that are easy  to use correctly and hard to use incorrectly.  When you get to an interface of a particular level  of complexity, and again, whether it's a user interface  or an API, once there are a whole bunch of choices  that people can make, a whole bunch of possible things  they can do, the likelihood of them doing the wrong thing  increases.  If you're faced with a whole wall of buttons,  the chances of hitting the wrong button go up.  So what we'd like to do is find a way  to reduce the likelihood that people are  going to hit the wrong button.  And one of the ways to do that is what is known  as progressive disclosure.  What progressive disclosure does is it says, listen,  of all these choices that people have,  of all the things that they could do,  these are the ones they probably want to do,  and these are the ones that they are much less likely  to want to do.  Now, we need to make all of them available all the time,  but what we can do is make it easy to hit the buttons  or use the levers that we want people to use,  because it's likely to be what they want,  and harder to use it some other ones.  So what you can do is distinguish normal from expert  or advanced level kinds of commands.  So this is something that happens to be from the most recent  version of Firefox, but you've got some choices here,  but notice there's an advanced button,  and when you click on the advanced button,  it brings up a whole bunch more options.  The idea here is that for most people when they're in,  well, which section is this?  Content, it looks like.  When you're in the content section here,  these are the things that you probably want to work with,  but there are some other options for people  who are more advanced, in which case they can click  on the advanced button and then some more options pop up.  The idea is to minimize the likelihood that somebody's  just clicking on buttons and gets themselves all messed up  by having the user interface designer distinguish  between the elementary stuff and the more advanced stuff.  I want to point out that progressive disclosure is not  the same as categorizing things.  So this is from a different program called super.  This is a fairly complicated looking interface  with all kinds of options, and they're separated  in the colors and dissections, but the point is all the options  are still there on one screen.  There's nothing there which says this is probably what you  want to do, and this is probably not what you want to do.  So there's nothing wrong with categorization.  Categorization serves a lot of really useful purposes,  but just bear in mind categorization is not the same  as progressive disclosure.  Progressive disclosure is a way of hiding things  from people initially because they are unlikely  to want to use them.  It's a way of making things harder to get at.  And it's not something which is limited  to user interface design.  So if I have an object which has, let's say, 100 methods,  number one, I've got a problem already,  but I've have an object with 100 methods,  and 20 of them are likely to be used a lot,  and the other 80 are for very specialized cases,  rather than having a single 100 method object,  what I can do instead is break it into two objects  where one object has the 20 methods  that I probably want to use, and the other object  actually holds the other 80 methods,  so I have to ask for that sub-object  in order to get access to those methods.  Now, a number of years ago, Ken Arnold,  actually almost 10 years ago, wrote an article called  Programmers Are People Too, and it was based  on the observation that a lot of work  is put into user interface design  to make it easier for people to use programs,  but at the underlying programming level,  people are often presented with these very large,  complicated APIs that are easy to use incorrectly,  and his observation was, why don't we do the same  kind of thing with programmers that we do  with regular end users?  Let's also shield them for this kind of complexity.  So the example he talked about was Java Swing's  JButton class, which he says it offers over 100 methods,  but he pointed out of those greater than 100 methods,  about maybe 15 are the ones that most people  dealing with buttons most of the time  are likely to want to manipulate,  and all the other buttons just get people in trouble  and lead to a lot more debugging for their programs,  so he proposed a better design, which essentially involved  taking the JButton class, breaking it into smaller pieces,  and the smaller pieces would then be used as sub-objects,  so if you wanted to get access to some of these lesser used  options, you actually would have to ask for a sub-object,  which meant that it was less likely  that casual users were going to get themselves into trouble.  It's progressive disclosure, but it's at the API level.  Another thing you can do to make interfaces easy to use  correctly and hard to use incorrectly  is simply to document them before you implement them.  If you write up the documentation for interface,  whether it's a user interface or whether it's an API,  before you've actually implemented the interface,  you are likely to find problems of the kind  we've talked about so far.  For example, if things are inconsistent,  when you start writing about it, you  begin to notice that they're inconsistent.  If things are overly complicated to try  to explain to people, then they probably  need to be simplified.  So if there are bad names, so if a name seems to say one thing  but actually says something else,  you have a chance to change the name.  And this whole idea of writing documentation  before you actually write the code  is completely consistent, for example,  with test-driven development, where  you are writing the test cases before you're  writing the code itself.  But it turns out that the very low-tech approach  of documenting an interface before you've  implemented the interface has the nice side effect of making  the interface better in most cases.  Assuming you are working in a strongly typed programming  language, something which actually does enforce typing,  if that is a reasonable assumption,  then it's important to understand  that the type system is one of the most powerful tools  that you have at your disposal.  So by using the type system, you can prevent people  from making certain kinds of likely mistakes.  So let's suppose I have a date class,  and here's a date class.  It takes an integer month, an integer day,  and an integer year.  Now, one of the reasons I chose the date class  is because the conventions for expressing dates,  at least colloquially, in the United States  are different from the way that they're expressed pretty much  every place else in the world.  So there is sort of the inherent possibility  of people expressing a date incorrectly.  But there's actually a more general observation  I want to make.  But the first thing is, so if we take the int month, the int  day, and the int year, then if somebody  doesn't pay close attention, they might say, well,  I'm going to pass it in the day, and then the month in the year,  or even the year, and the month in the day, which arguably  is the most reasonable way to do things.  But the interface can't tell the difference.  From the interface point of view,  they're all just integers.  So it has no way of knowing that the wrong things are  being passed in.  And there is a more generalized observation here.  Any time you have an API, which has two parameters next  to one another with the same type,  there is the inherent possibility  that they can be flipped, and the type system  won't be able to tell.  So any function taking parameters of the same type that  are adjacent to one another, you have just  eliminated the possibility of the type system  being able to tell you when people pass them in the wrong  order.  But let's talk about this idea of a date class here.  So this date class here, this is an interface  that is easy to use incorrectly.  People could easily pass in things  that they don't pass in the day, month, and year  in the proper order.  So well, OK, what we can do, assuming  we have a strong type system, is we  can create a type for day, a type for month,  and a type for year.  So now there are actually three different types.  Well, now that I've got three different types,  I can say, OK, here's my date class.  You've got to pass in the month first, the day second,  and the year third.  So now if you do not pass them in the right order,  the compiler through strong type checking  can ensure that your code does not compile.  This means we've just eliminated a whole class of errors.  People can't pass these things in the wrong order.  So that's a nice improvement.  Now, it also means that the code is clearer.  So if I say, all right, I want to have a date D with 4, 8,  and 2005, somebody reading that code  could easily misinterpret, OK, is that  April 8th or is that August 4th?  It's not quite clear from looking at it.  When you spell out the types, it's  quite clear exactly what's going on.  So that's an improvement.  So it's easier to read as well as being harder to make mistakes.  I want to point out that the technique of introducing new  types for strong type checking only  works if you actually are introducing new types.  So if you're working in languages with type aliases,  where you can create another name for an existing type,  c and c++ are the examples that come to mind,  if I say, OK, day is a synonym for int,  month is a synonym for int, and year is a synonym for int,  and then I say, here's my date class, which takes a month, a day,  and a year.  This is a beautiful looking interface.  The problem is, as far as the compiler is concerned,  it's date of int, int, int.  This is what I call programming to make you feel better  about yourself.  I mean, it looks beautiful, but the problem  is you can now say I'm going to pass in a day, a month,  and a year, which is the wrong order here,  and the code continues to compile.  So if you're going to use the type system,  you actually have to use the type system, not  the apparent type system.  That doesn't do you any good.  And if you want to know why my fixation is with April 8,  2005, that's the day we brought our puppy home.  That's Darla.  Now, Darla is adorable, needless to say.  But since we're focusing on interfaces,  it's important to recognize, even with what we've talked  about so far, there are still ways  to make mistakes with this kind of an interface.  So what I could do is I could say, OK, I want to have the month  m, but the month is minus 4.  Now, why would you type minus 4 as a month?  Nobody would type minus 4 as a month.  However, let's suppose you're supposed  to be calculating the month.  And instead of saying something like a plus b,  you accidentally said a minus b.  People have been known to make those kinds of mistakes.  So you might accidentally compute the month incorrectly.  Now, in this particular case, last I checked,  there are only 12 valid months.  So if there's only 12 valid months,  it doesn't make a lot of sense to me to represent them  by probably an integer which could represent  4 billion possible values.  When you have a constrained set of values, in many cases,  you are better off designing an interface that  constrains the values to only the ones that  are known to be legitimate.  So what we could do is we could say, all right,  I've only got 12 month values that make any sense.  So what I'm going to do is I'm going to create 12 month objects,  give them the appropriate name, and make it so nobody can  create any other month objects.  So for example, I might say, here's my class month,  and then I've got objects for January, February,  all the way down through December.  In this case here, I am making the constructor  for months private, which means nobody can create any other  month objects.  So I've said, here are the 12 month objects that you're  permitted to use, and you can't create anymore, which means  that now it's essentially impossible to create invalid  months.  You've eliminated a whole class of errors.  So if I try to say month M minus 4, this won't compile  because this is trying to create a brand new month object,  and we've made construction illegal for those kinds of  things.  But I could say, the month is month colon colon April,  that'll work.  So that's nice.  That's an improvement.  Well, the problem now is, OK, so I could say, all right, the  day D is 71.  Well, last I checked, there are not any months with 71  days in them.  So it's interesting, though, to think about what we can do  about dealing with that problem.  I believe it is an extremely useful exercise when looking  at any interface to always ask yourself, how could this  interface innocently be misused?  No one's going to type 71, but again, a formula might yield  something which isn't valid.  So the question is, how could we prevent these kinds of  mistakes?  Now, what we could do in this particular case is I could say,  well, all right, if I know what year it is, and I know what  month it is, I now know how many days there  exist in that particular month.  So one could imagine an API where you first you create a  year object, you go to the year, you then have it give you  month objects, and once you've got a month, it will then give  you day objects, and then it would be impossible to  specify the wrong day, or at least an invalid day.  You can specify the wrong day, but you can't specify a day  that does not exist.  Once you've come up with a possible way to prevent people  from making certain kinds of mistakes, then you can say,  all right, what is the likelihood of making the  mistake, and how serious will it be if somebody makes it?  And how much work is it going to be for me to prevent people  from making that mistake?  Once you have those two pieces of information, you can start  doing an engineering judgment for the trade-offs.  You can say, all right, this is how likely it is, and this is  what it's going to cost me if I do it, and this is how much  work it is to prevent people from making that kind of  mistake, is it worth it or is it not worth it?  I can't tell you the answer to that question, but what I can  tell you is that in my experience, most people don't  do the analysis in the first place.  They simply decide, all right, this is what we're going to  implement for an API, and we're not going to worry about the  kinds of mistakes that people can make.  That's what I just said.  Now, constraining values is not always the best way to go.  So this happens to be, this is from a couple of years ago,  Lonely Planet has changed its website, which will become  relevant in a moment.  But so this says, all right, so I've specified, as I recall  here, so the month has been specified to be June, but  notice I can choose June 31st.  So this is an example of an interface that makes the  interface designer feel like they're really doing a great  thing, they're constraining the values.  The problem is they're not making it impossible to  choose illegal values.  So this is an example of an interface that looks like it's  constraining values for a reasonable case, but it actually  doesn't solve the problem.  What would be a better way to solve this problem?  Pardon me?  Have someone have a calendar widget so you'd only be able  to click on the appropriate things in the first place.  So this problem can literally be designed out of existence.  What struck me when I did this a couple of years ago, so I  went to Lonely Planet where if you want to fly, then you go  to their flight logger.  Now, with the flight, you actually do have a calendar  that you choose.  And in fact, there's no drop downs.  On the other hand, if you wanted to do a hotel, then you  had drop downs and you had widgets.  But if you wanted to rent a car, you only had drop downs.  And the reason I bring this up is because, remember,  inconsistency is one of the things that makes an interface  easy to use incorrectly and harder to use correctly.  So this is an example of them having three different  approaches to solving the same basic problem.  So this is from about a year and a half ago, I think.  I actually checked shortly before I came here.  And right now they have a uniform interface.  At least they did when I left.  But they have right now, I don't know.  The last thing I want to mention is to avoid over  reliance on string.  So if I have an integer in my program, that is almost a  meaningless piece of information.  That is not a useful type.  And int, what does that mean?  A street number and age, number of microseconds since, I  don't know, January 1, 1970, number of people who attend  this conference.  And int is almost useless information.  String is similar.  If you have a type that is a string, that does not help  the compiler help you.  So for example, if I have a file name, a file name is a  completely different kind of thing, for example, from a  customer name.  And both of those are really different from, for example,  a regular expression.  If I have different types for things that are conceptually  different, that means that the compiler can make sure I only  use them in correct ways.  I can do much better validity checking on them.  I can also format them for printing things out, stuff  like that.  I dealt with a client one time, and they had to deal with  printer names and with printer driver names.  They were both file names, so they just had a string which  represented the name.  And they actually spent a fair amount of really unpleasant  debugging time trying to figure out why their program was  not working, because they passed in a driver name when  they should have passed in a printer name.  Because the type system did not realize that these are two  completely different kinds of things that are not  substitutable to one another.  So the summary of what I have to say here is I do believe  that the single most important design guideline is to make  interfaces easy to use correctly and hard to use  incorrectly.  And we talked about some specific ways that you can try  to implement that basic idea.  One of them is to adhere to the principle of least  astonishment.  And you can do things like avoid gratuitous incompatibilities  with things that are in the surrounding environment, choose  good names, which are still really hard to choose and still  extremely important, and be consistent in whatever choices  you make, whether it's for layout or for naming or for  concepts behind things so that people can figure out what  you're doing.  We talked about progressive disclosure, which is a  mechanism that discourages people from going into the  places that will probably get them in trouble and encourages  them to stay in the areas where they're probably going to get  the results that they want.  We talked about the very simple approach of documenting  interfaces before we actually implement them.  And then under the assumption you are working with a  programming language which has some kind of strong typing,  talked about introducing new types to prevent errors.  And I emphasize that you have to be types, not type synonyms,  so the type system can help you out.  Talked about possibly explicitly defining all the  values for that type so that people can't create invalid  values.  And then I concluded by saying you should avoid over  reliance on string.  If you are interested in more information on any of these  kinds of topics, there's some references here on  especially interface and API design, some stuff on user  interface design, and that's the end of that.  So are there any questions?  Yes?  What type of APIs do you like?  What kind of APIs do I like?  I like you are looking up to because they are well designed.  So the question is to name an API that I like because I  think it's really well designed.  Unfortunately, most of my time is spent in the world of C++  and I don't know of any APIs in that world that I would  really hold up and say this is a great example of API design.  I wish I had some.  I mean, there are some in that realm that I would say are  pretty good, but I wouldn't call them great.  So actually, because it's very late in the day, so I'm going  to say thank you very much.  You can ask a question later.  That'd be fine.  So thank you very much for coming.  And on your way out, please be sure to pick up the little  colored pieces of paper and put them in the bin.  So thanks very much.  Thank you.
Scott_Meyers_-_Better_Software_No_Matter_What_The_Most_Important_Design_Guideline_0_719.png Scott_Meyers_-_Better_Software_No_Matter_What_The_Most_Important_Design_Guideline_720_1379.png Scott_Meyers_-_Better_Software_No_Matter_What_The_Most_Important_Design_Guideline_1380_3887.png Scott_Meyers_-_Better_Software_No_Matter_What_The_Most_Important_Design_Guideline_3888_8495.png Scott_Meyers_-_Better_Software_No_Matter_What_The_Most_Important_Design_Guideline_8496_11015.png Scott_Meyers_-_Better_Software_No_Matter_What_The_Most_Important_Design_Guideline_11016_16319.png Scott_Meyers_-_Better_Software_No_Matter_What_The_Most_Important_Design_Guideline_16320_17531.png Scott_Meyers_-_Better_Software_No_Matter_What_The_Most_Important_Design_Guideline_17532_18095.png Scott_Meyers_-_Better_Software_No_Matter_What_The_Most_Important_Design_Guideline_18096_18143.png Scott_Meyers_-_Better_Software_No_Matter_What_The_Most_Important_Design_Guideline_18144_18203.png Scott_Meyers_-_Better_Software_No_Matter_What_The_Most_Important_Design_Guideline_18204_18251.png Scott_Meyers_-_Better_Software_No_Matter_What_The_Most_Important_Design_Guideline_18252_18443.png Scott_Meyers_-_Better_Software_No_Matter_What_The_Most_Important_Design_Guideline_18444_18503.png Scott_Meyers_-_Better_Software_No_Matter_What_The_Most_Important_Design_Guideline_18504_18695.png Scott_Meyers_-_Better_Software_No_Matter_What_The_Most_Important_Design_Guideline_18696_18743.png Scott_Meyers_-_Better_Software_No_Matter_What_The_Most_Important_Design_Guideline_18744_18995.png Scott_Meyers_-_Better_Software_No_Matter_What_The_Most_Important_Design_Guideline_18996_19295.png Scott_Meyers_-_Better_Software_No_Matter_What_The_Most_Important_Design_Guideline_19296_19487.png Scott_Meyers_-_Better_Software_No_Matter_What_The_Most_Important_Design_Guideline_19488_21839.png Scott_Meyers_-_Better_Software_No_Matter_What_The_Most_Important_Design_Guideline_21840_25403.png Scott_Meyers_-_Better_Software_No_Matter_What_The_Most_Important_Design_Guideline_25404_28907.png Scott_Meyers_-_Better_Software_No_Matter_What_The_Most_Important_Design_Guideline_28908_34391.png Scott_Meyers_-_Better_Software_No_Matter_What_The_Most_Important_Design_Guideline_34392_34451.png Scott_Meyers_-_Better_Software_No_Matter_What_The_Most_Important_Design_Guideline_34452_34643.png Scott_Meyers_-_Better_Software_No_Matter_What_The_Most_Important_Design_Guideline_34644_34703.png Scott_Meyers_-_Better_Software_No_Matter_What_The_Most_Important_Design_Guideline_34704_34943.png Scott_Meyers_-_Better_Software_No_Matter_What_The_Most_Important_Design_Guideline_34944_35003.png Scott_Meyers_-_Better_Software_No_Matter_What_The_Most_Important_Design_Guideline_35004_35195.png Scott_Meyers_-_Better_Software_No_Matter_What_The_Most_Important_Design_Guideline_35196_35243.png Scott_Meyers_-_Better_Software_No_Matter_What_The_Most_Important_Design_Guideline_35244_35351.png Scott_Meyers_-_Better_Software_No_Matter_What_The_Most_Important_Design_Guideline_35352_35399.png Scott_Meyers_-_Better_Software_No_Matter_What_The_Most_Important_Design_Guideline_35400_35447.png Scott_Meyers_-_Better_Software_No_Matter_What_The_Most_Important_Design_Guideline_35448_35495.png Scott_Meyers_-_Better_Software_No_Matter_What_The_Most_Important_Design_Guideline_35496_35603.png Scott_Meyers_-_Better_Software_No_Matter_What_The_Most_Important_Design_Guideline_35604_35651.png Scott_Meyers_-_Better_Software_No_Matter_What_The_Most_Important_Design_Guideline_35652_36059.png Scott_Meyers_-_Better_Software_No_Matter_What_The_Most_Important_Design_Guideline_36060_37667.png Scott_Meyers_-_Better_Software_No_Matter_What_The_Most_Important_Design_Guideline_37668_38711.png Scott_Meyers_-_Better_Software_No_Matter_What_The_Most_Important_Design_Guideline_38712_41879.png Scott_Meyers_-_Better_Software_No_Matter_What_The_Most_Important_Design_Guideline_41880_42563.png Scott_Meyers_-_Better_Software_No_Matter_What_The_Most_Important_Design_Guideline_42564_44507.png Scott_Meyers_-_Better_Software_No_Matter_What_The_Most_Important_Design_Guideline_44508_45575.png Scott_Meyers_-_Better_Software_No_Matter_What_The_Most_Important_Design_Guideline_45576_46655.png Scott_Meyers_-_Better_Software_No_Matter_What_The_Most_Important_Design_Guideline_46656_47663.png Scott_Meyers_-_Better_Software_No_Matter_What_The_Most_Important_Design_Guideline_47664_49787.png Scott_Meyers_-_Better_Software_No_Matter_What_The_Most_Important_Design_Guideline_49788_49895.png Scott_Meyers_-_Better_Software_No_Matter_What_The_Most_Important_Design_Guideline_49896_49943.png Scott_Meyers_-_Better_Software_No_Matter_What_The_Most_Important_Design_Guideline_49944_50051.png Scott_Meyers_-_Better_Software_No_Matter_What_The_Most_Important_Design_Guideline_50052_50099.png Scott_Meyers_-_Better_Software_No_Matter_What_The_Most_Important_Design_Guideline_50100_51167.png Scott_Meyers_-_Better_Software_No_Matter_What_The_Most_Important_Design_Guideline_51168_54107.png Scott_Meyers_-_Better_Software_No_Matter_What_The_Most_Important_Design_Guideline_54108_55175.png Scott_Meyers_-_Better_Software_No_Matter_What_The_Most_Important_Design_Guideline_55176_58163.png Scott_Meyers_-_Better_Software_No_Matter_What_The_Most_Important_Design_Guideline_58164_59747.png Scott_Meyers_-_Better_Software_No_Matter_What_The_Most_Important_Design_Guideline_59748_62807.png Scott_Meyers_-_Better_Software_No_Matter_What_The_Most_Important_Design_Guideline_62808_63707.png Scott_Meyers_-_Better_Software_No_Matter_What_The_Most_Important_Design_Guideline_63708_64379.png Scott_Meyers_-_Better_Software_No_Matter_What_The_Most_Important_Design_Guideline_64380_65807.png Scott_Meyers_-_Better_Software_No_Matter_What_The_Most_Important_Design_Guideline_65808_66011.png Scott_Meyers_-_Better_Software_No_Matter_What_The_Most_Important_Design_Guideline_66012_67595.png Scott_Meyers_-_Better_Software_No_Matter_What_The_Most_Important_Design_Guideline_67596_68603.png Scott_Meyers_-_Better_Software_No_Matter_What_The_Most_Important_Design_Guideline_68604_72107.png Scott_Meyers_-_Better_Software_No_Matter_What_The_Most_Important_Design_Guideline_72108_72203.png Scott_Meyers_-_Better_Software_No_Matter_What_The_Most_Important_Design_Guideline_72204_73667.png Scott_Meyers_-_Better_Software_No_Matter_What_The_Most_Important_Design_Guideline_73668_74951.png Scott_Meyers_-_Better_Software_No_Matter_What_The_Most_Important_Design_Guideline_74952_77291.png Scott_Meyers_-_Better_Software_No_Matter_What_The_Most_Important_Design_Guideline_77292_79607.png Scott_Meyers_-_Better_Software_No_Matter_What_The_Most_Important_Design_Guideline_79608_79775.png Scott_Meyers_-_Better_Software_No_Matter_What_The_Most_Important_Design_Guideline_79776_79859.png Scott_Meyers_-_Better_Software_No_Matter_What_The_Most_Important_Design_Guideline_79860_81431.png Scott_Meyers_-_Better_Software_No_Matter_What_The_Most_Important_Design_Guideline_81432_81491.png Scott_Meyers_-_Better_Software_No_Matter_What_The_Most_Important_Design_Guideline_81492_81551.png Scott_Meyers_-_Better_Software_No_Matter_What_The_Most_Important_Design_Guideline_81552_81611.png Scott_Meyers_-_Better_Software_No_Matter_What_The_Most_Important_Design_Guideline_81612_81695.png Scott_Meyers_-_Better_Software_No_Matter_What_The_Most_Important_Design_Guideline_81696_81767.png Scott_Meyers_-_Better_Software_No_Matter_What_The_Most_Important_Design_Guideline_81768_81815.png Scott_Meyers_-_Better_Software_No_Matter_What_The_Most_Important_Design_Guideline_81816_81863.png Scott_Meyers_-_Better_Software_No_Matter_What_The_Most_Important_Design_Guideline_81864_81911.png Scott_Meyers_-_Better_Software_No_Matter_What_The_Most_Important_Design_Guideline_81912_81959.png Scott_Meyers_-_Better_Software_No_Matter_What_The_Most_Important_Design_Guideline_81960_82007.png Scott_Meyers_-_Better_Software_No_Matter_What_The_Most_Important_Design_Guideline_82008_82026.png