 So I'm going to be talking about a concept called Easter-ordinated code, which is related to tell-don't-ask. I'm Jim Gay. I'm Saturn Flyer in most places, in Twitterland, on GitHub, and everywhere else. So tweet at me and tell me what you thought, or during. But I'm not going to be checking. I traveled west to tell you about going east, and I brought these people with me. So if you see them, say hello. I practiced my presentation with them this morning. They didn't quite get all the concepts, so it taught me to go a little bit slower. And this is funny, actually. When I posted this picture online, a friend of mine asked about my daughter there. Is she referring to all of us as losers? I don't think so. She hasn't said that. Easter-ordinated code. So I'm going to be talking about this idea. It might not make sense at first, and that's OK. I just want you to stick with me, and we'll get to some rules and things that you can do. You can walk out of here and try it on your own code, and see where it takes you. This is an idea coined by a man named James Ladd, who's an Australian developer, and we'll get into more of what it is and what he says about it. But we're going to be looking at our code and see which way the flow of information goes in our code. So this idea of information traveling eastward can help us in information traveling westward can actually be a problem. So if you were to look at a compass to get around in your code, you'd see queries traveling westward. This information going in a particular way. I should be pointing that way. And commands traveling eastward. When I first read about this, I didn't quite get the concept until I realized that I could actually look at my code and see this happening in it. Sometimes you can look at your code and you can see how deeply nested it is. And you realize a bunch of nested if statements. You have this gigantic angle or rocket ship shape or whatever you want to call it. And you can see that that's bad. But you can also look and see where there's the information going. Is it traveling westward or is it traveling eastward? So let's go over a couple of rules. We'll get into the code and how we will apply them. Rule number one, always return self. Rule number two, objects can query themselves. And factories are exempt. So it's OK. It doesn't make any sense. It will. One of the great things about programming is that we get to use fancy words, words like polymorphism and encapsulation and coupling, which has nothing to do with Valentine's Day. Item potent. These concepts matter, but sometimes it's really difficult to see them or know how they work into our code. We also get to use some not so fancy words, like this one. Does everybody know this one? Yeah. There's some liars in the room. This is probably the simplest and the most powerful word that we have that we get to use. And we can do amazing things with it. This is awesome, right? Although sometimes this kind of gets out of hand. Too much of this and you think, well, I'm not really sure what's going on. It's OK. You can refactor it. It sounds like some people have done that. I've heard about people talking about not using ifs and avoiding ifs. And sometimes you think about the argument and it doesn't quite seem right. What's the harm in one little if? But the problem isn't that one. It's that our code ends up looking like this. It's all over the place. So let's start looking at some code. Here we have a class person that has an address. And we want to display it. I know I've done stuff like this in Active Record when I was first learning Rails. It was amazing. You just put code in your Active Record object and it displays properly in the view. So here's what we might want to display. Here's some information, right? Depending upon what data we have, we'll display it in a certain way. We want to have a carriage return if we've got a street and a city or a province and postal code. We don't want to have a comma if there's no city followed by its state or province. So we have to make some decisions about the data and what we do when there are missing pieces. I'm not going to keep the type that large. I'm showing a good amount of code. You're probably not going to have to read all of it, but I've got to shrink it down. So let's look at an implementation of this. Don't read it. But how many ifs are there? How many? Five, six. Maybe there's more. There's some down below that we probably can't see. How many responsibilities? Too many. Too many. I think that the correct answer for both of those questions is too many. And there's actually a bug, too. We'll still get a comma even if we don't have a city. But it was hard to see. I actually wrote this code and I thought, well, let me use these ifs and let me find out about this information and see if I can piece all of this together and ran it. And I still had a bug. I'm sure a few more ifs would solve that. So let's start following the rules. Rule number one, always return self. So here's what it might look like, right? Down at the bottom, self. All of our algorithm for displaying this is still there. So we follow the rule. What happens? It's broken. So this is an indication. If we follow this rule, maybe there's something missing, right? Maybe there's another object, at least another object, that we need. So I think, OK, what principle can I follow to help me know what to do? I think this will help us understand, and I'll talk a little bit about it, and how confusing it is. Tell Don't Ask is an idea coined by Andy Hunt and Dave Thomas, an article they wrote, where they wanted to encourage you, and all of us, to create a division of responsibility without causing excess coupling. I know when I first read about it, I didn't quite get it. I thought I understood, and I moved on. And I know I hear this topic come up often. It seems to be a perpetual discussion topic for programmers. Another way to think of it is this. Command Don't Query. Don't ask for information, right? We're not going to ask an object about information and then perform some function for that object. It would be much easier if we just told it to do what it had to do. I think about this actually raising my kids. We're going to walk out the door. Let's go. You've got to know, put your shoes on. You've got to know, you've got to have your socks on. You've got to know that shoes go on the correct beat. All that kind of stuff. I don't want to have to do it. So look at this. When I first learned about Tell Don't Ask, I thought this is great. Ruby is awesome because I can put question marks at the end of my methods. And that's obviously a query. It has to be. And the ones without them, those are commands. I'm telling the address to give me a street, or I'm asking if it has a street. Good enough. Done. Moved on. And I actually did this. And I know that there are developers who think this. And you're wrong. So let's look at the code. Command Don't Query. We don't want to ask an object for information about itself and do the work. We just want to tell it what to do. But here we've got queries. We're asking the address for its street and checking that value to see what it is. That's a query, too. That's not a command, even though there's no question mark. Are there any commands here? I mean, it's hard to really say. All right, what else is wrong with this? This code is in person. We're displaying the address. This makes me think of this. Have you heard of the law of demeanor? Does anybody understand it? A couple of hands go up. OK, so in this code, we're breaking the law of demeanor because what it says is that an object really should only be able to access itself, any parameters that we've given it, any objects that it created, or directly held components. So it's an internal structure is really what you should work with when you're creating the implementation of how an object behaves. We're looking at address. We're going through address to get to street, checking its value. And then there's all these other things. So we have to know the full object graph of the relationships of these things in order to get this thing to work. So there's a lot of knowledge about the system wrapped up in this. This is bad. This is the person class. This isn't even address asking questions about it. So Andy and Dave, when they first wrote about this, this was their sample code. What if we were programming a television? We had to figure out a way to turn it on. How would we organize it? Maybe this is close to what we might do. We've got our television. It has a front panel. We've got to get from the switches the power button and turn it on. But what happens when the way on works changes? We decide we want to make it toggle or something like that. So that breaking change is going to go back through the power button. Switches isn't going to work anymore. Front panel isn't going to work anymore. My television isn't going to work anymore. And the code that calls this is broken now. So at any point in that tree of objects, this user class, this method here will break. Congratulations, everything is broken. You're a programmer. All right, now what? So what did they say? Do this. Just make a power up button on my television, right? Command that thing. Just start up. I don't care how you do it. Just turn on. So this method can take care of talking to related objects. The code that uses it only has to know that there's a television and it has a power up method. Back to this. What can we do? So clearly, there's an address involved here. Maybe we should do something with the address, right? So we're returning self. We're still following the first rule. We could just tell the address to display. Is that a command? So here we move the behavior down into address. There's still lots of queries, though. We're still asking a lot of information. Is that bad? So that's rule number two, right? Address can ask questions about itself. That's totally fine. This is OK. It should be able to know about its own data. All right, but I want to fix the bug. So let's clean up the code. This is what we would get in different scenarios. The way it would display with some pieces there, some pieces missing, we add province and postal code together. We compact them to remove any nil values and then join them with a space. And then here we are adding city. So if you have a city, we need to add a comma afterward and then do the rest of it. And then finally, the street has to be in there. So we add the street. And if there is a street, we're going to put in a carriage return and we're done. But that line break, something's not right because we're working with an address. And the address knows about the formatting. What if we did a different format, right? That thing doesn't really belong there. So an easy way to do it, let's just put an argument in there, line break, right? That's great. Now I can throw whatever I want in there. I can break it up however I like. And then of course, person needs to know about line breaks, which that doesn't seem right. Regardless, person is still returning self, so we're never going to actually see anything. So that's not right. We still need another object. We can introduce a template to handle formatting, right? This object's job could be determining the format. It can take an address and its method. The address would contain the data. It knows about the data. But the template says, I am going to output this to standard out. You see there the line on the bottom is just going to say, here's standard out. That's how this template works, right? And even it returns self. The algorithm for the formatting is still the same, but it's moved into the template. And if we add an HTML template, that thing knows how to write to a file and put in a break character. So the template's control the output. How do we use this? We could change the method signatures of the person to accept a template object. We tell the person, hey, display your address on this thing. And then person can take that and send it down to address and say, here, you display yourself on this thing. One of these things isn't following the first rule, follows the third rule. Factories are exempt, right here, where we set our default template. It would be kind of foolish of us to have new return self, because self in this case would be the class. And then we'd never have a new object. So it's OK. You eventually need to initialize objects. If we always return self, we'd never get new objects. So person sends the template along with the display command to the address. And the address passes itself to the template, returns itself. And then the template does all its data processing, outputs what it's supposed to output, and returns itself. So what do we gain? Each object tells the next what to do. Each object is responsible for its own part of the domain. And we were forced down this path just by returning self. So there's still a problem that I want to cover up. And that's that the data is still accessible from anywhere. Demeter is calling. So I want to remove the ability to add if statements. I don't want to be able to query at all. I want to be forced to command. Like, if this is a good thing, and if I can put all these responsibilities in different objects, and I'm forced to do it, then I'll do it. But if I can query, and I can ask objects for information and operate them on them, not only will I do it, but the next person will come along and see that that's accessible, and add an if statement to put processing in the wrong place. Or maybe not the wrong place, but a place where it'll be difficult to maintain or change later. So I want to remove the ability. And I know this doesn't really remove it. You can always get to private methods, right? You can use send, but that's ugly. It's at least some syntactic vinegar to make you wince when you have to type send in order to get address, or street, or city, or province. So now this stuff is protected. I only have these commands. And what happens? Here's our address, private attributes, and we broke it. So was that the right thing to do? Persons blocked from querying, that's good. But template is blocked from querying as well. So we can't have any demeter violations. And we don't have the ability to traverse the object graph inside a person. But we can't use the template either. So here's something that you could do to fix it. We can give the address an ability to provide a value object to the template. So in this case, if you're not familiar with OpenStruct, it's part of the standard library. You can just require it, add a bunch of attributes to the object, and then you can call them, just like we do in our template. So there it is. Instead of passing itself into the display address method of template, it just calls toValue, which is also a private method so a person can never get toValue. No other object can get toValue unless you go through Send and make it ugly. But why do this? Why bother with all this? Because of this. We might have data that we just don't want to display. There's sensitive information. Maybe you don't want somebody showing up in your home address. This is a web form. And you want to be able to mark something as private. So if we add the feature to only have private information, maybe we still store where I live so I can get packages. But I don't want to display on my profile exactly where I live. Maybe I just want the province or just the postal code. I'd like to be able to mark things as private, private information. So what object should decide how to do this? I think it makes sense to have the object that owns the data be able to decide what should be displayed and not how. So we can change this code to do this. Now, this is an imaginary method. I'm not implementing protect privacy here inside of toValue. But when we call toValue, maybe that's the thing that checks. Is this information available to the public? And there might be other ways that you want to expand that. Or you might want to protect privacy up in your display method. But wherever you put that, I think it makes sense for address to decide. And you can come up with all kinds of ways to show or not show data and do different things. But the benefit here is the address is deciding what data to display, but not how to display. We're still using the template. We've made zero changes to the template, and it will still work. We've made zero changes to person, and it will still work. So let's look at the template again. Now, in this case, we've got queries all over the place. Address province, address postal code, those are queries. We're getting information out of this thing. So that's bad. Didn't we talk about queries being bad? They're everywhere. So this is rule number four that I didn't mention. But you can break the rules. It's OK. A value object is intended to be queried, and only that. You don't really do anything else with it. It basically simplifies our parameters. But we can break that rule for that. But we can look at this code, and we now see that everything is traveling eastward. I don't ever get information in person about address. I don't get information about the template inside of address. And even inside the template, we command standard out to put this string to its output. So this idea of east-oriented code. This is what James Ladd says about it. East orientation decreases coupling and increases code clarity, cohesion, and flexibility. I think that code, to me, at least shows it. We had a lot of queries, a lot of mixed concerns inside of person, which I know I've written code like that. And it seemed totally fine. And you go down the road, and you have if statements all over your code base. And individually, they seem all right. But if you just took that first rule and applied it to your code, what would happen? You can look at your code and see the direction of information. And if things are traveling west, that's probably an indication that you're leaking information. You should see it like this. Information leaks knowledge. It leaks responsibilities. They queries actively encourage you to put code in the wrong place. But commands encourage polymorphism. East-oriented code and commands enforce encapsulation. They push responsibility down into objects. It loosens coupling. And I didn't talk much about this before. If you want to make code item potent, you can tell the address to display itself. And if it has already done that work, you can tell it again. And it decides whether or not it needs to. So you can tell it 1,000 times. And if it's done the work, it can say, don't worry, it's done. You don't have to do it over and over again. Whereas if we queried for information from the address, we would have to keep all the knowledge about whether or not it was done inside of that person class as well, which could become a little difficult to manage. So to be east-oriented, always return self. Objects can query about themselves. Factories are exempt. Break the rules sparingly, like in value objects. And James Ladd is on Twitter. I would love it if everybody said thanks to him for coming up with this idea and adding to a way we can enforce, tell, don't ask, in our programs. This is the difference. I know he's talked about east-oriented code before. And people said, well, that's tell, don't ask. But the difference is you must tell. If you're returning self and you hide information about an object so that you cannot query it, then there's no other option. So I love making tools for myself to give me and my team guiding principles so that it's easy to do what we want to do. So what if we had a tool to help guide us? Let's try it. OK, so this code, I'm going to walk through how you might make sure that you do something like this in your code. Say we've got a person. A person has a friend. And I want to be able to tell that friend to make me a sandwich. Sudo is not required. So this is what we could do. We just define a method, make me a sandwich, that it goes and tells the friend to make me a sandwich. I don't like that. I like to use forwardable. If you're not familiar with it, that's pretty much what it does. It's very simple. I think it really hides a lot of the mumbo jumbo of just setting up methods and just shows you, hey, all of these things that you specify up here, I'm going to send that onto friend. So in this case, if I do use forwardable, it's really a query. Because the information that I get back is whatever the result of that method is. So I might tell a friend to make me a sandwich, but I'm going to get whatever information it returns from its method as the return value for this. So if I'm telling a person to make me a sandwich, I don't continue operating on that person. I get whatever that method returns. So I want to be as concise as forwardable allows me to do that, but how do I do that? Don't install this gem. I wrote this gem just to show a way that you could write your own code in your project is very small. To add this to your gem file would be ridiculous. But it's there. It's on GitHub. You can read it. So let me just show you some tests that I wrote for it. I've got a friend here. The person's friend is set. Before the test runs, I clear the table. And when I tell the person to make me a sandwich, I assert that the contents of the table has a sandwich on it. But I could still go through person to get the friend to make a sandwich. And I don't want to do that. I want to protect that relationship. I don't want to have to do that. I don't want to have the object graph available. I want to hide it. You should just have the commands. So traversing the graph is bad. So forwardable allows me to specify which one I'm going to send. And because it's a method on the class itself, I can hide friend here. I can make it private, which is what we did before. Now, we can't traverse the objects related to person from the outside. And this is how you would use the gem. You'd just change from forwardable to direction. And I chose the word command instead of delegate, just so you know that's going to be a command. You're going to get back the object that you're currently working with, not the one that you're forwarding to. So it's a very simple change. And now the code still works. But down at the bottom, I get the original receiver. So I assert that the person is the result of making me a sandwich. Sandwich is made. And I get the person back to continue operation. That's what that test looks like. And I can continue telling that person to do things for me. So we can only send commands to that object. I can't ask person for friend and then go query about friend and what its favorite thing to do on a Wednesday morning is. So how these things are implemented is totally up to person. Some of these might be forwarded on to friend. Some might not. But I don't care. I just want to get that person back and continue operating. All I care about is that there's the person there. So all of these return self. And I can continue operation. So this is pretty much it. This is that gem. So don't install it. And I can walk you through so you understand. The module direction is extended on the class. And that adds class methods. So I have a class method called command. I can pass in a hash. And what this does is just loops through the hash where I've got the keys are the methods that I want and the values are the accessors that I want to send them to. So the related object. A whole bunch of stuff. It generates a string to define a method. It takes whatever arguments or block that you might pass on, sends it along to the value. So the value there would be friend in this case. And that's it. But the important part of this is that it returns self. This is fairly close to what forwardable does. But it returns self. So I can do the exact same thing that forwardable does. Just write configuration at the top. For all these methods are now exposed on this person. But I'm just going to send them off to that thing to happen. But when you use forwardable, you get the result of whatever it was. You're not explicitly stuck with commands. In this case, you are. So you can still write short code. You don't have to define every method now and return self at the bottom of each one. You don't have to just say, well, we can't use forwardable. I've got to now define them all and return self. You can just do some simple metaprogramming. And that will work. So that's what it would look like. Very small change from what forwardable has. So you can see, you can list other methods that you want to send on. So when you leave, go change your code, return self, and run your tests. Find out. Did you break it? Maybe there's missing objects. Maybe responsibilities are in the wrong place. But it did break.