A Philosophy of Software Design | John Ousterhout | Talks at Google

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments

His book is excellent, I recommend it to anyone who is a professional software developer. One of the highlights is about api / class design and a focus on the future user vs. what makes it easiest to code. Perhaps intuitive advice to some, but I’ve worked with too many engineers that design the most convoluted interfaces without really thinking about it.

👍︎︎ 18 👤︎︎ u/zilchers 📅︎︎ Nov 24 2019 🗫︎ replies

The problem with good software design is that it actually doesn't help your career that much. You get evaluated on the past, not the future which where good design helps. By cutting corners and launching fast, you can get promoted faster. If the technical debt becomes a problem, jump to a different project. It's synonymous with how people say you should focus on "impact."

👍︎︎ 23 👤︎︎ u/ilikesoftwarealot 📅︎︎ Nov 25 2019 🗫︎ replies

Here the slides from the talk: https://platformlab.stanford.edu/Seminar%20Talks/retreat-2017/John%20Ousterhout.pdf

Also I've just finished the book, A Philosophy of Software Design. It was a really nice read. It's focused on how to manage and reduce the inevitable complexity of software systems, building simple, clear and deep interfaces. It provides a good set of examples and advices making easy to apply the concepts right away. I would recommend it to anyone.

👍︎︎ 22 👤︎︎ u/ml01 📅︎︎ Nov 24 2019 🗫︎ replies

At 48:40+ his quality as a teacher manifests. Few teachers are receptive to things like that, fewer consider evolving their own philosophy based on it and fewer still credit the source.

Also, my kid just finished their CompSci degree. I looked at all the subject choices. There were no strands for anything remotely like design and expert+peer design critique. I saw it as a huge gap. My kid was very lucky in that their final year project they were head-hunted for an internship like situation, where they gained those skills, but other students in the degree proceeded with their own personal or student group projects. It left me wondering if they would be able to move into good design or if they had self embedded habits discussed in the video, like shallow classes.

Ahh, one more thing! The notion that 'a block of code should be no more than 20 lines', mentioned in that video. This 'lore' dates back to monitor limitations, where you had 24 available lines that were 80 characters wide. The 4 extra lines allowed for screen menus and footers and line overruns. In those times it was important, because scrolling was painfully slow and jerky. The ability to jump between code routines and see the entire routine on your single monitor was critical. It was not a lore of good software design, it was lore for the limitations of hardware in implementing software.

👍︎︎ 14 👤︎︎ u/CodeEast 📅︎︎ Nov 24 2019 🗫︎ replies

This is great. Thanks! Although I'm not against SOLID principles, they don't really get to the heart of what makes software valuable and how you can build that value. They might try, but not intentionally. Not like this. This really struck a chord with me. Checking out the book now :)

👍︎︎ 5 👤︎︎ u/RapBeautician 📅︎︎ Nov 24 2019 🗫︎ replies

I have some objection regarding the advice given to prefer "deep" instead of "shallow" classes. The flip side of the "deep" classes is the "god class" that encompasses all functionality. The advice also doesn't apply to interfaces: shallow interfaces are extremely common in FP languages (e.g. typeclasses such as Monoid, Functor or Monad in Haskell). The issue is that although such abstractions usually capture very short code, they have many more properties.

I also think that programming languages do mater: a lot of the issues with handling invalid states in C/C++/Java/etc come from the lack of suport for algebraic data types and pattern matching which have been around for 30+ years in FP languages and finally now hitting the mainstream in newer languages like Scala, Swift and Rust.

