 So today, I'm going to be talking about making Rails 3 a better Ruby citizen a few things to cover before I start in the abstract I focused pretty heavily on rack. I'm definitely covering rack in this talk But I'm going to be going a little bit more in-depth about other aspects of how rails can be a better Ruby citizen Defining what I mean by that and then explaining how we're doing that Another piece of housekeeping. I it's called making Rails 3 a better Ruby citizen not making Rails 3 a Ruby citizen Rails 2 actually does a reasonably good job of working with other Ruby code. There are a few exceptions things like JSON Working with other people that use active support So there are exceptions to where Rails 3 doesn't work very well with other libraries But by and large Rails is a piece of Ruby code and works well with other pieces of Ruby code I'm just talking about how we can crank it up a notch and do even better than we've already done in the past So who am I I work for a company called Engine Yard. I guess I can keep this slide very short since we've already covered this Engine Yard sponsored me to work on a project called MIRB for about a year after I started working for Engine Yard MIRB was basically an experimental fork of rails. So we Took a lot of the ideas of rails and made something that was Really cool, which we thought didn't have a lot of the deficiencies of rails and I worked on that for about a year about towards the end of that year what we discovered was that the deficiencies of rails were absolutely not intractable and In fact not very Conceptually difficult to fix and once we got everyone on board with actually getting past some of the political and social issues We determined that it would actually be rather easy to get the ideas that made MIRB supposedly a separate entity into just rails So now I work full-time on rails at the moment mostly it's about refactoring rails to make it a more modular integrated experience But eventually we're just going to get back to exactly what we were doing with MIRB and what rails was doing with rails and continue I Also work in the same room as the guys who work on Engine Yard solo Tom already sort of explained what Engine Yard solo is if you haven't checked it out yet. Definitely do so also as Tom pointed out there is a URL you can go to to enter of Is that readable? You don't actually have to read it. It's engineer.com slash go Ruko So if you go there, you can enter for a contest to get some free solo Now that I'm done talking about me, who are you who's the audience the audience is basically made up of a gradient So there's three people here, but it's really a gradient of a spectrum of three of people There is the guys to do app development basically have never looked at the internals of rails rely almost exclusively on the APIs That you can get by reading agile web development on rails might be doing relatively complex stuff They might be doing complex Ruby stuff But for the most part the people I refer to as app developers never delve into the rail source code or dig into Plug-in or extension APIs. They focus mostly on what rails offers you as an app developer Then on the all the way on the other side of the spectrum is guys who write extensions or hack on rails I'm all the way on the other side of the spectrum And then there are just people who may basically write extensions So new relic for instance might be an example of someone who focuses heavily on extensions people who work for that company In the vast middle though are people who might be writing applications or might be focusing on extensions But actually end up doing some of the other most commonly people who do apps for any amount of time end up inside of the guts of rails So when I say power user what I really mean is People are experienced and therefore they have their own ideas of how they want to use rails extend rails Web shops that want to take things from one application to another so they don't have to rebuild the same thing over and over again And just long-term projects where after a certain amount of time you end up having to modify the way rails works or the way rails makes expectations for one reason or another and This ends up being common. I the reason I was in the power user category before I started working on Mervin rails was a long-term project So I started working on rails and on that project about little before rails 1.0 I took it all the way to rails 1.2.3 But we had a large number of tweaks modifications and outright forks of the rail source code as a result of the fact that the project Just lasted a long time and we needed things to work somewhat differently And we were trying to obey the dry principle in other words if rails already did a lot of the work We weren't going to rebuild it ourselves. We were going to try to modify rails to get it the job done So what do I mean when I say Ruby citizen becoming a better Ruby citizen? I Actually mean three different things Number one. I mean rails uses existing Ruby libraries so as to avoid having to reinvent everything itself Some examples are test unit, which is ready is true Trying to use existing testing infrastructure on top of rack rack itself, and then rail 3 is going to start to use erubus, which is a Replacement for erb that also allows you to extend the templating language a lot better when I say rails is used in I mean rails being used as a library for other things Sprout core is not something that uses rails. It's something that uses merb But the idea is that frameworks that wanted a lot of the functionality that's available in rails or something like merb could more easily Just use rails itself without having to do a lot of hack up or start over right? So making rails a much more usable thing that could be used in other things that expand radiant is a good example Some place that it works right now active merchant uses active support Finally rails needs to work very well with other language other libraries an example of where it might do so right now is Hamel It's really easy to drop Hamel into rails Doesn't work so well in rails 2.3 with json or data mapper and those two are being resolved in rails 3 So basically looking at cases where there are known issues with regard to rails working with other libraries and Making that work better So let's start with rails using existing language features other libraries the most obvious example this is rack So let's take a look at what rack is exactly and why it's cool. Why it helps us meet this goal So at its core Rack is just a basic interface that says that if you have a server You can talk to an application using a standard mechanism and you can expect the application to respond using a standard response So if anybody here is programmed with something like CGI or mongrel or web rick or IIS or any of these things You'll know that before we had rack we had this problem where every one of these servers would use something that looked kind of like CGI But had all kinds of inconsistencies and then expected back a very Specific response that had to do with an API that it was using so what ended up happening in the real world is That all these guys made stuff for rails because rails was the gorilla in the room and every other framework Ended up having to rebuild it themselves. So we had you have MIRB Sinatra There was a talk of waves earlier all these frameworks would end up having to write special handlers to handle whatever they wanted and Then we saw one day that there was somebody who started work on a project called rack and from the most naive perspective when you first start to look at rack It looks like it solves that problem. It looks like it's main utility It solves the problem of having a bunch of servers that have different interfaces And now there's a standard way for servers to talk to you and a standard way for you to respond And when we started working on MIRB 1.0 This was huge for us because suddenly we no longer have to worry about managing all these adapters And it led us basically support any server on top of rack For us it was a bunch of things we were supporting separate adapters for all these things in MIRB 0.9 0.5 so this was pretty huge for us going into MIRB 1.0 and This was really happy We like this But actually turns out that rack is more than just a nice common interface rack allows you to build Something called middleware so if you start to think about it If rack is basically a standard that says If rack is basically a standard that says here's how you send a request in and here's a response you can receive every little piece of Machinery inside of that doesn't really have to know anything other than I am expecting to receive a request in a certain format With an environment hash and I am expecting to return a response And if you're stuck in the middle that just means that you're still receiving an environment hash It also means that you're going to be receiving a response from downstream But this means that it's things are very very simple take the example of path prefix So in the past if you wanted to implement path prefix You would let's say you wanted to put a blog in slash blog slash Whatever stuff you would have to put a bunch of code in rails or MIRB or something like that to say Every time I would expect to have to care about just generating a URL for instance I have to put slash blog in the front of that and every time I want to talk about generating a URL I mean recognizing a URL. I need to remove slash blog from the front What the path prefix middleware does is it takes in that standard hash Somewhere around there's something like path info a key called path info that contains slash blog slash whatever and it just takes that out So any downstream rack machinery just sees the entire URL as though it was blank Starting from slash and then if you generate a URL So let's say you generate slash post slash one on the way out The path prefix middleware just adds slash blog to the front so as far as any downstream Applications are concerned. They don't have to worry about this issue of path prefix at all conditional get is similar conditional get says If I am receiving a request for something in which it says if the e tag is this and I already have one or if not modified Right, I can just skip that process altogether and return which means I could basically short circuit the effort of getting all the way back into the application and Deal with it at a middleware layer Again static very similar what static basically says is if you receive a request for a URL and I have a file matching that just return it Right away. Don't bother going down to rails. So basically you can have middlewares that are very Single purpose don't have to care much about what else is going on can be developed for things that are not necessarily rails so other frameworks and rely upon a single standard and Rails 2 3 took this and said wow now that we have this idea of rack machinery That takes a request and returns a response We can actually rewrite how rails works to make more to make this work better and what they did in rails 2 3 This is before my time in the rails world is they said Let's make the router a thing that takes a rack request and the router will figure out what rack application to send to and so The controller is just another rack endpoint It's just a rack application and the router's job is to figure out which rack endpoint to go to and this actually was very smart and Reduce down the entire issue of control the entire controller down to a simple rack application that you can now actually rather easily Mount inside of another situation another thing that has that has the ability to route to rack Rails 3 actually goes a little bit further than this What we realized was that even though we were going to a controller Which was kind of the same as a regular endpoint controllers still had further dispatching to do so if you go to a controller and That and you you're going to the show action The controller starts to figure out based on something which in the case of rails is a magic key in the params hash That it should go to that action But actually good rack endpoints don't do any further dispatching. They're just single endpoints and if they are Due for the dispatching there's a standard way to do it that doesn't involve inspecting magic hashes so the solution for rails 3 Was basically to say the router actually points directly at an action the router doesn't point at a controller the router points at an action and The way to get at that action in rails 3 this works on master right now So say controller action name of action and that returns back an object that was that is a rack endpoint And then you can just call with the environment the standard environment you can call into the app into the application, which is the action you can also use an application which has gotten using controller action as middleware and Then at app dot whatever would work inside the action So at app dot call would work inside of an action now Of course This is not the standard way that people are going to be using rails the standard way is going to be the exact same way That we've been doing up until now But this means that the internals of rails works out work a lot better because the internals of rails are just Receiving a rack request to figure out what we're a request to go to go to that rack request Right, so if you follow the path as much simpler and it means that if you do need to use Rails for something more complex but in a non-standard way You basically have all the features of rails in something that is just a standard rack thing So you can put a rack action a controller action into some other context. That's not rails rather simply middleware is actually good example of Things that rails uses things that rails works with and things that rails is used in right Rack ships with a bunch of middleware and rack works Rails works very well with those middlewares it uses some things and in fact has shipped some stuff upstream So for instance, there's something called rack lock which knows whether or not to apply a mutex around the entire application and Rails ship that upstream so rack lock is now available as a middleware and rack and any other framework that wants to Use it can happily use it There's also a bunch of middleware that might exist on the side of rails that rails might want to use like a rack bug and Rack bug is basically just a middleware that allow that will provide some information It's basically debugging toolbar Per request and rails doesn't really know anything about that. It kind of knows about rails perhaps at the moment, but it doesn't really need to and Everything works similarly something like hop toad could be implemented as a rack middleware Just sits on the side of rails rails doesn't know about it It doesn't really know about rails it just deals with exceptions and sends them on and finally rails ships with a bunch of middleware like session middleware that Are usable in other frameworks that might want to use them We're also making sure that rails if you say require Action controller slash or action dispatch slash middleware slash session You can do that without fear that it will pull in like 10,000 other files and You probably don't want to do that in something like Sinatra So we're making sure that little that files that are expected to be used downstream Again like sessions or parameter parsing or general rescuing logic Those things are not things that are things that are easily able to be used downstream by Micro frameworks without for fear of memory problems Now you may not want to depend on rails as another application But in reality depending on action controller isn't is really only a hard drive concern If you don't at the same time have to worry about random stuff from rails getting pulled in So we obviously have to work with people downstream to see where people feel comfortable Depending on something like action controller when they really just want a middleware But it's not a technical problem. It's more a social political problem that we have to resolve Now in rails you can also use middleware the same way that you kind of the same way that you use them in rails themselves And that's just config.middleware.use foo and I've labeled this an application level concern Because I would I definitely anticipate people creating plugins that are expected to be you set up using config.middleware.use So if someone makes a middleware they could have it all wrapped up in a plug-in or they could say use config.middleware.use foo And then some options and this would be in your config block Finally, there's a benefit to using rack for integration tests Instead of Rails having to set up a whole bunch of stuff that knows about how rails works internally dispatches that stuff Receives responses back tries to analyze how things work in a rails context. What rails can do in rails 3.0 is basically just treat rails like a black box and send a and pretend the testing thing is just a server So instead of testing being a special magical Testing thing that requires a whole bunch of special APIs tests are just a pretend server Integration tests and they send a request that matches the rack request and then the application not knowing any better Sends the standard rack response which tests know how to manage there already exists a something called rack test Which works just fine with rails 3.0 on master right now because of the fact that it just uses the rack standard Something like that is going to be in rails 3 Which will also mean that you can use the rails integration test framework to test something like Sinatra because the rails integration test framework does nothing more than send a bunch of requests to to a rack endpoint So where are we going with all this? Crazy things that you probably won't ever want to use Most people but which are interesting that they are doable which is making any piece of rails Not a special thing anymore making any piece of Merb making any piece of Sinatra not special So you can have a top-level router that routes sometimes to a rails controller sometimes to a Merb controller Sometimes to another rails router which can have its own stuff under it Sometimes to a Sinatra app so basically instead of saying the rails router is a very rail-centric thing the rails router becomes a rack-centric thing and the standard API is pretty much the same as it is right now you're Shipping off to controllers nothing changes from your perspective, but from a power user perspective There will be a bunch of new API's that let you ship off to other kinds of rack things So basically the whole rack idea is to make rails just another thing that implements rack and work with other things that do The second category of thing that we're trying to improve in terms of rack citizenship is Making things work better with existing rails and basically that the main biggest thing in this is all our agnosticism We want to make you be able to use rms together with rails now when we say all our agnosticism the normal response from People who use rails is what why is your rm agnosticism any special any why do you need our agnosticism? Why can't you just use datamapper as a rail of ruby library rails is ruby supports ruby libraries? Why can't you just require the datamapper gem and use it and in fact that is true You can use datamapper today in rails without any problems and it'll work But there are things in rails that actually assume active record. You're probably familiar with form for Object and there are other things like saying link to some object right a bunch of rails assumes that if you provide active record objects Special things happen basically the whole simply helpful stuff that got added to rails in the to oh period is a bunch of things that say If you use active record, we will do magic and these this is good magic. We like it. It's good You can say render partial some object and it'll figure out where to go the thing is that that object Can actually be a bunch of different types of objects, right? It can be active record, which is already supported it can be sequel it can be datamapper Which kind of works like active record or it can be couch TV simple TV, right? It can be any kind of thing that represents data persistence and You want there's a similar kinds of semantics when you say form for so you want to be able to say Form for some couch TV object and you want it to still be able to you want to still be able to say f dot Whatever text field right f dot text field something you want this to basically work Because it from the perspective of form for your couch TV object wall a radically different thing isn't actually that different So murr 1.0 claim to be or am agnostic. Here's the secret sauce The evil secret sauce, which is that we basically just hard-coded the rms. We knew about inside of murr. So If you look at the I guess the fourth line of that method over there, you see that we say Or the third line we say that your sequel if the objects errors don't respond to each and The line right above that says if you don't respond to errors return nothing. So we basically said We know about some interfaces will hard-code them in other words There were two valid ways of using murr from an ORM agnostic perspective Option number one was to do the active record and data map per thing which had a valid question mark method a One way of doing errors and new record question mark Another way to do it was to use sequel which also had valid question mark a totally different errors object and new question mark Instead of new record and so we hard-coded the fact that we knew these things directly into murr The thing is that it's better than it looks because all you had to do if you were writing your own object that you Want to support for was implement one of those two interfaces and it would work So we didn't say if you're sequel we said if you respond to this interface So we basically defined a couple of interfaces you could implement and that actually worked for people So people use couch to be with murr reasonably easily because they just made it implement one of those two interfaces and that's fine We probably should not have said sequel equals in that method. We probably should have said like option two equals right something like that So it's kind of better than it looks at the same time There are definitely cases where it falls down where you can't really modify these objects or The errors object is already in use in sequel So imagine we hadn't supported sequel since sequel already has an errors object You can't just override that errors object and have it respond to the right thing because it's already in use internally So it's kind of okay, but it's not great if someone already use valid question mark for something else Basically, you were screwed right if valid sometimes returned false when it really meant true for some reason because it meant something else internally Suddenly murr would not work So the solution to this problem is to basically provide a way of saying Given an object that I have I want to use some other a proxy basically So the default proxy is just to say new record question mark proxies Valid question mark proxies and errors you have to implement yourself because it's pretty complicated Sequel for instance, and this is only part of it sequel has its own errors proxy thing But for a new record it just proxies to new this is pretty good in terms of of had a Support multiple rms and basically means there's two options for rm writers This is not two options for you as a user for you as a user It's all transparent you don't have to worry about which rm you're using as long as you use one That's claims to be supported by rails everything will work exactly fine without you having any problems whatsoever But as a person who wants to support a new rm that hasn't been supported before you have two options Number one is compliance basically means either the rm itself just works exactly like active record data mapper does that Or you write a shim that includes the method So if you have a thing that doesn't respond to valid question mark errors or new record question mark yet You can just provide a thing that gets in a module that gets included inside the object and everything will work fine The second option if those methods are in use already is to provide a proxy layer That says basically what I showed a couple slides ago that basically says given a sequel object It uses these methods to proxy to the real one and basically what you do is you specify you provide on your object a two-model method This is probably gonna change. I feel like this is too generic but something like a two-model method on the object and That will return either yourself if you're compliant or a proxy object that knows how to pretend to be active record So the bottom line is that somehow or other you have to pretend to be active record if you could pretend Yourself that's good. That's actually the more performant way to do it if you can't pretend yourself. You can provide something that pretends for you If you look at how this works in sequel So as we showed a few slides ago sequel has valid question mark Which works fine and invalid errors object in terms of active record and new question mark And we basically just provide a wrapper around that around the object that responds to the messages correctly active record and data mapper as I said before Already work and so they could just return themselves for two model So what about code changes when we first talked about where I'm agnosticism It seemed like we would have to go throughout all of rails and make radical changes to how rails works turns out not so much Let's take a look at error messages for which is a rather complex usage of active record basically what error messages for does is on the top it first collects the object that you want so You say error messages for some object it goes figures out what the objects are and then moves on All we need to do in order to work with the new support on rails 3 Is say this objects dot map bang? Oh Oh dot to model And what that basically means is that instead of having the objects array? We replace the objects array with something that responds that is like active record So bottom line here is that in order to improve the in order to make it very likely that we don't break things on the way and in order to Still support any ORM's what we've done is say since act since rails already understands active record We're just gonna add lines above the usage of active record and a bunch of methods that expect it to work to convert the object into Thing that responds to active record Now from a purest perspective somebody might say what is that wise active record so great Couldn't you have come up with a better interface that's like super better and yes We could have done that that would have been probably the purest way to go about it But the pragmatic way to go about it is to say rails only uses like three or four methods So if we can just tell everybody to respond to those methods Then we can avoid having to rewrite all of our code and so that was that was the right way to do it I think the second place where we're making rails Work with other things better is JavaScript So rails 2.3 does JavaScript in a very very non-agnostic way you write something like this Which seems rather pretty you could say remote form for user it looks like a form But the JavaScript the code that comes out. It looks like this. It's basically a bunch of code in line and also very very Prototype specific so you see new Ajax that request slash user asynchronous true eval scripts true it's not realistic to expect jQuery or Mootools or dojo to take a look at this stuff and create its own Ajax Request that proxies or something like that that would be the the way we did it in active ORM Because of the fact that the JavaScript code it gets admitted here is extremely wide-ranging does a lot of stuff and Uses the global namespace. It's not realistic to use that same approach. So we need to do something else One way to do it is to basically more explicitly support j rails And what j rails did is it basically cloned the exact all the JavaScript helpers and made it emit JavaScript jQuery code So instead of this we get something that looks like jQuery Unfortunately this requires for them having to basically clone the entire interface so one thing we could have done was Make a sort of an intermediate layer that j rails could hook into and emit its own JavaScript But it turns out that for a bunch of years now, we've known that there's a better way to approach this whole problem and that While it has been somewhat cumbersome and when rails was originally created and therefore rails did not take this approach It is now no longer particularly cumbersome and that approach which we're going to take in rails three is that instead of emitting A bunch of JavaScript on the page we're going to emit markup and that markup is going to be utilized by the JavaScript libraries That will be shipped with rails or provided as separate library So how jQuery might handle this markup that gets submitted might look like this Basically what this says is for every form that has the class remote make up Find a submit event and call HX submit which is something that comes to jQuery Basically the live as opposed to bind to jQuery means that instead of having to bind it to every single Form that remote that exists at that time It puts the actual click binding on the document so that if you add another form later Let's say via Ajax that binding still exists So this is sort of a missing piece of the puzzle the ability to say very simply I want to bind to something that doesn't exist now Because very commonly rails will add some new stuff some new HTML to the page using using Ajax And then the old way you would have had to do some cumbersome stuff either in the JavaScript or in the Ruby code to make it work Correctly so now we've basically solved that problem because all the libraries have reasonably good event delegation code and we can sort of Throw out the fact that we in order to work around one cumbersome thing We have to do another cumbersome thing and now do a much simpler simpler thing Of course rails will obviously ship with a prototype thing I'm planning on writing the jQuery version and the dojo and move tools guys have already signed on That they will also be shipping JavaScript libraries that hook into this markup that we're going to be generating The very last thing is that it becomes a lot easier to actually sort of move from the things that ship with jQuery into your own stuff because now If you have some markup that gets omitted It's just as form class equals remote and you want it to work a little bit differently You can basically just delete the or comment out or remove the code that comes with rails that jQuery.js That handles formed out remote and replace it with your own handler Or you could bind your own handler onto that markup to do something in addition to what rails already ships with so Basically, this means that you don't have to really worry about code that gets omitted anymore now jQuery and prototype and move tools and dojo and other frameworks are just providing default bindings for markup And you can provide your own and that's really good The last category of thing that we're making better is things that are used in so making rails a lot easier to be used in other frameworks And basically I'm going to talk about effectively what we're doing to refactor rails to be a better a better target for Your own stuff. So this refactoring obviously helps rails internally It helps you to read rails, but it also helps using rails for stuff that you want to write that isn't necessarily rails The very first thing that we did right away when we started was look at the filters because if you profile rails 2.3 With very simple actions not complex actions Which in which usually the stuff that you're doing takes up most of the time It turns out that filters were like 20% or something of the total time again This is not 20% of your active record heavy action because active record is going to be 98 99% But in an action where you're returning a string filters were very expensive now one thing you could say is you know That isn't very common hello world type thing type applications But the question is what if we want to use filters for other things or if we want to be able to easily support applications that do very little So advertising networks for instance receive a large number of requests and need to return effectively something that comes out of memcash And so for those sorts of applications it becomes very important to minimize the overhead Rails has historically focused on your application, which I think was the right approach in general We want to make your application move faster, but now is a good time for us to go back and look at making rails better target for Applications that do a lot of heavy caching small strings and stuff like that So filters which we wanted to be more usable in applications small applications That do a lot of traffic as well as other places where you need performance are a thing We looked at and when we looked at filters what we discovered was that there were a bunch of things that were support that existed in filters throughout rails and There a lot of them had been factored into a common implementation called call active support callbacks Before after and some condition support was in active support callbacks but around support and skipping support was actually added to Was actually part of the active sorry action controller base implementation So if you wanted to support around filters or skipping in a non-action controller base Context you would basically have to copy that code which actually was very action controller specific So it did stuff like skipping might actually look at action controllers Array or something like that. So they're actually things that couldn't easily be factored out So if you wanted around filters for instance in tests people might have asked why aren't around filters in rails This test stuff. Well, it's because it was not very easy to factor out so what we did in Rails 3 now as we wrote a callback system that supports all those features including performance, which didn't exist before In one specific implementation and then a small wrapper an action controller to add sugar that looks action controller So for instance the base implementation is not going to support like only some Some action because only some action doesn't make any sense outside of the outside of the action control implementation When you say only some action what you really mean is if proc Controller that action name equals that action name So what we needed to do is write some code in action controller that converted the sugar that exists to make certain types of things easy Into the standard implementation, but I think it's like 50 lines of code or something like that compared to 600 lines of code that existed before to wrap the this version the version that supported before after and conditions We also took a look at performance and tried to see why it was taking 20% of the time And so here's an example of a very simple before filter. So some people do use all the features all the crazy features But some people also just say before filter one before filter two right and they expect that to be reasonably fast You would expect it to be reasonably fast. All it's doing is running a bunch of methods But actually what happens is it does a lot of stuff. It does first of all What kind of filter am I in this case? It's a symbol. So there's a case statement step one the second thing to say is are there any conditions? So did the user put any conditions? There's no way to know in advance if you put conditions You have to check every time are there conditions the next step is have you actually skipped? The callback so you may have a before filter one But you may be in a subclass that has registered to skip it. So now you want to check have I actually skipped this Right, then you want to say am I actually included in this action? How do you find that out you check the only you make you check to see if it's not in the only list and you check To see if it is in the accept list neither those are true So the act it is included in the action and finally once it's done checking all those things and a bunch more that I couldn't fit On one slide It goes and does a send call to one then once done with that it says did I actually perform the action? Which means is there anything in the response body? No, okay do the same thing over and over over and That's just not very perform it right. There's a whole bunch of runtime checks that we actually know in advance so we know in advance all these things and We're just not taking advantage of it. What you actually want is this Right, you want a method to be run that looks roughly like this runs all the methods doesn't you send doesn't do any checks Saw us to check to see if any of the callbacks performed. That's actually something that potentially could be Like in a crazy world of actually writing Ruby code that Jits Which is doable we could do even more work to try to reduce the Constant check and see if you perform, but we're not going to be doing that yet because it's Obviously not the most expensive part of Rails anymore So you basically want a method that looks like this that already takes into advantage all the things that are Determinable at static time and makes a method out of it and you want to be able to perform the action by calling run action filters send action and Stat send action is the thing that gets yielded to above and in fact, this is what we've done We've basically set it up so that we take a look at all your callbacks and in some 400 lines of insane metaprogramming code we create a method and in fact There was some talk early on about metaprogramming and a bunch of controversy I generally agree that metaprogramming for its own sake is kind of weak But metaprogramming for performance in cases where there is noticeable performance Expense like here where it was taking up 20% of the overhead of a Rails app Definitely worthwhile doing in frameworks not in your own code because that's just becomes unmaintainable But in frameworks where the performance benefit is spread out across a hundred thousand people good thing Finally abstract controllers, so we also looked at the fact that abstract and that there were two types of controllers in rails There was Controllers and then there were mailers they kind of did the same stuff But they were implemented as forks basically of where rails controllers were in rails 0.5 or 0.7 or something like that and we wanted to say you know what if there's features that are the same in Action mailer and action controller we get exactly the same code instead of having to implement it right now They're most of the features are actually there an action controller and action mailer But they have to be re-implemented separately so layouts are there, but they don't reuse the same code They implement layouts all over again This is not great. So we wanted to fix this. So we basically Looked at how to best architect this and what we discovered was that the best way to do it is to have modules That could be added in that that are basically work the same way rack does where you can slide in some functionality Have it override the existing functionality and then call super I know like almost nobody raised their hand before when it was asked if you subclass But if you don't subclass, please investigate the technique If only so that you can follow and understand how modules work in in rails So basically what we're doing in rails is having a bunch of discreet functionality that gets inserted if you want it not if you don't want it and adds appropriate features so here's one example which is basically rendering and Here's how rendering works at the very lowest level is action controller base and in rails You can say render string foo and render string foo basically means render action string foo So at the base level it takes a look at a bunch of things that you might pass in and normalizes them to a more standard Way of looking at it. Then we add in a compatibility layer, which is entirely optional But is there by the default which does stuff like say in the past We used to support render template slash foo, but actually all we do when you do that is we strip off the slash So let's just have a compatibility layer that says you probably shouldn't be doing this to begin with But if you do it will support it for backwards compatibility purposes. So now we have Once we get up above the compatibility layer. We have render action foo from the bottom case we have render template foo from the top case and then we go into action controller renderer which says Okay, now that I have a relatively normalized structure. I want to get the actual template object so rails has this thing called a template object which responds to render and At this point at action controller renderer we say now that we have a sane structure that represents what you want to render get that object and Then we pass that object up another level to abstract controller render Which all it knows how to do is render the template object that you passed in Finally up one other level to HTTP Which says now that I've rendered the template object and have a string go set it and one other level up Which sets the response body So basically what's happened here is that we have a bunch of layers all of which do one thing very well Based on normalized data from below it So you can look at any level see what normalization is happening And then if you want to implement basically you want to chop off the bottom three steps over here and implement your own mechanism for Your own render API. It's very easy because all you have to do is say I have a render API And it gets a template object and it passes that template object up one level and then everything will still work exactly correct another random example I Ran into somebody in Germany who was asking me an Oddball question he said I would like to be able to override form for for a particular controller. So he said For some reason I want to be able to have a special form for a special link to only in my controller And again, this is where subclassing comes into play So the way that rails works by default in master right now is that there's an underscore action view method that Basically goes and says action view based on new and it sets up the view pass and does something with an empty ash probably could be refactored out and Sends in self. So that's the default behavior But in rails 3 nothing stops you from doing this which is basically to say in my post controller action view Sets up a special post view and post view inherits from action view base inherits And sets up its own form for which might call super to the default implementation possibly so it may Normalize behavior or it may completely override it depending on what you want and this the really special thing here Is not that this was impossible in rails, too It was sort of possible what special here is that we're supporting these apis They're explicitly available in rails 3 as documented supported extension apis and if you use them, we won't break you So now instead of there might be an internal thing you could hack into there's a here's an internal thing That is meant for you to extend so action view is meant for you to extend if you extend it you get that behavior We're not going to break it This allows you or us to make something like fast controller Which might be a very limited extension of HDP that provides simple rendering facilities So now instead of having to go to metal which was added to rails 2.3 for performance now we can use HDP which I think renders in nine microseconds if you don't do anything special, so I think metal renders in like five microseconds I think we're getting into diminishing returns here and You can add whatever functionality you want so because everything is modular you can pull in the rendering module if you want or you can Make your own you can make your own that gets a template object using specific stuff and sends it up Right you can do basically whatever you want for performance And I think it's likely that there will be a fast controller implementation that comes with Rails 3 that base it might be called like rails metal to be used the same terminology But the basic idea is go through all the modules figure out Which ones are actually performance drains if you don't use them right so there are some things like? Like render like callbacks rather that are actually expensive even if you don't use them So we don't want to clue that by default you could include that yourself But other stuff like rendering if you don't ever call render there's no cost whatsoever So take a look at what things are actually expensive and ship a fast controller that comes with only the modules that are free Let's you include whatever modules and clearly document if you use render here's the cost Here's how you might make a faster render stuff like this Yes, okay Just in time actually so you can also use this to make your own framework So as you can see a lot of the functionality that is kind of what you want like rendering templates and all this is actually kind of still available accessible in abstract controller base And abstract controller modules, but you can implement your own API You can implement something like Sinatra directly on top of this without any pain whatsoever So that's sort of one of my benchmarks for this whole effort is how easy it is to how easy is it to implement Sinatra on top of rails in a relatively similar performance band band and Using roughly the same DSL of course the benefit of implementing Sinatra on top of rails would be that You would then have access to other parts of rails if you would want to include them So you Sinatra Actions would become methods on some magical controller that we would make and if you wanted to include other features It would work just like rails. I'm not really interested in competing with Sinatra But the question is is it possible to implement something like Sinatra with all the benefits that Sinatra have just on top of the API's that we provide for rails. That's certainly a goal Similarly cloud kit which exists right now and does a bunch of its own stuff John has talked about wanting to be able to reuse functionality. So That's what we're talking about is trying to look at ways for people who are implementing a lot of rails functionality Make it easier for them to use it without having to pull in a lot of baggage So that's sort of the the last prong of the making rails a better Ruby citizen mission and that is all some time I'm sorry. I have time for two questions. Yes, sir The need for like application They've created an act application model that gets inherited from your your own stuff and then you could extend it I think that this is a good idea. I personally do this myself instead of out in extending from Act to record base. I extend from application model like you have a patient controller I there has been some talk internally about whether or not to do this I'm a strong advocate of it in general mainly because it allows you to write extensions that get included I think it requires people understanding how subclassing and super works in order for it to work correctly This is really something that I think hopefully rails through will bring and I think we as a community really need to reach out and Make sure like new Java developers know what classes are and how to subclass them new Ruby developers don't necessarily I think Personally, this is something I think we should fix make sure that everybody understands that classes are things that can be subclassed and Modules have that same behavior and if you call super it does this Right, these are things that in more static crazy languages. You're forced to learn and get away without knowing it in Ruby, but I Think we should do better One more question. Yes, even the bats Strain So the question is that Couch DB subclasses hash and so the case statement is a hash is winning and yes, we should definitely not do that So here's what we have not done yet We have not actually gone through all rails and replaced done all the work that I showed on that one slide of doing two model We need to do that But yes, one of the key things is to notice to assume that any object might actually be an ORM object At the very worst you'll have to Include something that provides to model, but hopefully we'll be able I mean you're gonna need to model So the question is what's the strategy for making it as simple as possible. I would hope the couch stuff would do that But we're gonna be working Like if you respond to to model you that wins Yeah, so there was kind of two questions here one of which is like what if I use an arbitrary object I still wanted to work assuming that it That it has rail semantics that is definitely being supported in terms of like hash winning by accident That's really a 2-3 bug and we should probably fix that in 2-3 honestly Okay, I think that is all I think I'm out of time