 So my name is Sandy Metz. I wrote code for 35 years every day. I went to my desk and wrote code. I'm a woman of a certain age. And then I wrote a book. And that was kind of by accident. I won't tell you all about that. But writing a book was like having a bomb go off in my life. It changed everything. I started getting invitations to conferences. I ended up having to quit my day job because I worked for a university. And they weren't willing for me to have that much time off. And so it became incumbent upon me to find a way to make a living. And I started teaching. People were asking me to teach. And so for the last couple of years, I've been doing a lot of teaching of object-oriented design. And curriculum is really hard. I made up some curriculum. Actually, I feel quite bad for the first students of my course. Katrina Owen, who's here, helped me make up curriculum, teach the first course. We had a five-day course that we now teach in three days and have more content as a teacher. What can you do, right? We did the best we can in it. And back in the day, two years ago, when I started making up curriculum for that course, I thought I was making a bunch of different exercises. I thought I was teaching people a bunch of important but unrelated things. And now my day job basically is to think about how to write code and think about how to explain how to write code. And in the leisure that I've had over the last couple of years, I've come to realize that everything I've been telling people has a single underlying principle. That it's not a bunch of different things. It's really one thing. And I didn't understand it. I couldn't see it to begin with. And so this talk is a 30-minute, 30-ish minute distillation of two years of teaching experience. And it's got a lot of code in it. So I'll move forward, OK? So here we go. It became clear to me after I wrote that book that I had an idea. The way I thought about objects was different than the way a lot of my fellow rubies thought about objects. And that is because I've been writing Ruby for 10 years now. I have not yet written Ruby for as many years as I wrote Smalltalk. I learned OO from Smalltalk. And so I am infected by Smalltalk. Now, so this talk's going to be in four parts. They build on one another. So I'm going to start at the bottom. I say Smalltalk infected, but really I mean inoculated. I'm inoculated against certain things because of my experience with Smalltalk. And in the first part of this talk, I'm going to give you just one small sense of what Smalltalk would have done to you had you written it for a long time, all right? And here's an example. You know what that is. It's this. Now, you may or may not be familiar with the send message. So you can send a symbol, which will kind of awkwardly like I can invoke the 2S message by sending it. There's a send message that sends messages, all right? And so that does the same thing. Now, in Ruby, we also have this. That might look special, but it's there just to make you feel OK, all right? That is really this. And you get the same result. Now, that's a fix num, and it knows things. Knows a bunch of stuff. Knows among them, and knows that. That's a method on fix num. That's what plus is. It's not special syntax in the language. The special syntax is the syntax that lets you say 1 plus 1. This is what's at the bottom of all things. We're sending a message. And you notice that we also have that. So you can do this, and I don't have to convince you now that I'm sending equal equal to a fix num and passing an argument. Well, I get that back, 1 equal equal 1. I get that thing back, and that's an object. It's an instance of true class. True is a constant. It's a variable that holds the singleton instance of true class. When Ruby boots up, it goes to true class and says new to it. And it takes the result, and it puts it in that variable. And that way you have it, it's defined for your use the whole time Ruby is up. And so true class knows things. Now, this is a useful lie. This is really not everything. But let's pretend for right now that this is what true class knows. And so I am very comfortable with this, right? Sure, true is an object. It's an instance of true class. Just like false is an instance of false class, and nil is an instance of nil class. This was not confusing to me when I came to Ruby. What was confusing to me when I came to Ruby is that Ruby had a special syntax for dealing with Booleans. I found that very confusing, a special syntax. In small talk, these are the keywords in small talk. This is the entire set of small talk keywords. In contrast, here's the Ruby list. And if you look on the Ruby list, you'll notice that there's this. There's a special keyword that you use this way. Right? You say if one equal one, then I'm gonna do what's in the true branch, otherwise I'm gonna do what's in the false branch. And that about this case evaluates to true. And so this was very peculiar to me. This seemed very odd, right? This is very procedural. Like the scripting languages that we came out of that had long procedures. We used to write these long nested conditions, right? Condition after condition after condition. But not only we have this in Ruby, we got it's worse, right? Because we got this whole idea of truthy. There's truthiness. If it's truthy, then I'll do what's in the true branch, otherwise I'll do what's in the false branch. And really, this is a type check. If I know the kind of object you are, I'll do one thing, otherwise I'll do another. And that is anathema to me. That is absolute anathema. I do not wanna do type checks on objects. I just wanna send a message. I wanna send a message to an object. And so to illustrate how easy this is in an object-oriented language, to get rid of that syntax, that special syntax that deals with conditionals, let's just write some code, okay? Let's write message, let's write small talk-like message sending syntax in Ruby. First we are gonna have to break open true class. Why not? You're gonna love it, right? And I'm gonna put an if-true message on it. And in it I'm gonna just say yield, right? So every method takes a block, the implicit block. I'm gonna yield to the implicit block and return self. Don't worry about the self for a minute. It doesn't matter for right now, right? So in the if-true method, I'm gonna yield to the block if one got passed and then false will do nothing. In the false class I'll do just the opposite. So in the true yields during if-true and false yields during if-false. And so if you write this code, if you break open those classes and monkey-patch them in this way, what you can do then is this. You can say if you send if-true to a true, remember that that's gonna yield to the block, which means if you run it, if you run that code after making that monkey-patch, you'll get this result. And remember that false does not yield to the block. And so if you send if-false to true, you'll get nothing back, right? Now, so you can imagine already think ahead to how it works when it's flipped around. So if I have false, false does just the opposite, right? If I send if-true to a false, it's gonna do nothing. It is not gonna evaluate that block. And if I ask a false, if it is false, it will yield to the block. It's as simple as that. And so now, this code works, but it doesn't really solve the whole problem because I just have true and false here. I don't have truthy. It's really easy to make truthy work. I'll just promote this up to object, because why not? And I'll copy that in a nil class. I'll duplicate that code in nil class. All right, and now everything is truthy except false or nil, which is exactly how Ruby works. This is, I took this code right from Yehuda Katz's example from this blog post, proving that nothing is new. And so now I don't need a true there. I can put anything there. Everything is true, and it's not false, except for nil, which just like false is false. And so now instead of writing this code, instead of using that special syntax to deal with conditionals, I can do this. Or if it went to a false, I can do that. And it totally works. You do not have to have any special code. I can send messages to objects to manage control flow. Now, having done this, I am not suggesting that we do it. All right, I'm not suggesting that we do it, but I want you to think about what your ideas about objects would be like if you didn't have an if statement, right? You came to Ruby, most of you. Many of you came to Ruby from other languages that were more procedural, and your procedural mindset was allowed to plug right into Ruby because the if statement was there. When you came to Ruby, had there not been any syntax to do conditionals, it might have changed how you think about object-oriented code. And I want you to imagine you live in that world because that's the world I live in, and it shaped all my thoughts about OO. So I'm infected by small talk. And because of that, you can guess I'm extremely condition averse. Extremely condition averse. And here's a condition, here's a condition that I hate that's really common in Ruby, right? Let's imagine there's an animal that you can look out, you can pass a key to it, like pig, and you'll get an animal back. If you pass an ID or a key that's not there, you get back a nil. This might remind you of something in Rails. Don't quote me, ah, what just happened? That's just here, wait, I can fix that. You know, oh, somebody, I'm supposed to be on a phone call with somebody. That's what my, that's what my calendar just told me. You know, this might take a minute because here, wait a minute. Oh yeah, look, it's gonna be fine. There we go, see, look how easy that was. They used to terrify me. You know, you just, things just get easier. I mean, I make mistakes for a living so much that it's like, it doesn't even phase anymore. Okay, so, if you pass a key that's there, you get an animal back, if you pass a key that's not there, you get nil back. And so let's say that you, initially, someone passes you an array of keys. And you innocently call find on animal for all those keys. If you do, in this case, what you'll get back is that array. And then, if you wanna talk to them all and ask them their names, well, the first one tells you it's a pig and then kaboom, right? And so we, so this is, so first of all, I'm gonna put one caveat right here, right? Sometimes nil means nothing. It really does. Sometimes nil means nothing. And if it does, you should just compact that array, right? Throw the nil away. We don't have, we can't return void in rubene. Something always comes back. And if you get a nil and you don't care, you should just throw it away. In this case, I just have pigs in sheep. But now, but if you're sending a message to those objects that come back, there's something. That nil means something and you need to deal with it in a different way. And so in this case, what we often do here is we put, we just put a conditional right there, right? And here's when I wrote it all out then in the ternary form, right? If it's nil, I'm gonna say no animal. This is like, there's no user logged on and you're gonna say guest. And you have that code in your views, right? If user, you know, user bar bar, user name or guest, you put this code right there. Now, this works and I can say, I can get no animal back in every case here, but this is ugly and we just can't bear that ugly code. So we start improving this code. We start hiding the conditional. And one way we can hide it is we can use truthiness. So that looks better. That makes me feel better because it looks better, right? Now, this relies on the fact that nil, if you interpolate nil into a string, you get an empty string back. So all of a sudden, I can't say no animal anymore. I can't call that user a guest. So I'm just gonna get nothing back here. So now I got pigs in an empty string and sheep. But even that's too ugly. So if you're a Rails programmer, you're gonna say try, right? Try that. And I'm not saying you should never use try, but I'm saying that I still got the empty string. This is really that. Let's be honest about what's going on here, right? This is that. And that, like this nil question mark method is very interesting, right? Nil answers no question mark and says true. Object answers no question mark and says false. But hash doesn't have one. There's no hash question mark method. There's no string question mark method, right? This is an implicit acknowledgement that we nil sometimes means nothing. But this one, here, wait, I have a pointer. Wait, I love doing this. Look, I have a pointer and you don't. Sorry. Sorry. Saying that is just saying this. This is an equality test. And since there's only, it's a singleton, there's one instance of we're doing this. This is a check on class. This is a check on type for nil. And if you're doing this, it's really that if you wrote it all out. And if you write it that down, then I really want no animal. And I want to make it harder, right? That empty string does not help. Mostly I want to say something there. And this looks like that, which is what I told you in part one I hated, right? Only it's worse here. It's worse here than it was in part one because really I'm saying, if this is an object whose type I know, I'll supply some behavior. Otherwise, I'll send a message. That's what we're saying. If I know the type of this object, I will supply the behavior. Otherwise, I'll send a message. And the problem with that is it's a condition and conditions breed. If you have one, you will get more. It always happens. And so here, the problem here is this no animal thing. Like this code gets all over, right? It isn't long before there are hundreds of places in your app that have to supply the missing behavior. And if you want to change that anywhere, then you have the code smell for the change you have to make at that point is called shotgun surgery. And there's a reason why, right? It's everywhere. That change is propagated in many places. So this is a bad idea. I hate these kinds of conditions. I am very, very condition averse. Instead, what I am is message centric. I just want to send a message to an object. I do not want to know this stuff. I just want to send a message somewhere. What I want to do is that. I want to do that and nothing else. Now, the problem here is that when I make the call to find on animal, I get back objects that do not conform to the same API. I'm gonna say that again, right? I send a call, I send a message to some other object and it passes me back things that answer to different APIs. The animals I get back do not conform to the same API that nil does. Nil doesn't understand name. And what I really want, I'm gonna do Ben, I think Ben mentioned this, right? I write a lot of code based on, I write the code I wish I had. The code we wish we had is we wish there was somewhere that we could send the name message and get back the string no animal. Let's just make that object, why not? We can do that. And I would rather know about this object than know about that behavior, always, all right? And so here, if I had that missing animal class, here's what I could use it, right? I could say bar bar right there and replace the nils with that missing animal. If I did that in this case, I would get an animal there. I get, there's someone that conforms to the same API as in every place in this array. Now you notice that nothing is free. I've added a new dependency and I still have a conditional. The conditional's not even gone. But what has happened is the behavior's moved. The behavior's moved and that is better. Now all of a sudden I can do this and I can do that and then thankfully I can do this, all right? And so, and I get the results I want. And so now my problem is a little bit better. My code is a little bit better. What I have, instead of knowing no animal in a million places, oh sorry, I get that wrong every time I practice, pretend I didn't say that. Okay, here, let's back up. So, missing animal, what is this? This has a name, can you get, sorry, sorry. Sorry, yeah, look, it has a name, it's this. It's the null object pattern. And I know that there are ways in the Ruby community, like I am self-taught, right? I am, I have a psychology degree. I wrote code, I figured stuff out the hard way for many years and I made a lot of mistakes. I figured out the null object pattern all by myself and I happened to be working with someone who was better read than me, who came back the next day and said, that thing has a name, right? I was like struggling, struggling with the problem and I knew that, I kept saying, if only I had a thing that would just answer this message the right way. And I had to discover it for myself and I tell you, it's the wrong way to do things. Like people have figured a lot of these things out and if you can just find a way to become a little bit more aware of the literature, lots and lots of things get easier. And so the null object pattern, someone described it as the active nothing. I wanna plug in an object, right? I wanna plug in an active nothing. Okay, so now back to the place I tried to go a minute ago. So I got this new dependency and so I'm duplicating the name of that class everywhere instead of that string, instead of the no animal string. And so I told you that I would prefer to know that object than to duplicate the behavior but the truth is I really also want to know only a few objects. And right now what has happened is every place I call animal.find now I have this dependency, right? It goes on and on and on. But once you get here, this is really easy to fix. I mean here's the class, let's assume this is someone, this belongs to some external framework, right? I cannot change this code and it is untrustworthy. I can't change the code and they're gonna, when I make calls they're gonna return things that conform to different APIs. It's easy enough, I'm just gonna put that in a box and wrap it in another box. I'll wrap it in my own code. And in my own code I'll do that conditional. One place in my whole app and then I'll make all of my code. Not do that but do this, right? So I'm gonna wrap it, I'm gonna put a wrapping class around the offending API and fix it. And then I'm gonna require that all the places in my code call my new thing. And so now I get that and I get that. It just works. It's incredibly easy. It's a really simple idea. It took me a long time to think of it and you should not have to think of it yourself. All right, so I push the creation of this new object to the edge, to the boundaries of my system as much as I can and this absolutely decreases the complexity of my application. And it comes from being message-centric. It comes from insisting that I wanna send a message. But now comes the big idea. So the null object pattern is, think of it this way, it's a concrete instance of a much bigger idea. And it was really interesting to me. I had seen Tom's talk before, the talk that Tom just gave about abstractions I saw it in the fall and I didn't really understand it. I don't know, he may have influenced my thinking about this some. I don't know, I was unaware of it but when I was struck by watching his talk by how well it dovetailed into what I'm about to say you. So if you think of the null object pattern is, it says sometimes nil is a thing and you should put an object in there to supply the behavior that you wish nil had, right? If you think of the forest and the trees, the nil object pattern is like a shrub and there's a 10,000 foot idea way up above it. And if you could understand this bigger abstraction, it would make all your code easier, right? And so this last part of the talk is about that higher level abstraction. Here we go, in order to do it, I'm gonna have to introduce a new example. This is the tail, the house that Jack built. I hope that you know it. Do you know it generally? Oh, okay, so it's a cumulative tail. So it goes like this, so it's a thing that kids learn when they're children, right? So the first line is this is the house that Jack built. And then it accumulates, new bits get shoved in in front of the bits that are there. This is the malt that lay in the house that Jack built. And then the next line would be this is a rapid ate the malt that lay in the house that Jack built. And there's 12 different bits that get plugged in and here's the whole thing. This would be the 12th line. And so if you're gonna recite the whole tail, you'd recite line one and then line two and then line three and each one would get a little longer. Tails are really interesting. If you go look this up on Wikipedia, it's two hops to Guy Steele and Java, right? They're very algorithmic, these songs. In the class I teach, we use a lot of tails and songs to teach because these kinds, they're iterative, often incumulative and they help let you learn how to deal with algorithms in domains that you're already familiar with. And so if you were gonna write the Ruby code to produce that tail, you would likely do something like this. You'd get all the bits and you'd put them in an array. Maybe you'd wrap a method around it and then you'd have, perhaps implement a phrase method that will go in and get, you may not know the last method on array, like you can ask an array for its last thing, it'll give you the last item, but you can also pass an argument, you can pass three and you'll get the last three things in the array. So as you're looping through a line at a time, the number of the line you're on represents how many bits that you want out of that array, how many bits should be in that line. I'm gonna make that smaller because you know it's in there, you don't need to see it anymore, I need the space. So I have a line method that puts the this is and the period on the end of it, so that's how you make a whole line, right? And then line calls, phrase on whatever line number I'm in to get the middle part that accumulates. And then the recite, which does all 12 lines of the song is just gonna loop over the number of bits in the array, yielding a number to the block and then calling line on that block. So that's how the whole thing goes and then if you wrap it in a class, you got it. This will produce the whole tail. And so if I were to get a new house and call line one, I would see that, line two gives me that, line three gives me that, line 12 gives me that and then recite does something like this. Okay, so that's the house that Jack built. So imagine that you've written a house that Jack built, you have a customer that asks for it and then once you have it done, they come and ask you for a new feature. They want random house, all right? Here's how random house works. They want you to take the array and they want you to randomize it. All right, now every time you randomize it, of course you get a different output. But for our example here, this is one random, in this case, it ends in the rat that ate and made an awful lot of milk, the cat that killed. And so random house for this randomization ought to be line one is this is the rat that ate and made an awful lot of milk, the rat that ate, the cat that killed the made an awful lot of milk, the rat that ate. Okay, so it's now time for me to warn you. Here's what the thing looks like. It is true that despite its innocent nature, many variants of randomization are not safe for work. Just saying. In this case, that the good news is that, the good news is that it's an equal opportunity offender. Pretend you're watching South Park. Do you know South Park? Yeah, okay, South Park from here on out. Okay, so if I wanted to, so here's the code we have, you have to keep house, you cannot break house. Right, houses, I like house, I wanna keep house. I also want random house and I'm gonna give you, I'm gonna charge you to implement random house without adding any of savings. You cannot have conditionals. So there's a really simple solution if you use conditionals, right? You can just plug a boolean in that says whether it's random or not and then randomize the array. That's not what we're gonna do here. So I really want two things from you. I want you to implement random house without using any of statements and I want you not to alter the code you have in order to do it. That's O principle and solid, right? You're allowed to rearrange this code if you want but at the point when you try to implement random house I do not want you to change the code you have. Now the solution to this may not be immediately obvious but there is a thing that we commonly do in this case. We say well, I can meet both those criteria with inheritance. I can produce random house without any conditionals and without changing the code I have. So let's just do that. Here's the thing, I can subclass house, I can override data, I can call shuffle. Shuffle's the method on array that randomizes the contents. Now since I only wanna shuffle it at the beginning of the song and produce the lines out of the same shuffled array in this case I have to cache the result. So if I write this code and I get a new instance of random house, sure enough, using the same randomization I got last time, this works, it is exactly right and house still works just fine. In this case you can see that somewhere in there the priest is marrying the man that's kissing the horse. And so great, that's awesome, right? And it actually may be the most cost efficient way to do business right now. But so let's get another feature request. Another new feature request, this is what happens, right? And now they want echo house. They like random house, they wanna keep it, they like house, they wanna keep it, they want echo house. And here's how echo house goes. It echoes the bits. This is the house ejector, the house ejector. This is the multiland, the multiland, the house ejector, the house ejector, right? The rat that ate the rat that ate the multiland. All right, and so this is a code I have and it's this bit right here that goes in the array and gets the three parts. I need that bit to change and it's a little awkward here because this method has a violation of single responsibility in it. It does two things. It gets things out of the array and it joins them with spaces. So the first thing I'm gonna do is just a tiny bit of refactoring. I'm gonna take that and extract it into a method of its own and then call it so that I can just mess with parts. And so this is all the code that we care about right now. Right now I get this back in house when I call it. What I need back, it would work. Echo house would work if I could only get that back instead. This is what I want. And so you have the same task. I want you to implement Echo house without adding any conditionals and I don't want you to edit the code we have. And now that we've gone down the inheritance path, of course we're gonna do it again. Absolutely. It's easy. It is so easy to solve this problem. Look, I'm in a subclass house. Now that I have the parts isolated, I'm gonna override the parts method. I'm gonna call super zip super flatten. Let me just tell you a little bit about that. So if you have an array that looks like that, that's what you get if you call it super. Zip sounds like compress, but it's not. It's zipper. All right. And so what zip does is it matches them up in order wise. So you get this back. If you call super zip super this two dimensional way where it's doubled up on the parts and then the flatten, of course, flattens it out so you have single things. And so this totally works. It absolutely works, right? I can call one. I can call two. I can call three. I can do the whole thing. And so here's the code we have. That's what house has in it. I got random house. It overrides data. I got echo house. It overrides parts. So now of course they want, yeah, they always do this, don't they? They want random echo house. And so now you're screwed, right? You are well and royally screwed. And here's why, right? We don't even need house anymore. Here's the problem we have. So I need behavior. I have two subclasses that have behavior and I want another subclass that has the behavior out of both of them. And there's no way now to proceed forward with inheritance without duplicating some code. And some people have, well, people occasionally insist that there is but there ain't really. Watch, right? So here's what you can do. These are your choices. You can duplicate some of the code. You can subclass. You can make random echo house subclass random house in which case you can inherit the data method but you must duplicate parts. Or you can just flip flop it and inherit off echo house in which case you get parts for free but you gotta duplicate data. And these two choices are so patently wrong that when I go places and look at people who have run into this problem very often they make neither of those choices. What they do instead is they duplicate all the code because there's a way in which it feels more honest to have everything just subclass house and to copy all of the code into this new. It feels almost like as if it is more right than the alternative. And this sucks. This is absolutely wrong. And it's wrong because inheritance is for specialization not for sharing code. All right, and now I'm gonna tell you how to recognize this problem and how to get out of it. The first question you have to ask yourself, if it is a specialization, then random house is a house. It is a kind of house. And it's really easy to think that it is a house because it says random house, right? And so the naming, naming, right? Hardest problem in computer science, cash and validation and naming. The name tells me, the name implies to me, but really what you have to ask yourself when you look at this code is what is different? What is different here? And that code is so, what changed between them? And this code, it's really hard to glance at that code and know it's different. It's very hard to answer that question. So let me give you a thing you can do there. This is paradoxical. You can make it more obvious how things are different, the way in which things are different by making them more alike. And so let's try that. You don't have to know the answer. I'm just gonna make them more alike until I can see the way in which they're different. So I'm gonna make that like this. And in order to do that, first I'm gonna go to the top and I'm just gonna pull that data out and put it in a constant. And then I'm gonna do something that might seem really pointless. I'm gonna set a variable to that and then I'm gonna make a method. I'm not even gonna use an adder reader yet because I want them to look as much alike as I can make them. I'm gonna do that. And now if I take out all the code but this, it's much easier to get a sense of what changed here. Now, you have to be able to give the thing that changed a name. You've gotta be able to identify and name the concept here. And that can be really, really hard in these cases but actually I was lucky enough to teach with Abdi Grimm, whom some of you might know and he suggested we were trying to ask a leading question to get people to discover this and he said, imagine it's a spreadsheet. What would you label the columns? And so this, okay, class data, I'm sorry, that's a crappy name, I know, I did that. But the question, the real interesting question here is what is the name of this column? And it's not randomization. Randomization is not what I'm doing. This isn't the column for random, this is a column for order. And if that's true, then this is not nothing. This is an algorithm for ordering and it's just as valid as this other one. And so if I were to write, so now that I know it's order that is varying, order is clearly not a house. And that means that this is not a problem for inheritance. It's a roll and I'm just gonna write some orders. Here's one. If I had a random order whose API was order and it took in an array, it could shuffle the thing it got and return it. What's the other one look like? What's it do? It just returns it. That's an algorithm, right? It's an algorithm for ordering. And so this is a code the way we saw it last. Now, I'm gonna just make an adorator there so I can make that a little smaller. So I'm gonna remove the responsibility for ordering from house, from the house I have now. I'm just, now I'm back just working on the house class. And we're returning to something that Ben talked about this morning, right? We're gonna invert the dependencies by injecting them. I got this thing. What I can do is shove it in there. I can inject an order in there and then I can give it a chance to operate on the data. Now house is no longer responsible for ordering. It just has an order that does it. And if I run this, this works. All right, so what have I done? I got more code to accomplish exactly the same behavior, right? And people hate this. They look at this and they say, oh, this is object-oriented design, right? They made a bunch of objects. They unduly made it unduly complicated. They complicated it for no good reason. But now watch. One and I shoved that one in and now I got random. This is composition. I'm gonna inject an object to play the role of the thing that varies. And now that you've seen that, echo house is incredibly easy, right? I'm gonna make an echo formatter and I'll just make a default formatter, right? The default format is to format it in no new way. I'm gonna have to take it and I'll put a default. This is what lets house continue to work the way it has. I'm gonna go ahead and, oh wait, here I did that just for Katrina. Let me back up. Notice I'm adding code and then they gotta line up. They gotta line up. It's killing me. We'll put that in there. Okay, and so, and I'm gonna go, I'm worried about it. I don't wanna intervene in too big a place. So I'm gonna go all the way down here at the point where the responsibility for picking the right items out of the array is still in house. The responsibility for ordering those items goes with the formatter. Whatever I plugged in is gonna get a chance right at this point to do it. So house still works. That's the same output we had before. But now, in addition to what I did before, I can inject an echo formatter and I will get echoing. And so I got these two rolls. There's an order roll and a formatter roll. And now I can use them this way. Instead of printing a line, I'm just gonna say recite the whole song since that's a little simpler. I can inject, I can get the normal house. I can inject a random order and get the random house. I can inject an echo formatter and get the echo house. Or I can inject the random order and the echo formatter and get them both. And that is no longer more code. It's actually quite a bit less code. And there's not a bit of duplication in here. I've got these units of pluggable behavior that are defined around the rolls, around the concepts. And this is composition and dependency injection. This is what it means to do object-oriented design and it is actually totally awesome. All right, so I'm abstraction seeking. So here we go. These are the high level lessons. If you're talking to NIL, if you're talking to the NILs, there's something. And you should use the NIL object pattern. You should make objects to stand in a place to respond to the messages that you wanna send them. The active nothing, use the active nothing. Quit putting NIL checks in your views. You're done with that as of today, no more. Stop that. Beware of inheritance. Now, I think inheritance is fine. I use inheritance all the time. It is not a bad thing, but it is not for sharing behavior. If you're gonna inherit off something, you should specialize most of the behavior of the superclass that you're getting. And finally, and this is a big idea, there's no such thing as one specialization. If you find yourself wanting to inherit to change a little bit of behavior of a big class, the new behavior that you added is one thing, but the thing it's changing in the class is another. And it's there, right? There's never just one specialization. There's always two, by definition. If you're making one specialization, you're specializing something, and that's the other half of it. So in that case, notice that. You need to isolate the difference, name the concept, define the role, and then inject the players of those roles. And in order to do this, you have to believe in that nothing. Believe in the nothing because nothing is always something. There you go, thank you.