 Anyways, I want to get through this talk because I've got a crap load of code to show you guys some really good codes I'm really sophisticated code, and I want to bring everybody along on that journey So the idea behind this talk is you've got Yehuda cats, you know who has done a lot of refactoring in Rails 3 over the past year and a half and The idea behind this talk was I took a look inside Rails 3 try to identify some of the really interesting design patterns that they've used inside Rails 3 and Show you guys, you know explain them in a way that everybody could understand them not just Yehuda So but when I first started getting into it, and I started the you know researching into it I just found I just went and to find like the most interesting design patterns And it so happened that some of the more interesting ones weren't done just by Yehuda But by people like Carl Lurch people like Josh Peake and people like Carl Huda which if you're not familiar is sort of the alter ego when you know Yehuda and Carl pair at Engine Yard They pair under the github name Carl Huda also known as emo cow so Our topics look a little bit something like this We're going to be going through looking at method compilation looking at microkernel architecture alias method chain versus super active support concern and finally catch throw in bundler So a couple techniques There's going to be a ton of code in here So really I know this is before lunch But I think if you really focus down on some of these code things that I explained through the way I think you'll find some really interesting patterns So before we get our feet wet you have to the experts in the room bear with me for a minute I know there's probably some people who are beginning beginning Ruby developers here, and I don't want to leave them out So before we get into the advanced stuff. We've got to test the water a little bit I apologize if this seems really basic, but I want to make sure everybody's on the same page a tribute accessor Right a tribute accessor is the same thing as saying, you know death city death city equals So basically we have some attributes, right? Initialize when we call it initialize basically that's me when we call simple print new it calls the initialize method Right and we can set variables from there When we have method missing Basically that means if there's a method in there and we call it like s dot ruby conf It's going to call the method missing method, right because it obviously doesn't exist so if we go to the command line and we do simple print new Taiwan And it just is going to set the city variable, right? Then if we do s dot ruby conf we get back ruby conf Taiwan, right? Right, okay eval So here we've got some code. We've got a hash. We're going through each of the keys We're gonna go through each pair of the keys inside there. We're gonna do something with eval We're basically gonna do eval key value So basically what we're doing here is it goes through iterates through this twice and creates two instance variables One called name and one called location, right and actually runs that code right in there So if we do puts name location, we're gonna get bar camp Orlando, right? I Didn't I guess this is an audience participation thing now. That's interesting. Okay, so instance eval if we have some code Like this we do class test print. Hello puts. Hello, right now if we do we create an instance of that We get back. Hello. Now another way we can do this is we can do test new instance eval and print and we get back The same thing. It's basically the same thing print is going to get run in the context of the class right Yeah, okay Cool another way we can write this Right if we did something like this, well, let me see no no no man What am I trying to say here instance eval we add the method right in there and we can you know run the method Makes sense we get back to look to Mind you though if we now went and created another instance at this point It wouldn't work right because we only added the method to that particular instance of the object. Oh, yeah Yeah, right. Okay Class eval just make sure we all understand class eval so we have class test We can extend it we can do something like this we can add methods we can open up our classes That's why Ruby is awesome We get back we print it out we get Ruby 5 another way we can do the same exact thing is By simply doing test class eval, right? So these two things we get back Ruby 5. Sorry. These two things are the same, right? Okay, now that we have that all the way Let's jump into it so Method compilation let's take a look at method compilation take a look at a really simple example of where we might use Effectively on some simple code and then we'll take a look at where this is implemented in rails 3 so We've got simple print new we have push it pop it and top it so let's say we have this code up here We want the output to be this What code do we need to write inside simple print to make that happen? Think about it for a moment. What do we need to make that happen? What might the code look like? Well one solution might look something like this What are we basically have first we're sending in the actions? We're setting the actions attribute accessor We're then we don't have this print method and Then we're going to use method missing in this instance So basically when we call those methods it checks to see well is the method one of them that we initially sent in If it is then print it out Make sense I don't want to go too quickly think about it. I know it's Almost lunchtime. So if we ran this code 3,000 times 30,000 times excuse me. We would find that it averages maybe about five seconds if we did it a bunch of times at least So my processor right so five seconds now. There's another way. We could write this We could write this using method compilation. What would that look like? Well over here, we're gonna have class better print We're gonna send in the initialize and we're gonna go through each of the items in the array Inside there. We're gonna call instance eval and We're basically going to define some methods for each of the items that we send in And I'm gonna move this over to the left hand side of the screen So basically when this code is run, it's gonna go through each item in that array and create methods for each item Right, so basically it's creating each of these under the covers one at a time Right, and then when it goes to actually call those methods. It's actually calling the methods that it generated on the fly right, I Say that too much. I'll stop doing that so using method missing about five seconds Using instance eval about 3.5 seconds That's about 30 percent faster Now you might be wondering what's going on under the hood and I was wondering okay. Why why is that? Why is it so much faster? So I jumped into ruby prof, you know, which allows you to do profiling and I ran both of those using ruby profile So method missing it looks like this method compilation looks like this if we get rid of the stuff that has in common We end up with this so if you take a look at this you can see that with the method missing version of this It's calling each of these, you know, 90,000 times. It's checking to see if the string matches If it does then it calls it whereas using method compilation. It's just calling the methods 30,000 times And that's about it. So it's doing sort of less things therefore takes less time the first commit that yahoo to did to rails Was using method compilation? He basically went into the mime types how we declare the different mime types for the controllers and made it use method Compilation so it was a lot faster when we go through and figure out what mime types a controller will take Another place you see method compilation around three are with the callbacks So stuff like before filter after filter around filter skip filter I'm not going to show you the code for this because it's very complex But basically if you think about this instead of every time an action gets called Going through all the filters and say do we call this one? Do we call this one? Do we call this one? Let's just compile a single method that says when you call the show action These are the three methods that you should call based on the before filters. So it just compiles a method It's about ten times faster with method compilation. It's financially faster Another place we see method compilation around three now is with layouts. So when you think about layouts, right? Basically the old layout code did something like this it looked and said okay What layout do we render is it a string do this if it's a symbol do this if it's a proc do this if it's a layout Do you know is it false through this if it's lay out and they'll do this and basically every time An action got called it would go through and all go through all these conditionals, right? so We made this faster Using method compilation. Let's take a look at that code. So this is the actual code from inside rails I apologize if it's a little faint to see in the back Basically if it's a string Let's do a class eval and create a method called underscore layout if it's a symbol Create the underscore layout method do something if it's a proc create the underscore layout Method so basically it's going through and of course the first time it runs this by the second time It's simply going to be calling the underscore layout method So that's an example a couple examples of how we've used method compilation in Rails 3 to speed things up Next up we're going to be talking about microkernel architecture and one really good example of this We see an abstract controller in rails 3 Which was predominantly the work of Carl Lurch So previously in the action controller stack It had a lot of stuff in one package a lot of stuff in one package The first thing I did to clean this up is they moved there all the router stuff all the routing dispatch stuff into action dispatch The next thing we can see is We identified certain components that are common that at the common the very base level and put those sort of on top of something we call abstract controller and If you take a look inside of rails inside the rail source you would see that There's an abstract controller directory now and each of these you know is a one-to-one mapping between you know the different Modules so it's really easy to if you want to learn about callbacks you go read about callbacks in that file The only file that doesn't it obviously didn't doesn't have a pointer here is base, right? That's the very base abstract controller. Let's dive into that code and see what it looks like So here is abstract controller base It's an abstract class and the guts of it are all in that one method called process It basically calls the action somebody does a request calls the action renders out the action There's a couple other methods. It might look familiar here If you've ever did dove into the internals like controller path action methods But that's that's basically the gist of it. So we've got action controller base It's a micro kernel with a bare minimum needed for dispatching and we have all these additional modules that we can then stack On top of it to give it additional functionality Maybe we are for creating our own controller We would start out with abstract controller and only layer the modules that we need But we can pick and choose that way some of the stuff of this that these do you've got your before filters in here You've got your helpers in here and you've got your layouts in here We saw some layout code a minute ago. That's where this resides So we've got abstract controller base one layer up from abstract controller base some people might consider its own micro kernel is Action controller metal One of the benefits of having this abstract controller with these different modules at the very bottom level Means now we can use them in one other place where we need them in our rails out This is action mailer base So at the very bottom of action mailer base this used to have you know a whole another separate You know set of files set of classes set of modules now at the bottom of abs of action mailer We've got abstract controller base reusing a lot of code keeping it more dry Now back to action controller metal metal is where we start seeing rack It's not until we get to the metal layer where we see just enough to make it a rack Compatible rails out. Okay, so let's jump into metal Here's what metal kind of looks like it's an abstract class the first thing we're going to see is the call method I think I was here two years ago talking about rack or three years ago talking about rack Right, so if you guys are familiar the main component rack is that call method which we can see right there in metal, right? So our quest comes in it calls action Action goes through the middleware stack calls the dispatch Method and hey look in the dispatch method it calls the process method which we saw a minute ago in abstract controller So basically calls up to abstract controller renders the action and if you're familiar with rack you'll be able to recognize that that basically returns the status headers and response body because That's right from rack So at the very bottom of this architecture we have Abstract controller base all the modules we can stack on top of that We have action controller metal and metal also has a bunch of objects much of modules Excuse me that you can stack on top of that when you start adding these modules that layer on top of metal you start getting rails And you start feeling like rails And if you take a look inside the source you're going to see that there's also a metal folder Which contains all of these modules we can layer on top of it some of the stuff this gives you this is where we get our redirects This is where we get that new cool response to syntax All right, so it's these modules that you know big make rails feel like rails So Let's jump into the very top level the one that you guys have all heard before probably written it a couple times before Action controller base. So here's what base looks like all that bases at this point is it includes a bunch of modules So it lists all these modules in an array and at the very bottom Right, you're gonna see it basically goes through and calls include on all of them Right, so basically include all this stuff go through each of them include that Now when I first saw this I looked at this in way a second. How is that right? There's abstract modules and there's metal modules Shouldn't they all be included in here? That was a little bit confusing But what I came to realize is when I started looking inside the metal modules You see inside the metal modules the abstract modules get included inside the metal modules just where they're needed So everything's getting included, but where it's actually being pulled in might be inside another module that needs it We'll get back to that in a bit So here's the architecture diagram of the whole stack right at the very bottom You've got abstract controller base and the modules that lay on top of that one layer up you've got action controller metal and The modules you can lay on top of that and sitting at the very top is the action controller base The action controller base includes some of the abstract modules and includes some of the metal modules and metal includes some of the abstract Modules, so there's your architecture diagram of the sort of new You know microkernel architecture of the action controller stack So that's an example of microkernel architecture and one really cool side effect of this is all of a sudden rails has become a lot more readable This whole stack has become much more readable. It's a lot less intimidating to jump in there and go Oh, I need to learn about you know rendering I want to rewrite that okay Well, I'll look in the rendering module and everything that it needs that I need to know is going to be in that one module Then this can be better documented So I really highly encourage you the next time, you know, you think about you know, why is this behavior in rails? Why is it happening like this feel free to jump in and read the code? It's become a lot more readable Okay, we've got a couple more topics, but we have to test the water one more time Okay, and everyone's got to be on the same page with modules. So including modules, right? So we have this module print method basically, you know If I do include print method and I do test new print I'm going to get back Ruby So that's including at its instance method if I want to include it as a class method I use the extend parameter. Hopefully you guys all remember these basics and then I can do test print and get back Ruby 5 What if I want to include both instance and class methods at the same time? Right. Oh, I'm one step ahead of myself So what if I want to do that? So here I've got a instance method and I've got a class method And I want to include them both in here, right? Well, I have to do a little bit something a little bit tricky and Adam touched on this a little bit honest in his talk Basically, we have to do Self-include right and so this is how we do we add the extend, right? So it's include normally does just for instance methods, but if we want this to also give us the class methods We have to use this self-included little block here. How many people have written this type of code before just out of curiosity Okay, about half the room. Okay. It's not right. Cool. Another way we can write this is base extend Right, it's another way. We can do it same thing. We can do base extend And this lead us to talk so so now we have the basics out of the way We're going to jump in and talk to talk about some alias method chain versus super and then we're going to go into active support concern all right, so Here's your next code challenge. This is our class That's the parent class we have in a class user inherits from generic user We need to be we're going to do puts user new name and if we do this with this code We're going to get output Greg Pollack but the output we want is Mr. Greg Pollack, but here's here's the catch We can't modify the classes at all. We have to use some metaprogramming to modify the classes Okay, and all we can do is you know basically do Right there include mister. So we have module mister and what goes in there? That's the question what goes in there to make that work Well, what one way we might solve it is basically have do the self-included block, right? and Here we're going to say alias name without mister name, right? What does that do it basically makes it so that if we call name without mister it calls the same name method Then we're going to define our own method in this module called name with mister Which calls name without mister so if we call name with mister it's going to be mister plus name without mister Now we're going to add one more alias down here alias name name with mister, right? So that basically cancels out the name up there and basically makes it alias to this method instead right Right, so that works Now another way we could write these two alias methods. You see these two alias methods down here Another way we can write that is of course alias method chain, right? So alias method chain is basically those two alias lines, but simplifying it to one line. Who here has used alias method chain before? Okay, about the same very good Right, so obviously. Yeah, we can use alias method chain there and that would work And so this is one pattern that will work. However given this code. There's a much much simpler way To do this anyone? Super right right with the same code we can use Mr. Super and Basically because it's a you know, it's a parent class of that right? It's going to go through and call mister on there and then call the superclass great public Much simpler. So what this is telling you is that if you code in a certain way You don't need to use alias method chain. You can use super when you try to override things and And we see this a lot in abstract controller Which you guys are now experts on because I showed you the architecture diagram, right? So in abstract controller, you know, I mentioned here and you'll notice it So so basically metal has a helper's module You'll notice here also abstract controller also has a helper's module So when I first saw this I was like, huh, what's going on? Why is abstract controller of helpers and metal have helpers and what additional functionality does the metal helper give? So let's take a look at some of that code okay, so here we've got the Abstract controller helpers and this basically goes through returns a list of modules You know all your helpers modules for helpers. That's all it does The metal helpers module all it basically does is give one piece of functionality on top of it It gives you helper all so if you ever use helper all basically says, you know this controller can use all the helpers, right and Basically, if you look inside the code, you're going to see that it basically goes through and says if the argument exists all Add all the application helpers on to args then call super Right, so that's how sort of the modules are laid on top of each other They sort of extend from each other and really take advantage of super so that's alias method change versus super Next up and Adam talked a little bit about this and I'll go to it a little more a little more depth is Active support concern the most majority of this work was done by Josh peak. That's him. No, I'm just kidding. Who knows maybe it is him for all we know but Let's jump into active support concern. Okay, so let's say we have this bit of code and Let's say that it includes bar camp 2010 I've got this module what goes in this module to make that code work another code challenge What goes in there? There's a couple different ways you could solve this Right, I'm going to solve it using this method. I'm going to say self-included class eval In there I'm going to set a class method and maybe just to be complex. I'm going to make title a method so let's say Module class methods def title and then we do extend class methods, right? So doing those two pieces of code we get back bar camp 2010 Now there's an easier way to write this right We can write this using active support concern which Adam again briefly touched on so how would we do that? Well, we could do something like this if we do included self-year 2010 These two are now the same. So here's some of the differences you'll notice now we're no longer having to include the class methods and We're using this included block to wrap what we ran inside class eval So it's basically the same thing so basically what does active support do it does actually four different things And we're going to cover them all the first thing it does is looks for class methods and extend them So for example if we have something like this Right, it's basically going to take if we have a module inside our module called class methods And it's automatically going to include that The second thing that it does is it's going to look for instance methods and include them So we've got module instance methods here and basically it's going to automatically get them included inside of the class The third thing that active support concern is going to do is it's going to class eval everything in that include bucket You saw a minute ago So basically if we had some simple code like this and we included it It's going to take that run that inside of the class and Lastly and I think most interestingly It's basically going to include modules that get their included hook run on the base class, right? So basically we have a top module that looks like this We have a bottom module that looks like this right and Basically one module the thing to notice here is one module is including another module and they both have the included block in there Okay, now what's going to happen here is when we include it inside of a class Both of these included blocks are going to get run in the base class that was included by them Before this would not be possible Previously you would have had to get this functionality you have had to do this you've had to do include my foo include my camp and Only then would it run these both these methods in the proper sort of base class But of course we don't need to do that now It properly runs that included block in the class that includes them. Does that make sense that base class? and a good example of where we see this again is Back in the methods we were looking at a minute ago if we took a look inside This class here, right? So we've got the base Metal helper and we've got the abstract controller helpers. You can see that you've got one includes the other They both have the included blocks And if we take a look and we include them inside, you know action controller base We're going to see that both of these included methods are getting run on the base class Cool, so that is active support concern How am I doing on time? You good? It's gonna go Lunch is at what time I Got ten minutes dude. Sweet. Okay. I can get through everything. Okay catch throw So we're gonna talk a little bit about catch throw Yeah, I saw you see this picture. It just brings back memories But no, that's not my kid But it's funny because it's like you see this picture and it's not just the fear of you know Oh my gosh is that kid gonna be all right? I don't know if there any fathers in the room But there's also that fear that you know I've been there and you know you go and you do something that you throw it up in the air and all of a sudden you're realizing oh my god Did I just really just grew up really badly just doing this not just the kid, but just like oh my god What was I thinking anyways? So let's let's talk a little bit to try catch and throw some babies. I mean not So if you think a little bit about bundler, I'm not gonna give you guys like an intro to bundler or anything I think enough people have sort of heard what it is But when you think about what it's doing under the covers It's basically doing a depth first search of all your dependencies, right if you remember back from your college days It's depth first search so it's starting on the left-hand side Going through trying to resolve all the dependencies and it's gonna go on the right-hand side and try to resolve the dependencies And if one of them conflicts Well that could have repercussions in a few places It's gonna have to jump back to the other projects not only is gonna have one that works But then jump back to the other projects and see if you know We need to keep a different version there and if we had to switch versions there Then are all the dependencies under that gonna be compatible with that version too, right? It's not a simple piece of code, which is probably why it's sort of taken a while to get bundler, right? I think they've rewritten it like 10 12 times to get it right Excuse me, and if you take a look at some of the really complex code, they're using some interesting control flow So control flow basically control flow like these stuff, right? You've got your conditionals another form of control flow that we use in Ruby is your method return method invocation We use raise and rescue predominantly for errors And there's one other that we rarely use in Ruby that not too many people know about called catch and throw Who here has ever used catch and throw before? Even less. Okay, good. Yeah. Okay. That's about right probably. So what is what is catch throw? Okay, basics look like this so you declare a catch and somewhere inside that catch block you have a Throw and basically what that's going to print out. It's basically going to skip everything else after that so in this case it would print out this will not get executed and then What's interesting about it is you can also return stuff. So if I do throw marker and return hello We're basically going to get you know, this will get executed and it will return hello, right? So this is you know kind of similar to you know, when we do throw and rescue begin rescue, you know raise But that's predominantly for error messages, you know, and this is more for control flow So let's go back to this diagram We thought a minute ago about you know, how we're doing the depth first search here going through all sorts of different stuff It goes all the way over here and then it has to sort of jump back over here doing some sort of control flow All right, so inside bundler. I'm going to show you a little bit of code So basically we've got this when we're resolving our requirement. This is inside resolver It's a really cryptic piece of code if you ever really want to really complex a piece of code to wrap your mind around it So when resolving requirement, we basically do catch and give it our requirement name When an activated gem is conflicted At that point we want to jump back to the initial requirement and the way they do that is by doing throw So we return the parent name existing required by last name, right? So that's going to jump back To that point in the code When a gem is not activated, but it's dependencies conflict It's also going to do another throw and send it back to where it was resolved initially so that's sort of a glimpse into catch and throw and That's pretty much we got through a lot. I think in that talk But if there's any sort of moral of the story that I hope you guys take away from this It's don't be afraid of reading the source, right because it's become a lot easier to read and Don't be afraid of making it your own with a lot of these sort of the microkernel architecture and all the different modules It's become easier than ever to create your own version of rails if you really wanted to you want to create a controller That's maybe just specifically for Serving up code it's JSON for iPhone apps or something right you could easily go in there and start from abstract controller And simply build and build and build and only take what you want nothing more And you create your own little skinny application stack. So it's become much easier to customize which I think is good I think it'll help rails sort of Stay mainstream That's great commons a couple things So I've got slides in all the slides that you are all up at the top If you like the talk, there's you can rate it. Please rate it. Give me feedback. I'm always looking to improve Really appreciate you guys coming to the talk We printed out some NV lab stickers and we got some Ruby 5 stickers up here If you guys want any feel free to come up and grab a sticker sheet They're kind of neat And also I do the Ruby 5 podcast and I always carry around my portable microphone So if you create some sort of open source tools You know you did like a recent release or you have some library that nobody knows about you want to get the word out Please come find me during the conference. Maybe we'll get a little audio and get you on Ruby 5 Do I have any time for questions or we'll take we'll go to lunch and you can questions you can take questions afterwards Okay, yeah, well I appreciate you guys comment if you want to go and get a jump on lunch You're welcome to otherwise. Are there any questions? Everyone's hungry Let's take a look at the slide later because I can't picture everything you just said sorry And then the questions I think everyone's dispersing you have any questions just come find me come up here afterwards. Thank you guys