YouTube Developers Liv ode Simplicity with Max Kanat-Alexander



[MUSIC PLAYING] JAREK WILKIEWIC ello, and welcome to YouTube Develops Live. My name is Jarek Wilkiewicz, and as always, we have a very exciting show for you today. I am honored to introduce my guest today, Max Kanat-Alexander. How are you doing, Max? MAX KANAT-ALEXANDE reat. Thanks, Jarek. JAREK WILKIEWIC nd Max will talk about code simplicity. You might know that he's the author of a book named aptly "Code Simplicity," published by O'Reilly. When did the book come out? MAX KANAT-ALEXANDE ast April. JAREK WILKIEWIC K, great. So if you haven't read the book, today Max will give you an overview of what it is about. And hopefully, you will be able to learn more after this talk, and reach out and get the book to get the details. So let's talk a little bit about you, Max. So can you tell me what got you into software in the first place? MAX KANAT-ALEXANDE eah, sure. I think that it started when I was younger. And I think like a lot of programmers, probably when I was in elementary school, they sat me down in front of a machine with Logo. JAREK WILKIEWIC remember Logo. MAX KANAT-ALEXANDE eah. Most programmers that I talk to, actually they started either with Logo or with HyperCard, because it was a system that allowed you to immediately see the results of your work. And I think, to this day, for most programmers, the magic of programming is asking the computer to do something and then seeing it actually happen. And I, to this day think, that's actually a really important experience for brand new programmers to have. If you load them down for their very first experience with a bunch of theory and don't let them actually accomplish something or give them very complex tools to start off with, then people don't become as interested in programming. But when you give somebody that little turtle and you just be like, hey, here's some commands you can use to move the turtle around the screen and it draws lines. Then you're like, oh my gosh, this is magical. Then people suddenly interested in being programmers. JAREK WILKIEWIC ool. So it looks like got into software because of a turtle. MAX KANAT-ALEXANDE eah, I think so. JAREK WILKIEWIC o tell me more about-- what do you do at YouTube? MAX KANAT-ALEXANDE ure. So I am the technical lead for developer productivity, which means that I am in charge of the tools that the developers use internally. I'm in charge of promoting best practices throughout the organization. And basically, just unblocking people. In a technical sense, making sure that everything is happy and that code is simple and easy to work with, and those sorts of things. JAREK WILKIEWIC K. So in a nutshell, making sure that YouTube will work as advertised? MAX KANAT-ALEXANDE es. Or at least making sure that YouTube will work as advertised in the future. JAREK WILKIEWIC K. Yeah, I know this is a great segue to your presentation, because I know that you're talking about the future value of the software and the maintenance and so forth. So let's transition into the more formal part of this presentation today. And I'll hand it over to you. And tell us more about code simplicity. MAX KANAT-ALEXANDE ure. Great. So first, let me give a little bit more overview of who I am so everybody understands. Like I said, I'm the technical lead for development productivity at YouTube. I used to be the chief architect of a particular piece of open source software called Bugzilla, which I spent many years refactoring. It used to have a very bad code base. And it was a code base, which actually, everybody had to see because everybody wants to customize their bug tracking system. So it wasn't just the developers who were being affected by the bad code base, but it was actually a lot of our users because they actually had to modify the code, unlike many products. And I wrote a book called "Code Simplicity." I also have a blog by the same name at that domain name, codesimplicity.com. And I have a lot of other things. And there's a link to my personal website there on the slide. And today, I'm going to be talking about software. And in particular, I'm going to be talking about the laws of software, and basically fundamental principles that we can use to make good decisions about software. So one of the problems that we have today is that software development is really complex. When I talk to most programmers, the systems that they're doing with are very complex systems. And so many people feel like that's just the way that life is in the world of software development because it's so pervasive. Well, it doesn't actually have to be that way. There are projects that aren't complex, which sort of disproves this theory that that's just the way it is. And I did a lot of research into why this was happening for people. And what I discovered is that the fundamental underlying reasons have to do with understanding. Particularly, understanding how to make decisions, what principles to follow. And the more junior an engineer is, the harder it is for them to know-- how do I know that this decision is the right decision? And the reason that that's hard is because in the field of software engineering, most of our most important lessons are learned through experience. And that means that not everybody has all the experience. And particularly, the newer you are, the less experience you have. And since there's always new people coming into the field, there's always a lot of IT people with not enough experience to make decisions who have to make decisions. Because that's basically one of your most important jobs as a programmer, is to make decisions. And even if you're an experienced programmer, you might not have all of the experience required to make the right decisions for every situation because your experience might not have covered that situation. So you might still be new in something. And also, not everybody has the same vocabulary. If we want to talk about these concepts, we need words to share. We need ideas that we can agree on. A couple years ago, the idea of technical debt, for example, became very popular and widespread. And before that, we didn't have a word for that. And when people didn't have a word for that, it was much, much harder for them to talk about. But now it's easy for everyone to talk about. And particularly, it's easy for technical people to communicate to nontechnical managers about why they need to do the work that they're trying to do to improve code quality. And that's what I want to have people be able to do is to be able to talk about why they're doing what they're doing in an intelligent way. Because once you can communicate about it, you can get team agreement on it, and you can actually make progress forward. So my solution to this problem was to come up with something that I called the laws of software design, which are basically the most fundamental or most important facts about software. And today, I'm just going to give a real whirlwind tour. Obviously, there's a whole book on this subject, which is my book, "Code Simplicity." And I'm just going to touch on it really lightly, and the book goes into it in much more detail. So one of the things that people tell me after I read them some of these things is they say, well, that was obvious. I already knew a lot of those things. Well, that might be true. But what matters here is that there's a sea of data in the field of software engineering. There's all kinds of opinions. There's all kinds of information. And what matters is that we pick out the most important pieces and we recognize that those are the pieces that we use to judge our decisions against. Because otherwise there's lots of conflicting data. There's lots of different ways we can make decisions. We need to know what the most important information is, so that we can use those to judge other information. That's why you need a structure of information, so that you can use the senior information to judge the more junior information. And when people tell me that this is obvious-- so, just for a second, like off the top of your head, could you list the five or six most important facts about software engineering? Just think about that for a second. I'll give you a couple seconds. That's hard, right? It's hard to just pick out-- like, oh my gosh, off the top my head, what are the five most important things that I know? And also, as I mentioned before, we need to be able to communicate these ideas to other developers. So even if we kind of inherently or instinctively knew some of these things, it's very hard for a lot of us to put them into words, and thus explain them to more junior developers or explain them to our managers. And if we can't do that, we can't make progress forward because software development in the real world is mostly a team activity. JAREK WILKIEWIC o I have a question about the last point you made. You're saying that we need to be able to communicate the ideas and communicate about the idea. So can you explain what the difference is? MAX KANAT-ALEXANDE ure. There's not really a lot of difference, but-- the ideas themselves are the laws. And then communicating about the ideas would be like, well, how are we going to use these in our day-to-day work? So we're going to dive right into it. And our first principle is what I call the purpose of software. And this is not exactly a law. The book talks about the definition that I'm using for these words, which is slightly different than the traditional definitions that people have for these words. Basically, I'm very much opposed to inventing new words, so I just tend to take existing words and use them in ways that are valid in English, but which people are not necessarily always as familiar with. But this is not a law. This is sort of a guiding principle. When you have a science or a way of looking at data, you need a way to know that- you need to know what you're accomplishing. You need to have a guideline by which you can judge whether or not your laws are accomplishing what you're trying to do. You need a purpose. You need to know where you're going. And then you can say, this science or this study is valid because it accomplishes this purpose. And that's more or less the only way to validate many of these things. Particularly in something that's almost a social science, like software engineering. And I looked around for a very long time for a phrase that I thought would encompass the purpose of all software. And I found one that I have not been able to disprove yet. And that is that software exists to help people.1 Sometimes people come up to me immediately after I say this1 and they're like, well, what about viruses?1 Well, viruses do exist to help people.1 They just exist to help different people than you'd1 think, or help people in different1 ways than you'd think.1 When you talked to virus writers--1 I remember reading an interview with a virus writer1 many years ago.1 And he said, I'm trying to help people realize1 how stupid they are.1 Or, how much more careful they should1 be with their computers.1 Or sometimes, if they're virus writers for a government or1 for an intelligence organization, then they're1 helping that government or they're helping the1 intelligence organization.1 And so there's definitely a subjective aspect to this.1 But what's most important here is that software is not1 written to help the computer.1 Even if you're writing libraries, you're writing1 those libraries to help other programmers,1 not to help the computer.1 Even network stack stuff is there to help1 somebody, some person.1 It's not there to help the computer.1 And I mentioned there's a subjective component to this,1 but I would like to encourage people to be more1 objective about it.1 To look at, how do you actually help people on the1 broad scale?1 How do you help people across the world?1 How do you help people in your organization or in other1 organizations?1 And then also, how do you help yourself?1 I mean, that is valid.1 It might be a little less important on the scale, but1 it's still an important fact.1 And part of the subjective component is that the word1 "help--" like, what is helpful to1 different people is different.1 But the word has a dictionary definition, and it means to1 make it easier for a person to do something, often to do part1 of the work of a person.1 That is, more or less, straight out of the Webster's1 Third New International Dictionary.1 And this is also useful because you can state the1 specific purpose for your software by picking the group1 of people you're trying to help.1 And then, what you're trying to help them do.1 So for example, if I write a piece of accounting software1 for accountants and it's designed to help accountants1 do taxes for others, then I can just say the purpose of my1 software is to help accountants do taxes.1 And one of the nice things about this is it allows us to1 very specifically state what the focus of our system is.1 And more focused systems are usually1 better for their users.1 It also allows us to rank features, so we can be like,1 hey, this feature helps accountants do taxes more than1 other features.1 It gives us a guideline against which we can actually1 use to make these judgments.1 JAREK WILKIEWIC o the manifestation of that would be1 some sort of a human-centric design?1 And I think, to a certain extent, use cases or1 contextual design falls into that category, where you1 actually have somebody in mind when you're1 building it, right?1 MAX KANAT-ALEXANDE eah.1 I think it's important many times to not have just one1 person in mind, because you're trying to help a1 whole group of people.1 And so I've occasionally seen this model fall flat if people1 try to do too much categorization of their users.1 But I think some categorization of your users1 is good, as long as you either try to find a set of1 categories that are broad enough that they cover1 everyone or you recognize that you're not covering everyone1 and that ultimately, the purpose is to help the whole1 group of people.1 JAREK WILKIEWIC ure.1 That's the purpose of personas, right?1 This is what people use personas for?1 MAX KANAT-ALEXANDE eah, exactly.1 And I've seen people misuse personas in these cases.1 And so I always want to be careful when people are using1 personas that they're using them intelligently, because1 that's what makes them valuable.1 1 So now we get into our first law, and this first law is1 something that I call the equation of software design.1 And it basically states that the desirability of any change1 is directly proportional to the value of the change, which1 is how much it helps people, our previous law, versus the1 effort involved in making the change, which is just the1 total time that it takes to make the change, including all1 the work that you have to do-- bug tracking,1 everything like that.1 And what we can use this for is we can1 use it to rank decisions.1 In the field of software design, there's no absolutely1 right or absolutely wrong decisions.1 There's only decisions that are1 better than other decisions.1 And eventually, sometimes you get to the point where there1 are two or three decisions that are all equally good.1 But usually, then you're in a good state.1 As long as you've eliminated all the bad decisions and you1 have a bunch of different decisions that are good that1 you can pick between, I'm happy for you1 to have that problem.1 1 Although, however, this is the overly simplistic version of1 the equation.1 Because really, in reality, desirability and software has1 a time component to it.1 We maintain systems over time.1 So the full version of the equation looks like this.1 It says that the desirability of any particular change is1 proportional to the sum of the value now plus the future1 value and inversely proportional to the effort of1 implementation plus the effort of maintenance.1 Now, one thing that we can look at here-- and what I mean1 by value now is I mean the value basically right when you1 release it, or right when it hits the user.1 It depends, but you'll have a sense for yourself of when the1 now is versus when the future is.1 And the effort of implementation is all the1 effort that it took to get to the value now, the immediate1 value of the system.1 And like I said, usually that's when1 it's released to users.1 First is future--1 and those are both constants.1 So the value now and the effort of1 implementation are constants.1 And the value in the future is a function of time.1 And the effort of maintenance is a function of time.1 And software tends to have very long time lines, which1 means that, in general, we tend to be looking at the1 limit of this equation as time goes on, or time approaches1 infinity for those of us who did calculus, which is a lot1 of programmers.1 And so what happens is the equation actually reduces at1 the limit to the desirability of any particular change being1 proportional to the future value and inversely1 proportional to its effort of maintenance only.1 That the constants drop away as you go into the future.1 And I think that this is something that people often1 forget when they're very caught up in the effort of1 implementation, because there's a lot of effort in1 implementation and the effort of maintenance in the future1 is not yet realized.1 You don't see it yet.1 But it's there and it's usually much more important.1 Particularly because when you make changes to your system,1 you're influencing the maintenance of other parts of1 your system.1 So you're increasing the maintenance of the overall1 system and you're making everything less desirable as1 you add more and more maintenance in the future.1 So it's important for us to think now about how we reduce1 future maintenance.1 JAREK WILKIEWIC ne question about this equation.1 So you were talking earlier about technical debt.1 So how does technical debt picture into this?1 Does it increase the em right off the bat?1 How does it work?1 MAX KANAT-ALEXANDE hat's pretty much1 exactly what it does.1 So a good guideline is that you can accumulate technical1 debt for about three weeks without it affecting you.1 And then, about three weeks into it, the technical debt1 that you incurred three weeks ago will actually start1 slowing you down so much that it wasn't worth incurring the1 technical debt.1 JAREK WILKIEWIC nteresting.1 MAX KANAT-ALEXANDE eah.1 And that is what you're doing, you're increasing the effort1 of maintenance.1 And our goal as software designers, if we talk about1 the field of software design as a sort of a subset of1 software engineering, is to avoid situations where the1 future value becomes outweighed by the effort of1 maintenance.1 The idea is that the future value of any change you make1 increases and increases and increases, and the effort of1 maintenance decreases.1 That's the ideal, but any situation in which the future1 value increases faster than the effort--1 they could both go up.1 As long as the future value is getting bigger and bigger and1 bigger, you're fine.1 But what this tells us most importantly is that it's more1 important to reduce the effort of maintenance than it is to1 reduce the effort of implementation.1 That if you have to do sort of a balancing of work, you want1 to do more work at implementation time if that1 means less work at maintenance time.1 However, there's definitely some catches to that.1 You don't want to add a lot of complexity to the system in1 order to sort of handle future maintenance that you don't1 know whether it's going to be necessary or not.1 And we're going to get into that.1 JAREK WILKIEWIC his is very difficult to do, though.1 MAX KANAT-ALEXANDE es.1 This is very difficult to do.1 Although, I have some guidelines that I think--1 JAREK WILKIEWIC ou're going to show us how to do it?1 MAX KANAT-ALEXANDE eah.1 This is my goal.1 JAREK WILKIEWIC ooking forward to it.1 MAX KANAT-ALEXANDE eah.1 Now, one thing though, to know about the future, is that it's1 very hard to predict.1 Like I said, software has very long time lines.1 Even things that you expect to live for a very short period1 of time are likely to live for months or years.1 And that the farther things get into the future, the1 harder and harder it is to predict.1 And as a result, any time that you start predicting the1 future, you have a chance of being wrong.1 Any time you start making a decision now based on the1 specifics of something you think will happen in the1 future, there's a reasonable chance you'll be wrong.1 Most people, they know what they're1 going to have for lunch.1 And maybe they have some sense of when they're going to be1 leaving work.1 But if you think about all the times that you were wrong1 about when you were going to leave work, you can realize1 that it doesn't have to be a very long time horizon before1 your predictions start becoming relatively1 inaccurate.1 And since we're designing these systems where our future1 is really important, it's important that we don't make1 inaccurate statements about the future.1 One of the most disastrous errors that programmers make1 is making some statement about the future when, in fact, you1 can't know that.1 When you act as though you can know, when really you can't.1 For example, people say, we will never have1 to reuse this code.1 You don't know that.1 You might be right, you might be wrong.1 People might say, well, we'll never have to handle any other1 input to this method than what it's getting now, or input to1 this class than what it's getting now.1 Well, you might be right, you might be wrong.1 And sometimes you do have to make assumptions.1 For example, with internationalization, it can1 be very hard to bolt that on later.1 But you have to be aware that what you're doing is an1 assumption.1 And you have to make it in some way that it doesn't block you in for the future. It doesn't cause your future to become unchangeable or inflexible because you could be wrong. You always have to sort of hedge your bets. For example, with internationalization frameworks, what I tell people is you might start off only need the thing in English. So just try to use internationalization framework that adds very, very little complexity to the system. And we're going to get into why that is a little bit more later. But that will basically make sure that you're not going to box yourself in. What I recommend to developers is that-- and this is going to sound a little contradictory and I'm going to get into this resolution of the contradiction, is that you don't make specific predictions about the future. Instead, what you should do is you should understand the principles of software design and use those principles and the rules and best practices to understand how you can make decisions now that will lead to a good future no matter what happens. I told you at the beginning for the equation of software design, I said the most important thing is the effort of maintenance and the future value, which is all about the future. And then I told you, but really, don't make decisions about the future. So this sounds like a contradiction, but really it's not. There's a difference between designing right now in a way that is guaranteed to reduce future maintenance, which is what I want you to do, versus attempting to predict something specific about the future, like this platform will always be maintained. Or, there's going to be x number of developers using our framework. Or, nobody will ever need another part of this API response. Those are decisions, specific things about the future that you're predicting that you can't know. Whereas, if you say, OK, right now, we know that the purpose of software is to help people. The purpose of software is going to always be to help people, and so that can guide our future decisions. That's a good way of making a decision about the future, is things that you know will always be true and will always help things be better, rather than very specific things that you might be wrong about. So one of the things that we can know about the future, with fair certainty-- with actually, total certainty-- is that the longer your program exists, the more probable it is that any piece of it will have to change. Basically you can think of this as a reflection of entropy. That the universe is going to change around you, and that as long as you want your system to continue to help people, you're going to have to change it. Because you're going to have to adapt it to the changing needs of the universe. Or, maybe it doesn't even fully fulfill its users needs yet, which is most pieces of software. You're still adding features to fully fulfill, even the presently known needs. It's impossible to make a system that doesn't change but continues to help people just as well as it does now. The helpfulness of a piece of software decays if it is not changed. Many people believe that it is possible to do this and they make bad decisions based on this belief. Now, when people get into trying to change pieces of software, there's three major classes of mistakes that they make. And I give a whole presentation on these three major classes and there's a whole section in the book about them, but here I'm just going to go over them really briefly. The first is that they write code that isn't needed. They think, I'm going to need this code in the future, and so they write it now. And there's this philosophy in extreme programming called you ain't going to need it, which sort of forbids doing this. But I think that that phrasing is wrong, because-- and it's hard to convince people that way. Because sometimes you do need it. Sometimes you were right and you did need this piece of software. But what you don't know is you don't know what the real requirements of the future are until you reach the future. So you don't know exactly how the software should be written or what's the most ideal way to write it until the future comes. So what usually ends up happening is you write it now, and then you don't need it now. And then you end up rewriting it in the future when the real future comes, or you don't rewrite it and then you have to hack around it because it's not what you really need. So you're basically wasting effort right now by writing software that you're going to need in the future. The second is not making the code easy to change. And usually, this is just lack of design. Like the simplest way to do this is just to not think about the design, not understand best practices. If you're working in an object-oriented language, don't write object-oriented code. If you're working in a functional language, don't write sensible functional patterns. Don't think about the design of your functions. And you're going to get into a system that just is enormously difficult to change. And the change is the one constant that we have that we're sure about. So that's the thing that you really do need to design for, is change. And so there's two. I probably should have written them on the slide-- rigid design and-- JAREK WILKIEWIC o the third one you have listed here is being too generic. And frankly, this is one of the traps that I find myself falling into all the time. And it's related to the first one, because I'm trying to anticipate the need, so I want to make it generic. But then it's really complicated design. So how do you find the balance between allowing for future change, like you said in the previous slide, because change is going to come. This is inevitable. But then, at the same time, not being too generic so the code is easy to read and so forth, like this is something that I personally struggled with. MAX KANAT-ALEXANDE eah, that's a really great question. And it was something that I struggled with too for a while in my career. And I found a principle that basically resolves it. And so yeah, so being too generic is a problem. And it's a very serious problem. So what I see is that junior engineers tend to have the under-designing problem and senior engineers tend to have this over-engineering problem, being too generic. Because they've experienced the pain of inflexible systems and now they want to handle the problem. But then, they design a system that is generic in ways that they don't know if it needs to be generic or not for the future. And my principle is that you can handle this problem if you just-- very similar to a lot of the other solutions here is, if you focus on being only as generic as you need to be right now and you get really accustomed to refactoring. So it is important to be as generic as the system presently needs it to be. But whenever you're making predictions about future genericness, you could be wrong and you could be wasting your time. And in fact, it's likely that you're wasting your time because you could just wait for the future to arrive and then re-design the system appropriately then. So what I encourage people to do is be as generic as you need to be so that you never duplicate code and that your system always remains simple enough. And particularly, that it remains stable. So sometimes you need a level of genericness to, for example, handle multi-threading appropriately, even though there's only one part of your system that's using it. But more often, what you'll find is you suddenly have two things that look similar. And at that very instant, that's when you need the generic functionality. But you need it to be only as generic as it needs to be to handle those two specific cases. JAREK WILKIEWIC ot it. Cool. MAX KANAT-ALEXANDE ool. And that actually, pretty much wraps up that slide for us. So that brings us onto our next law, which is the law of defect probability. And this is a fairly well-known fact, but I think it's useful to categorize it up here as something that we can use to make decisions about it on a very senior level. And it says, "the chance of introducing a defect into your program is proportional to the size of changes you make to it." I mean, this is obvious, but it's useful for the framework purposes to point out that defects are basically things that don't help people. I mean, that's not the exact definition of a bug, but it's a good way to look at it. There are no perfect programmers. Studies