👍︎︎ 3 👤︎︎ u/pbvas 📅︎︎ Nov 26 2019 🗫︎ replies
Captions
[MUSIC PLAYING] SPEAKER 1: OK. So, welcome. Good morning, everyone. It's my pleasure to welcome Professor Ousterhout for this Talks at Google presentation. My name is [INAUDIBLE]. I work in Technical Infrastructure Cloud. Very quick intro to John to get things started here-- John is a Professor of Computer Science at Stanford University. He spent, before that, 14 years in industry where he founded two companies, Scriptics and Electric Cloud and, before that, 14 years as a professor at UC Berkeley. Anybody here who has taken a class with John before-- so a bunch of his students as well. So he's pretty distinguished, so I'm not going to go through a list of his awards here-- a member of the National Academy of Engineering, ACM Software System Award, UC Berkeley Distinguished Teaching Award, to name a few here. But more relevant to this talk, John has built several influential systems, the Sprite operating system, Tcl, Tk, log-structured file systems, Raft, and, more recently, RAMCloud. And I think his bios says he has literally graded, like, thousands of programming student assignments. And today, we are going to hear the synthesis of all of John's first-hand knowledge both from his research and teaching on a topic that's very close to us, how to design and how not to design software. There is a book here. I don't have it to show. Let me show it to the camera here. There is a book or "A Philosophy of Software Design." I was pretty lucky to read the pre-print of this. It's a really good book. And hopefully, he'll tell us a little bit more about that as well. And last note, if you have questions, since this is being recorded, just raise your hand, and you'll get the mic to you. And then you can ask questions. So, welcome, John. JOHN OUTSERHOUT: Great. Thank you. [APPLAUSE] First of all, I do not have an hour's worth of material prepared, because there will be lots of questions. I'm happy to take them in line as we go. At some point, probably, there'll be too many and we're running late, then I'll cut them off. But feel free to ask questions, you know, expresses disbelief, argue, insult my mother, whatever you wish, during the talk. But do make sure that the insults are on the mic. [LAUGHTER] OK. So people have been programming computers for more than 80 years now. And yet software design is still basically a black art. There's essentially no agreement on how to do software design or even what a good piece of software looks like. You know, we talk a lot about software engineering, and software tools, and testing, and processes. But we have almost no conversation about the fundamental act of designing software. And this has bugged me for a long time. So today, I'd like to tell you about some things I've been doing to try and change that, to start the conversation and to see if we can somehow create a more, a greater, sense of design awareness in the software community. And that consists of a new course I developed at Stanford and then, based on that, a book on software design. OK. So let's start with the basics. If you had to pick one idea, one concept that's the most important thing in all of computer science, one thing that threads through every aspect of computer science from AI to systems to theory, first of all, what would you pick? AUDIENCE: Abstraction. JOHN OUTSERHOUT: Abstraction. AUDIENCE: Testing. JOHN OUTSERHOUT: Sorry? AUDIENCE: Testing. JOHN OUTSERHOUT: Testing. Other ideas? AUDIENCE: Composition. JOHN OUTSERHOUT: Sorry? AUDIENCE: Composition. JOHN OUTSERHOUT: Composition. AUDIENCE: Complexity. JOHN OUTSERHOUT: Sorry? AUDIENCE: Complexity. JOHN OUTSERHOUT: Complexity. So I asked Don Knuth this question. He said, layers of abstraction, which I would say is almost right. [LAUGHTER] Although, some would say, by definition, it's right. What I would say is problem decomposition. How do you take a complicated problem or system and chop it up into pieces that you can build relatively independently? And yet, as far as I know, aside from what you're going to hear today, there is no course anywhere where that concept is one of the most important ideas in the course. We simply don't teach it. Second, we all know that some programmers are way, way more productive than others. Google has coined the term the 10x programmer. And yet, as far as I know, no one attempts to teach these skills either. And these ideas have been sitting in the back of my head and bugging me for a long time. How can we have these things that are so important, and yet we don't really make any attempt to teach people this stuff? You know, if you're a great programmer, somehow you just figure it out on your own. So that leads to the question, can we do this? And there's three questions there. First, is it even possible? You know, is this just a some sort of innate skill that you're born with in your genes, or is it something that can be taught? So first let's do a quick survey. How many of you think this is something that it's, you know, either you have it or you don't? You can't really teach it. It's just an innate skill. A few. How many think that this could be taught in some way or another? Good. A few summers ago, I read a really great book by Geoff Colvin titled "Talent Is Overrated." If you want a fun read, read it. It's a relatively quick read in which he goes through study after study that shows in these fields where we think of some people as being tremendously talented, in fact, the only thing that really differentiates the top performers from the average performers is how much they've practiced. That's the one consistent correlating factor they could find. It's all about practice. So that got me thinking, I mean, I believe it's got to be possible to teach this. But the second thing is, who's going to do it? Well, unfortunately, not most of today's faculty. The problem is the typical faculty member writes a little bit of code as a grad student, never really gets any instruction. You throw out some crappy code for your dissertation, and then you become a professor. And then you decide coding is what graduate students do, so you stop coding. And you never write anymore code. And so, you know, the only way to become a great developer and learn design skills today is with tons of personal experience, sort of trial and error. Faculty don't have that. So they can't teach their students. And so the whole process just continues over and over and over again. But, fortunately, I'm not one of those faculty members. So maybe I have a better chance of doing this. So, personally, I love programming. I mean, programming, it's really one of the top two or three things I live for-- you know, my family, programming-- [LAUGHTER] --really bad golf game. There's a sort of few things [AUDIO OUT] the things that drive my life. But if I don't write 5,000 lines of code a year at least, I feel like it hasn't been a great year for me. So in over my career, I've probably written, I think now, 250,000 to 300,000 lines of code. So I've had a chance to observe a lot. And, again, as I've been doing it, I've been thinking about design stuff. So I thought maybe, you know, if anybody can do it in academia, I probably got about as good a shot as anybody. Then the third question is, well, how do you do it? So I combined all these three things together. I finally decided only one way to find out. I'm just going to have to try it. You know, maybe I'll crash and burn, but I'll give it a try. So I created a new course at Stanford, CS 190 Software Design Studio. It's not taught like a typical [INAUDIBLE] course. It's taught more like the way you learned English writing in high school with an iterative approach. So, you know, the way about writing is you write something. Your teacher marks it up. You get it back again. You rewrite. They marking up again. And so the whole process iterates several times. And it's that process of getting criticism, incorporating the criticism and learning and seeing how that makes things better. That's how you become a good writer. So I thought we'll try the same idea in the class. And so that's the way it works. Now, we only have 10 weeks in a quarter system. So we can only do three iterations of this cycle. But the basic way it works is in the first couple of weeks of the course, students in teams of two build the largest system they can possibly build in three weeks. That's typically about 2,000 to 3,000 lines of code, so, you know, still not a huge system. Then after week three we go into code review phase. Students read each code and write reviews. And I read every single line of code written by all of the students. This is sort of one of the limitations of the class right now. So I end up reading 20,000 to 30,000 lines of code in that week. And then we do code reviews in class where students will present pieces of their project and other students will critique it. And then I do longer code reviews. I read everybody's projects. I typically make 50 to 100 comments on every team. And then I meet with the teams individually for an hour and go over it with them. Then the second phase is they revise based on the code reviews. They actually add a little bit of additional functionality as well in the second phase. We do another round of code reviews. And then the third phase, they get a new project. They start from scratch again. And we finally do a third round of code reviews. And when they do this, the students get no ideas from me about how to design. I just tell them what the system has to do. They have to start from scratch and figure everything out themselves. So they make lots of mistakes in the first phase, but that's part of the learning of the class. Yeah, another question? Mic's coming here. AUDIENCE: I watched your YouTube video on the same topic you gave. And in that one, phase three, it was past the project to person on the left and inherit someone else's code. Why did you change it? JOHN OUTSERHOUT: Yeah. In the first two times I taught the class, I actually scrambled the projects in the third phase and made people add over somebody else's project. That was a good learning experience, but the problem is people end up spending a lot of time decoding other people's projects and being frustrated with it. That has some value, but they don't spend as much time doing real design stuff. And so I finally decided if what I really want is to teach people design, I think they'll learn more if they get to start from scratch and do a new design project. So I changed it. I may change back again. I'll try this for a while and see if it works. OK. So that's the basic idea of the course. Now, you may be wondering, so what are the magic secrets. How do you do software design? And by the way, what makes me think I know what the secrets are? So first of all, I don't claim to know all the answers. I have, you know, some ideas that have kind of coalesced in my mind over the years, which I'm using in the course and the book. I don't claim those are the end. Actually, I'm hoping more to use those to start a discussion of all of them over time. But in the class, there's about sort of 10 high level ideas. They're very abstract, almost philosophical. I can't give you a recipe. You know, follow these 10 steps, and you will produce a great design. I'm not sure that there is such a recipe. So instead, there are these vague ideas that I talk about while students are doing their first round of design. I'm not sure they sink in very well, because they're so abstract. It's probably hard to figure out how to apply them. The way they work best, though, was when we do the code reviews. Then I can show the students how they violated some of these principles and what the consequence was in their code and how they should change it. And then they can go back and apply the principles as they revise. And then I think the ideas start sinking in. So it's sort of a-- question in back, yeah. AUDIENCE: Yeah. I'm curious what you think about how does the sort of end to end principle in sort of software design factor into this in terms of trying to push all the complexity to the edges of the system? JOHN OUTSERHOUT: End to end principle? AUDIENCE: So like the [INAUDIBLE] example of TCP, the checksum, you know, is done end to end. It's not in the intermediate router stages. And that was a design principle that they had. JOHN OUTSERHOUT: I'll have to think about that. I'm not sure that relates in a direct way to this principles, but I'll have to think about that. So there are these vague principles. Then the other thing I try and do is talk about red flags. So red flags are very specific things that, if you see this sort of behavior or pattern, you're probably in trouble. And actually I think for beginners in particular, red flags are really useful to people. Because even if you don't know how to design the right system, if you can see you're going wrong, then just try something else until eventually the red flags go away. And you'll probably end up in a pretty decent place. So red flags are really very useful. So what I'd like to do is I'm going to talk about the four things that are in red just to give you a sense of some of the ideas. Two of them are design principles. Classes should be deep. Define areas out of existence. And two of them are more about mindset. I'll talk about those afterwards. So the first one is this notion that classes should be deep. This is really just another way of thinking about the idea of information hiding David Parnas first put out in a paper in the early 1970s. By the way, to me, this paper is one of the two most important classic papers and all software design and engineering. Has anybody here read this paper in classes? Great. It's still topical and relevant today. The last third maybe not so much so, but the first part's still-- and it's got a great example and easy to read. So the way I think about it, think about a class as a rectangle. And the area of the rectangle is the functionality that class provides. So you can think of that's the benefit that the class provides to the rest of the system. Then think about the top edge as that's the interface to the class. And by interface, I mean everything someone has to have in their mind in order to use that class. It's not just the signatures for the functions, but things like side effects and dependencies and things like that. That's really the cost. You think that that's the complexity cost that this class imposes on the rest of the system. So we'd like that to be as small as possible. So ideally, what you'd like is the greatest cost-- sorry, greatest benefit, least cost. So you'd like the smallest interface and then the largest area. So the opposite of that I call a shallow class. So that's something that has either not a whole lot of functionality or really, really complicated interface or both. Those classes, they just don't give us much leverage against complexity. In fact, in the worst case, in the worst case, the additional overhead of the interface adds more complexity than what you've hidden underneath the interface, and it's a net negative. What we'd like to have, of course, on the other side is a deep class-- very simple interface with a very large amount of functionality underneath it. I mean, that's another way of thinking about abstraction, right? The idea of abstraction is we're trying to provide a simple way of thinking about something that's actually quite complicated underneath. So deep classes are good abstractions. And this notion you can apply it to classes. You can apply it to methods within classes. You can apply it to interfaces in general or modules in a system or subsystems, anything like that that has an interface or an implementation. Yeah, question. AUDIENCE: Is this one of the concepts that you give your students before they start the first project or after? Because it seem important to give at least a few hints at the beginning. JOHN OUTSERHOUT: This is what I give them before-- well, it's concurrent while they're doing the first project. We don't have enough time for me to go through all the ideas before they start designing. So while they're designing, we're talking about this stuff in class. Here's a classical example of a shallow method, which I have to say I see distressingly often. There is essentially no information hiding in this method. In order to use it, you pretty much need to understand the complete implementation. And, by the way, there's almost no implementation there. In fact, this is so bad that it takes more keystrokes to invoke the method than if you had just did the body of the function yourself. So it's basically a complete loss, just adding complexity and getting nothing back for it. Another example, actually, of a relatively shallow class I see all the time is a class for list manipulation. This is very shallow. I mean, lists are really easy to manipulate. It's two pointers. We know the pointers are hiding underneath there someplace anyhow. And so that's a very shallow class. Now, you can't always eliminate shallow classes. You know, sometimes you end up the best you can do is a shallow class. And so I wouldn't say you should never, ever have them. But a shallow class doesn't buy you much from a design standpoint. It doesn't help you in the fight against complexity. AUDIENCE: [INAUDIBLE] AUDIENCE: So I think one thing that is perhaps a bit subtle is that the size of the class is not the amount of code that is in it right now. It might be the amount of code that you eventually have to add or if you have to have multiple implementations of it, right? So maybe this doesn't make sense in isolation, but perhaps there is something else, there is another implementation of it maybe right now or in the future which is going and storing stuff in a database or something like that. And so I kind of wonder if you disagree with that characterization that you need to keep track of the evolution of the class in mind when deciding on its depth. JOHN OUTSERHOUT: Well, I agree with that. In fact, the whole idea behind software design is we're doing things for the future. It's we're doing things today to make it easier for us to develop in the future. And you have to think a little bit ahead. Although, of course, you know the classic problem with software is we can't visualize the future very well. So it's dangerous to try and think too far ahead. But I agree with your concept in general. In this particular case, though, the problem is that the interface is already so specialized that there's just probably not a lot of room for wiggle room under there. Almost certainly anything you change to the implementation is probably also going to change the interface. And so, again, it's probably not going to help you. But, you know, if you have reason to believe it will, well, yeah, sure. So the problem that leads to this-- and by the way, I think this is one of the biggest mistakes people make, too many, too small, too shallow classes. And the reason people do that is because they've been taught classes and methods should be small. How many of you at sometime in some course were taught your method should be small? And how many of you have been given a number, like any method larger than n lines, you should chop it up? How many of you have heard something like that said? OK. Tell me a small value of n you've heard. AUDIENCE: 20. JOHN OUTSERHOUT: 20? [INTERPOSING VOICES] JOHN OUTSERHOUT: Has anybody heard 10? [LAUGHTER] I've heard 10 sometimes. So if you take this to the extreme, this results in what I call classitis. Classitis is when somebody says classes are good and somebody else thought what they heard was more classes are better. [LAUGHTER] And so under classitis, your goal is to have as many small classes as possible where each class adds the tiniest possible amount of new functionality to the previous classes. If you want more functionality than that, make another class for it. Probably the best example of this in the world today is the Java Class Library. There's nothing in the Java language that requires this. But somehow this has just become the culture in the Java world, these tons of little tiny shallow interfaces. Like, for example, the thing that just bugged me about Java when I started programming, if I want to open a file and read serialized objects from it, I have to create three objects for that. First, I have to create this file stream. But for some reason, I don't get buffering. If I want buffering-- it's like, do you want it eat today? [LAUGHTER] If I want buffering, I have to create another object. And then if I want read serialized objects, you add another object on top of that. And each of these can throw exceptions that I have to catch. And then exceptions can come halfway through, and I have to do clean up-- enormous amount of complexity for something that's really, really simple. So I think they lost sight of the idea that, first of all, in managing complexity, the common case matters a lot. You want to make the common case really, really simple. I shouldn't have to do all of this. OK. Maybe I want to be able to not have buffering, but that should be an option that-- you know, if I don't want buffering, that should be where things get more complicated, not to have to remember to ask especially for buffering. So to me, it's not about length. Length is really not the fundamental issues. I don't have problems with methods that are hundreds of lines long if they're relatively clean and if they have a deep interface to them. It's abstraction. That's the most important thing. So rather than striving for length, you should first try and get these deep abstractions. And then if you end up with something that's really big and long, then see if you can chop it up. But depth is more important. So what's an example of a deep interface? My favorite in the world, probably one of the most beautiful interfaces ever invented is that Unix file I/O interface-- five functions, falling over easy interfaces to every function. The only complexity is the flags and the permissions for open are a little bit funky, but everything else is very, very simple. And then think about what's hidden behind this simple interface. There's typically hundreds of thousands of lines of code behind that that do everything from managing disk space to file caching to, you know, device drivers-- enormous amount of code and, of course, many other lower level interfaces behind this, but just this amazingly beautiful five functions. Now, today, people look at this and think, well, duh, of course, that's the way you design things. But it was not like this. Has anybody in this room actually programmed at around the time Unix came out? Only a few of us are old enough to have done that. Things were pretty horrible before then. Like, for example, in pre-Unix file systems, there would be a totally different set of kernel calls if you wanted to open a file for random access versus sequential access-- two different sets kernel calls, different kinds of files. You'd have to declare your file random access or sequential. And Unix just had this amazing the simple interface. So anyhow-- a beautiful example. OK. Let me go to my second design principle, which is define errors out of existence. So we all know that exceptions are a huge source of complexity in systems. For example, in the RAMCloud storage system, we thought we were building a low latency storage system and figured out we'd be spending all of our time making things really fast and low latency. But, in fact, 90% of our time went into doing crash recovery. So they're a huge source of complexity. And, again, the common wisdom kind of leads people astray. You're taught to program defensively, which is good. But people then think, ah, I should be throwing lots of exceptions. The more exceptions I'm throwing, the better defense I'm doing. And as long as I, building my module, catch all the errors and heave them up in the air as exceptions, I don't have to worry about where they land or who's going to deal with them. I've done my job. In fact, the more of them I throw, the better programmer I am. But then that just results in this explosion of exceptions that have to be caught and handled. And then the exceptions themselves create more bugs. And you have secondary exceptions and so on. So I would argue, in general, overall, we should try to minimize the number of places where you have to handle exceptions. You can't completely eliminate it, but try to minimize that. And the best case of all-- which I found you can do surprisingly often-- is simply to redefine the semantics, so that there is no error. There is no exception at all. That's the best. It's just gone completely. So let me give you three examples of that. First one-- when I was designing the Tcl scripting language many years ago, I introduced an unset command, which deletes one and more variables. When I was doing this, I thought-- by the way, this is a classic mistake, people-- I thought why in their right mind would anybody ever delete a variable that doesn't exist? That makes no sense. So I'm going to throw an exception for that. Well, turns out people do that all the time. For example, you're halfway through a computation. You decide you just want to bail. So you want to clean up all the mess you might have made. So you go through and delete every variable that you might have created, but you don't know which ones you actually got around to creating yet. And so some of them don't exist. So in practice, people complain about this all the time. And in fact, if you look at Tcl code, I bet virtually every invocation of the unset command is wrapped in a catch command that will catch the exception and throw it away when it happens. So what I should have done-- in fact, I don't know why I didn't fix it once I found the problem. That was my second mistake. What I should have done was redefine the semantics, so that unset makes a variable not exist. And if you think of it that way, ah, well, if the variable doesn't exist already, we're done, clean, no harm, no foul. So that's what I should have done, should not have thrown that exception. Another example is file deletion. In Windows, at least in the early days, if you tried to delete a file when some process had the file open, that was not allowed. Anybody experienced this? Anybody that have used Windows experience this? It's this horrible thing. And then now you figure, OK, who's got it open? You start going around killing programs to try and make it so you delete the file. And you can't find which program has it open. So finally, you just give up, and you reboot. And then it turns out-- [LAUGHTER] And then it turns out that it's a system daemon that has the file open. So when you reboot, it's still in use. You can't delete. So Unix has a beautiful really lovely solution that makes this error go away. In Unix, if you delete a file while it's open, what happens is it deletes the file from the directory and from the namespace. It no longer appears anywhere in the file system. But the actual contents of the file still hang around, so that any process that's using the file can continue to access the file. And then when the last open instance of the file is closed, then finally it cleans up and throws away everything else. It's a lovely solution. Because you could have made the other mistake, which is that I'm going to delete the file. And now, anybody doing I/O on the file gets an error. That would probably be even worse, because now every program would have to be written to handle the case where the file goes away in the middle of your accessing it. So Unix had this beautiful solution where there's no errors on either side. It just does the right thing. So Windows, they eventually realized this was a problem. And I don't know where they are in the evolution of fixing it. But I know that the first stage they did is they had some special flag you could set that would say, delete the file even if it's open. Or you can maybe when you open the file-- so then you can allow it to be deleted while it's open. But they didn't get rid of the directory entry. They kept the directory entry around. And so you couldn't recreate the file while it was open. So if you were, for example, trying to rebuild and, you know, the binary was in use, you couldn't create a new version of the binary file, because the directory entry was locked down. So they still didn't get it right. So, again-- examples of why you just want to make these errors go away. A third example, which people often consider more controversial when I say this one, is substrings. So in Java, there's various methods that will extract a substring out of a string. And these methods are very exception happy. If either of indices is outside the range of the substring and throws an exception-- and I believe if they're kind of out of order, it throws an exception-- I find this a huge pain. I end up, typically, having to write my own code to effectively clip my indices to the range of the string before I invoke the Java substring command, so I won't get these exceptions. I consider this just a bad idea. Instead, it'd be so much simpler just to find substring, so that it returns the overlap between the indices you've specified and the available contents of the string. So if both of the indices are outside the range of the string, it returns an empty string. You know, if they are in reverse order, clearly there can't be anything in the right order. It doesn't return and just does the clipping automatically. This would eliminate so much extra code people have to write and also, I suspect, a lot of runtime exceptions that occur, because people forgot to clip their indices to the range of the string before they invoke the command. So, again, the overall idea here is to try and reduce the number of places where people have to deal with exceptions. The book talks about a few other ways of doing this. But the best case of all is just to define the exceptions away. Just make the normal behavior always do the right thing. And nobody's objecting on the Java substring. Usually somebody raises their hand and objects to that. Yeah. AUDIENCE: Yeah. So not objecting, but defining [INAUDIBLE] the semantics, perhaps, is a more complete definition. I mean, you could simply say, OK, whatever set of parameters you pass, you have random behavior that are difficult to explain. But the examples you gave were very, very intuitive, like when you defined overlap between the indexes and the available space or the Tcl, et cetera. JOHN OUTSERHOUT: Somebody want to argue that Java substrings should throw exceptions? AUDIENCE: Yeah. [INAUDIBLE] JOHN OUTSERHOUT: Let's bring the microphone over here. AUDIENCE: [INAUDIBLE] JOHN OUTSERHOUT: I know some of you thinking it, so yeah. AUDIENCE: I think it should throw a runtime exception, because, like, you can-- sometimes it could be just the wrong assumptions on client side. Like, they've just done something wrong. And they're assuming that's correct range, but it's not. I think it should be a runtime exception. JOHN OUTSERHOUT: This is part of the philosophy about we're going to try and keep people from making mistakes, which it's kind of a noble thought. But the problem is that it's really hard to keep people from making mistakes. And so typically what happens when we try and do this is we introduce lots of complexity, which makes it hard to even do the right thing. And so I'd argue, in general, we want to make it really, really easy to do the common case and the right thing. You still have to do testing to catch mistakes. And so this isn't going to replace the need for unit tests. But, in general, I think when you try and build systems that can keep people from making mistakes, you usually create a whole lot of complexity for everybody. AUDIENCE: So how do you distinguish between Java substring versus java.string.character@index? Should that throw an exception if the index is out of range? JOHN OUTSERHOUT: Good question. That one probably should, because it can't really return a character. You know, what do you-- you know, you could redefine it kind of like IEEE Floating-Point did, where there were special values that represented arithmetic errors and things like that. So if you have some sort of a null character that you could return, that might make sense. But we really have that in our character sets. So in that case, you really can't. I'm not sure what you would return if you're going to return something. So, yeah, so in that case, you probably do have to throw an exception. AUDIENCE: [INAUDIBLE] AUDIENCE: -optional character. AUDIENCE: So one question-- so when is it a good idea to actually throw exceptions? So the intuitive case is you want to eliminate exceptions as much as possible, then how do you decide, no, there's nothing that I can do? My changing semantics doesn't work. And I really have to throw an exception now. JOHN OUTSERHOUT: Well, if you fundamentally can't carry out your contract with your caller and if you can't implement your interface, then sort of have to throw an exception. You know, like, if you're reading [INAUDIBLE] you're doing a read operation and the read can't succeed, because you got an I/O error, you have to. That's information that you do have to reflect that back to the caller. So you can't eliminate all exceptions. You know, some of the students in the class thought this was really a great idea. And so they basically wrote no exception handlers in their code-- [LAUGHTER] --and said, I'm just defining them out of existence. I said, no, no, some of them actually matter. You have to-- and a lot of software design, I think, is figuring out what matters and what doesn't matter. And, ideally, you'd like to make as little matter as possible. You know, you'd like to be as-- to not depend on very many things. But you have to recognize the things that really are important and do matter. And those you do have to reflect in the system. Yeah. AUDIENCE: Do you have thoughts on exceptions versus extra status code or extra error code return? JOHN OUTSERHOUT: Boy, that's a classic argument, exceptions versus return values. Now, there are times when each make sense. I believe exceptions actually provide the most value when you throw them farthest. If they're going a long way up the stack, that's where they provide the biggest benefit. Because you've made it unnecessary for a whole bunch of intermediate layers to deal with the situation. You can take it all the way back to the source and deal with it at the source. If you are catching exceptions in methods you call, you know, there's not as much value for that compared to just getting a return value. It's not a whole lot different. One of the problems with exceptions is, also, they all have clunky syntax. And, actually, checking a return value is actually simpler syntactically than declaring an exception handler. But, you know, a lot of times, some of these exceptions you really will want them to propagate a long ways. And so then even if the caller is going to look at it, you probably want to manifest it as an exception rather than a return value. AUDIENCE: Any thought on crashing as a way of, like, avoiding [INAUDIBLE],, like, passing [INAUDIBLE]? JOHN OUTSERHOUT: Any thoughts on crashing as a way? AUDIENCE: Yes. JOHN OUTSERHOUT: Yeah, yeah. Actually, crashing is a fine thing to do in certain situations. Like, for example, in most programs, I would argue you should not be trying to [AUDIO OUT] out of memory exceptions. It's just hopelessly complicate to try and do that, because it depends so much on memory. That for most applications, if you run out of memory, just crash. I mean, print a message and crash. It almost never happens. Machines today they have tons of memory anyhow. You know, again, use with caution. But I think there are situations where just crashing is a fine thing, a fine way to do it. The alternative would create so much complexity that you probably wouldn't get it right in the first place and it'd end up crashing anyway. SPEAKER 1: Hey, John, there's 17 questions on the Dory. So I'll just ask the top ranked one, so that we don't run out of time. The question is from [INAUDIBLE].. And in real life, development is often under these constraints-- for example, tight schedule, need to experiment and be flexible about design, lack of mature tools, library, et cetera. Does your approach to software design philosophy change based on the real world constraints? JOHN OUTSERHOUT: Yes. And actually, that's a good lead-in. Let me move on to the next part of the talk, which I'm going to talking about that. And I think I want to get moving, too, because we're starting to run a little tight on time. [AUDIO OUT] about a couple of specific techniques or philosophies you can use. But I think one of the biggest obstacles to good design is mindset. If you don't have the right mindset, you will just never produce a good design. And I think there's two ways of approaching the programming or design process, which I call tactical and strategic. Unfortunately, most people take the wrong approach, which is the tactical approach. In the tactical approach, your goal is to get something working-- you know, your next feature, fixing a bug, whatever. But that's your goal, to get something working. So you think, how can that be wrong? Isn't that the whole goal of, you know, building systems? We want them to be working. Well, the problem with this approach is that when you do it, then you usually have a mindset that, well, I'll try and make it mostly clean. But if I have a little-- if I take a couple of, you know, short cuts or a little bit a kluges, as long as I don't do too many of them, if I get it working, that's what really counts. The problem with that is that those kluges build up really fast. Because not only are you doing it, but everybody else on your team is doing it. And then after a while you start saying, well, I probably shouldn't have made that decision back there, but we've got our next deadline we've got to hit. You know, I'll try and find time after that deadline. But then by the time the deadline is done, you've introduced so many kluges, you realize it's going to take weeks to fix all these. And you don't have time for that. And so it just never happens. So the result of this inevitably is the system turns to spaghetti really, really fast. And the problem is that complexity isn't one mistake you make. It's not a single big thing that makes the system complicated. It's hundreds or thousands of mistakes made by many people over a period of time. And so that means, first of all, you don't notice it as it's happening, because it's just a bit at a time. But then, even worse, once it's happened, it's almost impossible to fix. Because there's no one thing you can go back and fix to fix the problem. It's thousands of things in hundreds of places. And so it's just so overwhelming, you never get to it. So, by the way, there's an extreme of the tactical programmer, sort of personality type, I call the tactical tornado. This is a person who turns out enormous amounts of pretty shoddy code that kind of 80% works at a huge rate and leaves a wake of destruction behind them. [LAUGHTER] And in many organizations, these people are considered heroes. This is who management goes to when we need the new feature for tomorrow. And they'll have a feature tomorrow that works for most of the day tomorrow, anyhow. In fact, actually, when I gave this talk, somebody said, oh, is that what you mean by the 10x programmers? [LAUGHTER] No. No. How many of you feel like you've been in the presence of one or more tactical tornadoes over your career? Yeah. Every organization has them. I'm sure they're here at Google. And, unfortunately, one of the things I hope to do is to provide a name for this, so we can start calling them out and maybe educate management about them. How many of you feel like your management actually rewards technical tornadoes? Yeah, that's even worse, unfortunately. So, you know, the tactical approach is really, really easy to slide into, very hard not to do that. But so the first thing you have to realize, if you want to do great design, you have to realize working code is not enough. That can't be the only goal. It's sort of table stakes. Of course, things have to work. But that shouldn't be the real goal. Instead, you should take what I call a strategic approach where the goal is a great design. That's the most important thing. Yes, it's got to work today, but we have to have a great design. Why do we want a great design? It's so that we can develop fast in the future. So it's really all about investing. We'll invest in good design today, because most of the code we develop is going to be in the future. And so if we mess things up today, we're slowing ourselves down for the future. So you have to think about complexity, try and find ways to drive complexity out of the system. And, fundamentally-- this is the hard part-- you have to sweat the small stuff. And you sort of have to have a zero tolerance approach. Don't let those little bits of lint creep in. Because if they do, then you're going to slide back into a tactical mode again. You know, so if you program strategically, you're going to go slower first. But, presumably, in the end, you'll end up going faster. I mean, even with a strategic approach, you're development will still slow down over time, because complexity is inevitable. We can't prevent it. We can only kind of slow the growth as much as we can. But, eventually, you'll end up [INAUDIBLE] to be faster. So the issue is you have to invest. If you're not willing to take a little bit of extra time today, at least a little bit, you can't do good design. But in my opinion, it all pays back. You always get your investment back. Now, the challenge is what are the parameters of these curves? Like, how much slower do I have to go initially? You know, when do I get to the point where the slopes are the same, so I'm at least now running as fast as I was tactically? When do I actually catch up so I actually have a net gain? And then how much faster I go at the end? Unfortunately, I don't know of any quantitative answers to any of those questions. You know, I have opinions. Like, my opinion is that the crossover period is somewhere in the 6 to 12 month range, roughly how long it takes you to forget about why you wrote that last chunk of code. But I don't have any data to back that up, unfortunately. So that's the challenge. Because, you know, people can see the cost today, but they can't really estimate when the benefit's going to come or how long in the future it's going to be. And so it's really easy just to optimize for this part down here. AUDIENCE: Yeah, just quick question. Have you thought of analyzing open source development and seeing whether or not you can observe this? I mean, it would require some judgment calls, I guess. But-- JOHN OUTSERHOUT: I'm not sure how you do-- you can look at the rate of commits from the new lines added. But the problem is you don't know how much effort went into those. AUDIENCE: Yeah. JOHN OUTSERHOUT: So-- AUDIENCE: I was thinking like when a new storage device comes out and people are writing new file systems or something. You know, you could look at this across different OSs and see how things happen. JOHN OUTSERHOUT: Yeah, that's a thought. It's hard. So the question is, how much do you invest? Actually, let me charge for a couple more slides, because we're starting to run a little tight on time. So how much? What's the right amount to invest? And, you know, if you look at most start-ups, honestly, they're mostly completely, 100%, tactical. They feel a tremendous pressure to get the products out. You know, our financing is going to run out in six months. Whatever evil we put in, you know, when we become famous and wealthy and do out IPO, we'll be able to hire more engineers to clean up this mess. And so, you know, they end up with these horrible spaghetti code bases. And, unfortunately, of course, once you get that, it's pretty much impossible to clean it up. I've never heard of anybody-- maybe if you could go back and completely rewrite, you could do it. Maybe there have been examples of that, but it almost never happens. So to me, Facebook is the poster child for this. They even built it into their company motto-- move quickly and break things. And they did both of those. [LAUGHTER] So now, in a sense, developers kind of like this. So fresh college hires could come in. They're super empowered. They push their first commits, and they're changing the website in one week. The first week on the job feels like, you know, really empowering for them. But their code base was just a notorious mess. One summer, a couple of my graduate students went there for internships. They came back, and they just couldn't believe what they'd seen. And this was interesting, because my students had been whining for the whole previous year about why do we have to write unit tests and write documentation. Linux doesn't have any unit tests. And Linux doesn't have any comments. Why do we have to do this? I never heard that again after they came back from Facebook. [LAUGHTER] So Facebook has eventually realized this. And so they changed their motto to "move quickly with solid infrastructure." It's like, you know, no, no, I meant to say wouldn't, not would. [LAUGHTER] So have they been able to fix it? I don't know. Now, people hear this, they say, well, yeah, but Mark Zuckerberg is the fourth wealthiest person on the planet. How can this be a bad approach? And, of course, the answer is, you know, you can be successful with crappy code. You can be tactical and build companies that succeed. Facebook has done it. But I have two thoughts on this. One is you can also succeed with the other approach. And although, I don't have personal experience with either of these companies, my sense is that both Google and VMware took a much more, sort of, stronger design culture approach at least particularly in the early years, you know, 2000 to 2010. Those were the two companies known in Silicon Valley as this is where the really great software developers go. They really care about design. And they do really good coding. And the reason this matters is that if you have that culture, I think you're in a much better position to recruit the best programmers. And we know about this 10x phenomenon. You know, the best way to get great products out fast is to get the best programmers. And so I think the strongest argument in favor of a good design culture is that it allows you to hire top people. And that will give you an advantage. So you can do things the crappy way if you want, but there's enough success stories to show that you can make this work. You can do the investment approach. OK. But then again, OK, but how much to invest? I would say how much can you afford? You know, just ask yourself what's the most we can afford at this stage in our lifetime to invest. I think in terms of maybe 10% or 20%, something like that. I bet, almost everybody, you can afford to go 10% slower today realizing you're going to get it all back. It's not a sunk cost. It's all coming back to you. In somewhere, you know, six months to a few years, you're going to get it all back again. You can afford to do that. And I think in terms of small steps, not heroics. You know, you can't spend six months and completely design the whole system, you know, from first principles before you write any code. That doesn't work. We know one of the problems of software is we can't visualize the way our systems are going to turn out. You have to use a somewhat iterative approach. So I'd say, think of it in terms of small steps. So when you're building new modules, take a little bit of time to design the interface. Try to come up with deep classes. Write the documentation as you're going, unit tests, of course. And then whenever you make changes, you have to realize you can't get it right the first time. It's one of the rules of software. We just can't. So assume every time you're in a system, you're going to have to be improving things. Always look for something you can make better. One reason for this is you're probably making something worse when you go in also. So even if you just want to break even, you've got to find something to improve. So I just think that I'm just trying to at least break even. So this is against the normal philosophy. I think, oftentimes, when people are changing existing code, they go for what's the smallest number of lines of code I can possibly change to do this. I think sometimes it's because they're afraid. I don't understand this. I'm going to break something, so I'll make the fewest lines of change. So I'll just kind of directly access a global variable, another file, rather than trying to find a clean interface for it. So don't do that. Try and find a clean way of doing things. And ideally, in the best case, you'd like to end up where you would have ended up if you had built the whole system from scratch knowing what you know today. That's what you're like. Is this the way we would have done it if we had built it from scratch? That's the ideal. Now, you know, you can't always do that. Sometimes that would be a refactoring that's way beyond the scale of what you can do. So, again, I would just say ask yourself at any given point in time, am I doing the most I possibly can? Don't just give in and the boss says we've got to get a release out tomorrow, so I'm just going to hack this thing in to make the boss happy. Ask, is this the best I can possibly do? Yeah. AUDIENCE: John, will you touch on layering, which is often considered very good in software engineering, but it also has a challenge of performance of the code when it executes? Often, the functionality is replicated in multiple layers. And it's not clear how to distill that without mucking up the code. JOHN OUTSERHOUT: So is your question, are the layers good? AUDIENCE: Yeah. So how do [AUDIO OUT] deal with layers, the demand for abstraction layers, and the demand for performance both contradicting each other here? JOHN OUTSERHOUT: We need layers for managing complexity. So in that sense, they're good. They do have problems for performance. I think people do too many layers. And so I think that's a common mistake is just to throw in lots of skinny layers, again, rather than having a smaller number of meatier layers. That's one problem. The other thing is that for cases where performance matters, if you think a little bit about what your key performance metrics are, I believe you can often define your layers in a way that allows you to achieve very high performance even with layering. But you have to be thinking a little bit about sort of this, the overall, kind of gross level performance metrics while you're doing your system design. OK. So anyhow, I think this investment thing is the biggest challenge, particularly because a lot of managers, I think, don't really get it. And they're sort of pushing for the next feature or the next release. I don't know how to combat that except to have the people that everybody recognizes of the great engineers in the company go to management and try and get management buy in. And I think it'd be great if companies can have sort of explicit-- this is in our engineering philosophy. We will invest at 10% [INAUDIBLE].. Roughly, on average, 10% of our resources are going towards making designs better, not just cranking out next features. Yeah, John. AUDIENCE: Hi, John. I haven't looked at this for 20 years now, but the quantitative analyzes that you're describing were the domain of the social engineering community for a while. I'm wondering if you sort of poked into that space to see if they have experimentation, numbers, analyzes, that might be useful. Or have they just dropped off the map? JOHN OUTSERHOUT: I haven't looked very carefully, partly because I'm sort of skeptical that it is possible to measure it in a meaningful way. So I haven't-- but I would [AUDIO OUT] see numbers if there were [AUDIO OUT] were believable. But I haven't looked enough to know. OK. So I just have a couple more slides, then I'll open it up for questions. So is the course working? You know, it's hard to tell for sure. I mean, you can't become a great programmer in one quarter. It'll take, still, lots of experience for these people. We'll have to come back and ask them once they've been out at industry a while. This is just sort of the first step in the process I think. But the class has a really fun energy to it, really fun. The students start off in the first round of code reviews. And they're very tentative, kind of afraid to criticize each other, not really sure what they should be saying. So the first round's kind of tentative. Then they meet with me, and they get unloaded on. And then they start-- oh, OK, I can do that, too. And so about halfway through the second code review, typically the tone of discussions changes where students are now being more critical of each other. We have these interesting arguments in class about whether one approach is more complicated than another. And it's really clear by the end of the quarter that the students are thinking about programming in a very different way than they thought about it before. So I think that's really encouraging. I will have to say, though, even if the students don't become better designers, actually, I'm becoming a better designer from teaching the class. It's really interesting for me. You know, you might think it's tedious reading 20,000 lines of code in a week three times over a quarter. And it does take some time. But, actually, I learn a lot from that, because the students are all doing the same thing in the same language. And so I can see different approaches. And I can see kind of common mistakes that they make. And, actually, what's ended up happening is I've changed my view about a couple of the design issues as a result of teaching the course. And in particular, the one at the bottom of this slide was I realized that making classes just slightly general purpose, even though you're only going to use them in one place, actually makes the amazingly simpler and deeper. I hadn't realized that until I saw some student projects, actually, the second time I was teaching the course. So it's been really interesting for me to see this. And I feel like I'm learning more about the process of software design and getting better ideas for how to teach it as I go. Then as I've talked to people about the course, people kept saying, well, you should write a book on this. And I was on sabbatical last year, so I decided, OK, I would do that. So I have written this book. It's a relatively small book, 170 pages, again, still fairly philosophical in nature more than prescriptive. So the hope is that I can reach more people, because I can only teach 20 people a year in the class. I can't do more than that. And ideally, I'm hoping the book will kind of be a lightning rod that maybe we can kick start a discussion. I hope people write to me and disagree with things in the book or suggest other design ideas or provide better examples. I'm also trying to define terms that people can use. One of the things I hope maybe the book can do is people can use that in design reviews to have ideas and ways of talking about design and design ideas. Actually, I have a question for you. How many people here do design reviews? I assume almost everybody. And how many of you in your design reviews it's common for you to discuss design issues as opposed to coding style and bugs? How many of you commonly talk about design things? Good. Great. I'd like to see more of that. So now the book's been out for a couple of months. If you read it and have thoughts or comments, I'd love to get your input on it. My view is this is just a first stab. If this actually ends up being a useful book, it'll probably be-- it's kind of like software. At about version three, you know, where it really hits its stride, I'll need to get feedback and revise and fix things that are wrong and add new ideas. So just to conclude, I really believe we can teach software design. I really believe we can. My current approach, unfortunately, is woefully non-scalable. I haven't figured that out. I really need somebody with a lot of experience I think reading the student's code. I feel like some principles are emerging. You know, if you read the book and agree or disagree with me, I'd be curious to hear your take on that. What I hope to do in the future is just to somehow leverage this out into the community. I'd love to see just a greater sense of design awareness in the software community as a whole can we have a discussion. We make an important part of our community it's just sad that we don't really even have discussion today. So I created a mailing list for discussion topics about the book. Hasn't been much traffic on it so far, but I hope there will be more in the future. And, again, I hope to take ideas from people and make the book better and better and the class better over time. And the long-term goal is it'd be great if, 5 or 10 years from now, we actually have a relatively robust set of principles that most developers agree are good for software design. So thanks for your attention, and I'd be happy to take more questions. [APPLAUSE] SPEAKER 1: So let me get a few questions from the Dory out here. Do testing considerations, like unit testing or marks, influence interfaces and abstractions? JOHN OUTSERHOUT: Testing considerations-- I'm a huge fan of, particularly, unit tests-- crucially important. I have debated whether to try and teach them in the class. Actually, I did a little bit at one time in the class, but it was just too much of a distraction for the class. We only have 10 weeks. And so I finally decided, for the class, I just got to focus on design. So I don't do unit testing in the class. But I'm a complete advocate of unit tests. I can't imagine doing software without unit tests. AUDIENCE: So I was intrigued by the first part of the discussion when you said in the iterative process you actually dropped-- you initially had students build on other students code. To me, that's a very, very real world problem. And I'm just surprised that you-- I mean, I wish you would teach that. JOHN OUTSERHOUT: You know, I agree with you. In a perfect world, that would do one of the things we do. The problem is we've got 10 weeks. How do I use that 10 weeks? And I decided I want to try and do the most I can on design. And so I have to sacrifice other things. It's the same reason why unit testing got thrown out, because I felt like it was better for them to be thinking about more design issues than unit testing issues. But I agree with your thought completely. Yeah. AUDIENCE: Do you have TAs for the course? JOHN OUTSERHOUT: Do we have TAs? Yeah, me. [LAUGHTER] Not right now. Because I just worry that the TAs would not be able to give high enough level of feedback. I've started wondering if maybe students who have taken the course previously could TA. So far, actually, the demand has not been more than my capacity. And so I've been able to keep it small. If the demand grows, I may try an experiment to see if previous course participants can TA. But, again, I worry. Also, for the first few offerings, I wanted to read all the code myself, too, because I wanted to learn from it as well. AUDIENCE: Have you thought about using software engineers as TAs? We read and write code every day. [LAUGHTER] JOHN OUTSERHOUT: I'm not opposed to it in principle. But I'd want to make sure students don't get mixed messages. And so particularly because the ideas I'm teaching in the course are not ideas that are not necessarily widely spread in the community. Like the worst thing would happened is if a software engineer comes in and says, no, this method is longer than 20 lines. You've got to break it up. So if I could find people that are sort of bought into the philosophy-- and maybe, you know, the book gets out there and more people buy in, maybe we can do more of that. SPEAKER 1: OK. One question from the Dory, the second highest rate one-- are threads still a bad idea? [LAUGHTER] JOHN OUTSERHOUT: You know, one of the interesting things when the only form in which you publish something is a set of slides rather than a paper-- which that was. It was just an invited talking at a [INAUDIBLE] conference a long time ago. It's interesting. People can come back and interpret that in whole bunches of different ways over the years. So that was done in a very narrow context of the time where people were starting to introduce threads for things that didn't even need threads. They were doing threading on machines that didn't even have multiple processors on them. And so that talk was a reaction to that. Threads are unavoidable. I mean, for certain things, you just have to use them. But they're still sort of the next to worst alternative where the worst alternative may be, in some cases, not using threads-- incredibly hard to program. So I'm still not a fan of threads, but they're kind of a fact of life. Yeah. AUDIENCE: I have a question on Tcl language. I think the language is sort of very simple in itself, but eventually not gained, like, larger scope of adoption. I want to ask, because you are the language inventor, is your like high level issues in the language of design you saying you got it wrong, which makes it-- JOHN OUTSERHOUT: What even happened to Tcl, I think, would be your question. I don't want to diverge too much from that. I would say two things. First, one of the things Tcl was best at was doing kind of simple interactive GUIs with Tk. And when the web came along, the web basically took that over and Tcl did not make the transition to the web. So a lot of things people would have used Tcl Tk for, they end up doing in the web. The second thing is, is it really with the right language? I'm not sure, in retrospect, that it's the right language. Actually, I built it for a very different purpose. I built it as more of a textual command language that you'd be typing commands to programs, almost like a shell language. And then it ended up getting used as a scripting language. It has a bunch of interesting properties. But I don't know, if I were doing it again, I'm not sure I would design the same language. But I think that the biggest thing that happened is kind of the web came along and Tcl did not effectively make the transition to the web. SPEAKER 1: OK. So there's a lot of really interesting questions both on the Dory and in the room. In the interest of time, I'm going to do two more Dory questions and two more in the room. And then John is going to stay around and hopefully answer more questions as well. OK. So any thoughts on the hiring process based on what you've observed? And the question has, how would you change the hiring process which is so algorithm heavy? Can you share your experience when you ran your company? JOHN OUTSERHOUT: Hiring process, actually, I'm not sure it relates to software design. But I have a very strong opinion about hiring process, which is you should hire for slope, not y-intercept. I think people, when they hire, they do a pattern match of what this person has done, try and find the person who has exactly done the job we want to do. I think that's the wrong way to hire in general. I think you want to hire the person who's the fastest learner, who has the fastest slope. I don't particularly care whether they've done the job I want to do. Because particularly at a startup, when things change so rapidly, you know, things change. So I look for people who are really smart fast learners rather. Also, by the way, the person who has done this job five times before, you sort of wonder, well, you know, why haven't they moved on to the next job? Oftentimes, those people kind of hit their plateau. Whereas, the person with the rapid slope, has the potential. AUDIENCE: OK. JOHN OUTSERHOUT: That's my [INAUDIBLE].. SPEAKER 1: Last question from the Dory-- what do you think about Hyrum's Law? JOHN OUTSERHOUT: Sorry, remind what Hyrum's Law is? SPEAKER 1: It's a-- I googled it and it says with a sufficient number of uses of an API, it does not matter what you promise in the contract. All observable behaviors of your system will be depended on by somebody. [LAUGHTER] JOHN OUTSERHOUT: I think there's truth to that, that, yeah, over time what happens is the, sort of, application, they find every crevice and sink their roots under that. They will discover. So unless you're very careful with your APIs, I think that's probably true-- sad, but true. Yeah. AUDIENCE: Hi. Have you observed any change in the simplicity or the complexity of a software design based on the choice of languages and support ecosystem? JOHN OUTSERHOUT: Oh, a good question. There's some languages somehow lend themselves to better design than other languages. You know, there probably are-- I think that's mostly a secondary, sort of second order thing. But, for example, today, I'd rather program in C++ than C, because I liked some of the object oriented features in C++. Now, C++ is sort of a big beast of a language with a horrible learning curve, but I appreciate the power of it. But, honestly, I think the design principles are fairly universal. You can use them in any language. You know, that simple file system interface for Unix was done in C with no object oriented stuff. And then people would say, oh, no, actually, you notice it's actually object oriented, because there's a file descriptor that gets passed around. And the object oriented was really crucial to that. I say, no, they just found a really sweet interface. So I haven't found one language that somehow was dramatically better than others for design. But if people have opinions, I'd be curious to hear other opinions about that. SPEAKER 1: So back to hiring, you mentioned we should hire on slope, not on y-intercept. And I radically agree. How do I estimate the slope? JOHN OUTSERHOUT: How do measure that? SPEAKER 1: Right? Especially, like-- JOHN OUTSERHOUT: I have no idea. SPEAKER 1: --you need at least two points, right? In an interview, I get only one. And I am terrified of hiring more tactical tornadoes. [LAUGHTER] JOHN OUTSERHOUT: I don't know. You know, so I'll tell you what correlated best for me, but it's sort of crazy is that I found in my experienced people who worked out best were the ones where I just really enjoyed my conversation with them during the interview. And that's sort of weird. I feel kind of funny saying that, because that means somehow somebody sucked up to me. And I liked them and hired them. I don't think that's it because I have a pretty sensitive meter for suck-upness. And that really pisses me off. And people have also pointed, if you take that edge, that's kind of a risk that you're just hiring more people like yourself. And so you're not going to do diversity very well. So I have no idea what to make of that or whether it's even a good idea. But that's the one thing that seemed to correlate in my experience. SPEAKER 1: OK. Yeah. So let's thank John once again now. [APPLAUSE]
Info
Channel: Talks at Google
Views: 139,508
Rating: 4.9453735 out of 5
Keywords: talks at google, ted talks, inspirational talks, educational talks, A Philosophy of Software Design, John Ousterhout, the philosophy of Software design, Software design philosophy, understanding software design philosophy, Computer Science
Id: bmSAYlu0NcY
Channel Id: undefined
Length: 61min 40sec (3700 seconds)
Published: Wed Aug 01 2018
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.