Summarized using AI

Code is Required

Aaron Patterson • June 05, 2015 • Singapore • Talk

In the video titled 'Code is Required,' presented by Aaron Patterson at the Red Dot Ruby Conference 2015, the speaker delves into the intricacies of how Ruby loads code and its implications on the performance of Rails applications. The talk highlights several key concepts related to code loading, including the functions load, require, and autoload, as well as their interactions with global variables.

Key Points Discussed:
- Understanding Loading Functions: The presentation breaks down three primary functions for code loading in Ruby: load, require, and autoload. Each function is explained with examples of how they interact with the load path and loaded features, essential for managing code execution in Ruby applications.
- Global Variables: Two critical global variables are discussed: the load path, which serves as a database for loading code, and loaded features, which tracks what has already been loaded to prevent redundancy.
- Performance Metrics: Patterson emphasizes the importance of faster file loading to improve Rails application boot times. He notes that loading files can significantly affect application performance, with his own experience at work showing a boot time of about 12 seconds due to extensive use of models and controllers.
- Influence of Ruby Gems: The speaker touches on how Ruby Gems affects the require function and the load path, detailing the performance implications of using numerous gems in a project. Patterson conducted a survey to analyze typical development environments to better understand the impact of gem count and file structures on performance.
- Performance Improvements: The talk concludes with Patterson outlining potential strategies for optimizing the load path search process, aiming for constant time (O(1)) lookups for requires instead of the current linear time (O(n)). This involves creating a caching mechanism that could predict file paths and thus streamline loading.
- Anecdotes and Humor: Throughout the presentation, Patterson shares lighthearted anecdotes and humorous observations about programming challenges, including a quirky bug involving file naming conventions that led to errors, stressing the importance of persistence in debugging.

The key takeaways from Patterson's talk are the critical nature of efficient code loading, the ways to monitor and improve performance in Ruby applications, and the need for developers to continuously seek to understand the underlying mechanisms of the tools they use. The talk is a comprehensive exploration of how loading mechanisms in Ruby can be better understood and improved for enhanced application performance.

Code is Required
Aaron Patterson • June 05, 2015 • Singapore • Talk

Code is Required by Aaron Patterson

You can't talk about running code without talk about loading code. Part of improving the performance of Rails applications is looking at parts that impact Rails from outside of your application. In this talk, we'll look at the different ways Ruby loads code and how this impacts our applications. This talk will be more than you ever wanted to know about how Ruby loads files, and how we can speed it up.

Help us caption & translate this video!

http://amara.org/v/Ghc6/

Red Dot Ruby Conference 2015

00:00:38.600 that I I really wanted to bring something for everybody but I was told that I was not allowed to bring durian
00:00:43.920 in here so I'm sorry
00:00:49.239 uh my name is Aaron Patterson uh and I have come from the United States to
00:00:54.760 bring you freedom
00:01:08.720 give a talk at the beginning of the conference if I can because I assume that like if I do extremely poorly at
00:01:14.759 least it happened at the beginning of the conference and everyone will have forgotten by the end of the conference
00:01:20.159 but today I'm giving the very very last talk so that kind of made me nervous and then I realized something that I I'm
00:01:26.880 giving the last talk and right now I'm the only thing that's between you and
00:01:32.920 beer so it doesn't
00:01:37.960 matter oh I'm still on mute am I on mute ah
00:01:44.600 sorry oh unmute hello is that better no
00:01:52.920 hello on mute oh it's it's
00:01:58.840 off let me try this
00:02:04.200 oh is it on now now now we're on wow
00:02:10.160 much better okay all right uh yes so I
00:02:16.120 am the only thing that is between you and beer and I also figure that once we have go to the Afterparty hopefully
00:02:21.760 after a few beers you'll have forgotten everything that I say so it'll be fine I'll be fine um at least I tell myself
00:02:29.599 that uh I work for Red Hat um I am on the manage IQ team at red hat and we manage
00:02:37.280 clouds so if you have a cloud we can manage your Cloud that is what we do
00:02:43.360 that is what our team does so if you happen to have one we will manage it for you um on the team I my job title is
00:02:50.920 hacker man uh
00:02:57.000 that's that's me uh so I'm on the Ruby core team I'm also on the rails core
00:03:03.640 team and I'm a pro Neco atsume player so I've gone
00:03:09.239 pro pro at this game this is a this is a picture of my my
00:03:15.239 setup uh I really want to say thank you to all the organizers here thank you Winston thank you all of you for coming
00:03:21.640 give yourselves a round of applause please thank you thank you for being
00:03:28.120 here uh this is an awesome conference I feel really privileged to be here for the third time it's amazing I'm so happy
00:03:35.000 to be here uh so I want to talk a little bit about my experiences here on this trip um so I I just want to you know
00:03:43.400 talk a little bit about the stuff that's happened to me while I'm in Singapore uh I had to endurian the
00:03:51.799 heat I ate a locks of food I took many selfies
00:04:00.319 so these are these are all my selfies um more selfies selfies with mats um I took
00:04:09.519 over where over 200 selfies and wees and I plan to do more of that after this
00:04:16.560 after this talk is over uh so some of the stuff that I learned I want to talk a little bit about some of the
00:04:22.440 presentations I saw here uh I learned that Ruby motion is not phone Gap
00:04:37.039 uh science is s horrific uh rails is not
00:04:44.000 Omas which uh I'm actually I'm really glad to hear about this that it's not
00:04:49.280 Omas because once I heard that it ruined sushi for me uh then I like everybody
00:04:56.080 was doing Richard Stalin stuff so I decided to Google awkward Richard Solon so that's that's what I found when I
00:05:01.960 look for that uh I learned that refinements need more
00:05:09.160 refinement so there have been there have been a lot of really really awesome talks here today so what I'm really what
00:05:15.000 I'm really trying to say here uh while you watch my presentation is that you should lower your expectations
00:05:25.360 please so yeah I'm I'm really sorry I gotta I'm GNA apologize up front really
00:05:30.919 got to apologize up front because uh all the stuff that I'm going to present to you today is like it's all very very
00:05:36.880 technical stuff like most of the stuff we're going to talk about is very Tech numbers heavy things and I'm afraid that
00:05:44.160 the content might be might be very boring it might even be super
00:05:57.919 dry so well welcome welcome welcome to my talk you may have noticed I'm trying to use so I'm trying to use in all the
00:06:05.199 slides a Baskerville font uh and the reason that I'm doing this is because I read online that uh stuff in Baskerville
00:06:14.080 if it's written in Baskerville it's more believable so I'm not making this up you can go to that URL and read about it so
00:06:21.039 I wanted I wanted people to believe the things that I have to say uh and then I just decided I should
00:06:28.280 put in a picture that I like which is this picture I I saw that on the internet I just wanted to share it
00:06:35.759 uh that's it it's just a picture I like um all right so I've got I've got a
00:06:41.960 couple cats this one this is one of my cats her name is Chuchu or uh CAC seac
00:06:48.599 uh Facebook YouTube airport is her full name uh and this is gorbach or gorby
00:06:54.840 Puff Puff Thunder horse and I actually have stickers of him so if you want a sticker of my cat come say hello to me
00:07:00.680 and I will give you a sticker of my cat um and if you want to know how I got these cats like I I I'm going to explain
00:07:20.720 uh so how if you want a c like
00:07:27.120 mine ah I I also like extremely strange keyboards too I've built like one of my
00:07:33.840 hobbies is to build keyboards I love building keyboards this is one of my keyboards I have it with me today so if
00:07:39.240 you want to check it out I'll tell you all about that and we can talk about strange keyboards um and my cats love
00:07:45.520 them too there is another one of my keyboards at home and they like to sit on it that's Choo Cho and then Gorbachev
00:07:51.560 also likes it it's really convenient while I'm programming it's right there helping me out right this is my other
00:07:59.080 one uh cho cho with my other keyboard uh recently well I guess last December my
00:08:05.440 wife and I decided to get some uh uh photos taken professional photos taken
00:08:10.680 and I wanted to share them with you these are supposed to be for holiday cards this is my wife and
00:08:15.919 I this is this is another one of me I'm not sure so I'm not sure if I actually
00:08:21.199 am supposed to own show these because I don't I don't actually own the copyright on them and I'll explain that to you
00:08:28.120 over some beers uh it's not it's an interesting story it's slightly interesting and this is
00:08:34.680 another picture of my cat just for fun um I'm really into extreme programming
00:08:39.919 so I love I love XP really love XP and when I was at rails conf I got the opportunity to meet Kent Beck which is
00:08:46.480 really awesome this is he took a photo with me this really it's really cool of him uh now
00:08:54.080 we're best friends forever uh anyway like he and and I while we are
00:08:59.920 being best friends we worked on a we collaborated together on an extreme
00:09:05.279 programming uh setup and I've been prototyping it at my apartment and this is the extreme setup so that you don't
00:09:12.880 get hurt while you are extreme programming anyway so
00:09:19.360 uh the title of my talk you might have read the in the program the title of my talk was code required but actually the
00:09:25.680 real title of my talk is uh everything you ever want to know about files but we're afraid to ask or maybe you didn't
00:09:32.519 really want to know about it anyway but you're here just because and then they told me that was too long for the
00:09:38.880 program they couldn't fit it so I had to give them a short name so this is called code required uh and I also put it in
00:09:46.680 emoji so I want to talk I want to talk a little bit about security uh this isn't
00:09:51.720 the main thing main part of the topic but we covering other stuff that you know other talks here Andre talked about
00:09:58.200 security and I want to talk talk tell a little bit a little story about uh
00:10:03.279 security stuff a little security mistake that I made uh
00:10:09.680 and this story sucks um so this is I learned this command you don't need to do this command today if you're on a
00:10:16.480 newer gate you don't need to do this one uh but this is a really really important command that you should you needed to
00:10:22.760 learn earlier uh so I'm on the security team the rail security team and I deal
00:10:29.399 with security issues that come up from time to time and basically the way that I handle those is or the way that we
00:10:34.959 handle those or my personal way that I handle it is we have a branch I'll have a branch that's like you know we got the
00:10:41.440 32 32 stable branch and that's the one that's up on GitHub and you know just for example there's all the other ones
00:10:48.040 the stable branches as well right and then I have a on my local machine I've got a 32 SE branch and I'll do that for
00:10:54.839 each of the branches that we're maintaining and I keep that branch on my machine until it's time to actually uh
00:11:02.399 do the release right when it's time to do the release I'll merge those back into the stable branch and then push
00:11:08.480 those up to GitHub anyway so I I had been working on some security stuff and
00:11:13.720 it was time you know good we're going to do the release the next day everything was going fine and I so I decided like
00:11:19.720 we had planned on doing the release the following day so I was like well I'll just do some like bug fixes now or
00:11:24.800 whatever you know just go about my work cuz we got that done so you know I'm
00:11:30.000 working against master and I decide okay I'm going to do a you know fix a bug do a commit so I do that do a commit and
00:11:36.639 then I was like okay I'm going to do get push and then as soon as I did get push
00:11:42.519 that happened and all the security patches were posted to GitHub a day
00:11:48.839 early and then I learned how to delete branches on GitHub very quickly so uh to
00:11:57.200 fix this problem you use that command that I showed earlier and I wanted to find so I was thinking I should find this I should find what happened like
00:12:04.720 the campfire conversation what happened when this you know when I did this uh so
00:12:10.880 I searched campfire for this and uh I couldn't find anything there are way too
00:12:16.320 many there are way too many uh Records in there so anyway after that I learned
00:12:21.839 how to delete branches on the remote on GitHub I did that very quickly and then I tweeted this um and everybody thought
00:12:29.800 wow that's a very handy command I should use that too and I was actually just face bombing the entire time why didn't
00:12:35.560 I do this earlier anyway so the moral of the story is that security is not fun um
00:12:43.120 and don't do open source I'm just kidding I'm just kidding
00:12:49.160 uh I'm kidding about the don't do open source part security is not fun it's it's just not fun all right so I'm on
00:12:57.120 the rails team and and I spend a lot of time thinking about
00:13:02.240 rails performance I like working on Rails performance but a lot of the time like I think a lot about boot time like
00:13:09.399 uh our application at work our application is actually open source you can go to our GitHub I don't I should
00:13:14.680 have put the URL in here but you can go to our GitHub the manage IQ GitHub and actually look at our repository so you
00:13:20.199 can see what's happening there uh and our app looks a little bit something like this we have over 500 models 83
00:13:26.959 controllers these this is just the numbers from rake stats so I don't know if it's totally accurate uh our boot
00:13:32.839 time is like 12 seconds and the way that I'm measuring boot time for this purpose is just just like this I'm running rails
00:13:39.440 Runner and just printing out the version so it takes about 12 seconds to do that and a lot of the time spent in our
00:13:45.760 application is loading files so I'm thinking about how can we load files faster so that is that's the stuff that
00:13:52.920 I've just been working on recently and that's really what this presentation is about is things I've been working on recently so before we get into how to
00:14:01.560 make this faster I want to talk about what it does today uh and then we'll talk about usage usage of loading files
00:14:09.839 how people use it uh and then we'll talk about speeding it up so first let's talk
00:14:16.040 about how files are loaded so we're going to look at three functions we're going to look at load require and
00:14:22.720 autoload and in order to talk about these functions we need to know about a few Global variables and you probably
00:14:28.320 know about these variables already so we'll look at these variables is the load path we have dollar load path
00:14:34.000 that's our first Global variable and it's just a list uh and you can modify the list you can modify it by just
00:14:40.199 saying unshift or you can use dasi and mutate it so you can actually say like
00:14:45.759 I'll run with you know I'll run- I hello and you'll see that at the top there you added that to your um added that to the
00:14:53.160 load path if you print it out now you can think of the load path is essentially our code database our code
00:14:59.639 to load database when we want to look up we want to find some code you say require Fu that's where we're going to
00:15:05.720 go look for it that database is the loaded uh the load path now the other
00:15:10.800 Global variable we need to know about is loaded features this is this is the other Global variable this is our code
00:15:17.360 that has been loaded this is just a list uh with a caveat that it's not just a
00:15:22.680 list uh it looks like a list to us Ruby programmers if you print out the global variable it's just a list but uh under
00:15:29.680 the hood inside of MRI there's actually a cache a hash of that so we can do lookups faster uh so it's not just a
00:15:37.079 list under the hood but to us it is uh this is our already loaded code database
00:15:42.839 this is the code that we've already loaded so you know when you require a file twice it's not going to be loaded twice so if we need to find if we need
00:15:50.079 to find code we look in the load path and if we need to test whether or not code has been loaded we look in loaded
00:15:55.759 features so those are our main main players when we're trying to look up files to
00:16:01.560 load all right so our first function to look at is load this is a function for
00:16:07.079 loading a file it takes a file name it also takes this wrap uh option and we'll talk about that later you can give it a
00:16:13.519 full path so you say load full path and if we run that code so we load up test
00:16:19.600 twice or test will load x. RB twice when we run that you'll see it actually loads the file twice it just takes whatever
00:16:26.720 code is in that file and just executes that thing we can also give it a VAR or a relative path so you can just say load
00:16:33.600 x. RB and in that case it will search the uh search the load path and uh load
00:16:40.880 those to find those files so if we run it you'll see uh the output is Hello World twice and you'll also notice that
00:16:46.560 I had to provide a-i the temp so that it knew where to find x. RB so that
00:16:53.000 searches the load path but it only searches the load path if you provide a file that's not an absolute path
00:17:00.360 now this this very or this option is interesting the wrap option how many of you have used
00:17:07.079 this yeah that's what I thought yes
00:17:12.160 okay so you can provide a true you can say load true now let's actually I don't
00:17:18.079 want to spoil the surprise sorry let's look at this this is our usage of it we'll say load x. RB and we can print
00:17:23.480 out X the class and on the right hand side there we'll print out the name of the class
00:17:28.919 okay and if we run this we'll see it looks exactly what you'd expect it prints out the string X because that's the name of the class and then it just
00:17:35.440 prints out X again because that's the class that was defined now if we add
00:17:40.600 true if we add true what will happen is Ruby will actually evaluate that code
00:17:46.480 inside of an anonymous module so if we execute that s this
00:17:51.799 program we'll see the output is okay module blah blah blah blah blah blah blah X and then uninitialized constant X
00:18:00.200 which is it's kind of interesting so you can actually load some code inside of an anonymous module if you want to I think
00:18:07.600 this would be interesting like let's say maybe you want to load two versions of the same library inside of an anonymous
00:18:13.200 module I think it might be interesting however you can't get access to that Anonymous module outside of the load the
00:18:19.720 caller can't get access to that the other interesting problem with this is that let's say we have uh this setup
00:18:26.120 here where test loads X and then X loads y so this evaluates that file and then
00:18:32.720 comes down and evaluates this file so we print out the names of each of those so when we execute this program we expect
00:18:38.880 the first thing to be output is uh that name and then that name so we expect y
00:18:44.960 to come out first and then X to come out second so does anyone know what the output of this will be
00:18:59.640 you might think that both of those would be wrapped in the anonymous module but it's not actually y will be Define
00:19:05.880 defined at the top level and then X will be defined in the uh inside the
00:19:11.120 anonymous module so my question is is this actually very useful and I talked to
00:19:17.520 matz about this earlier and he was like I don't know I don't know if anybody uses this so the answer
00:19:25.720 is so it seems to me like we should probably REM wrap everything wrap
00:19:31.799 everything or somehow give a module or something to that variable say wrap it in this module or remove the feature I'm
00:19:38.960 not sure what we would use that for otherwise although since nobody's using it it doesn't really matter right
00:19:45.480 right all right so load to recap load load searches the load path but it
00:19:52.559 doesn't do it doesn't have any interaction with loaded features it doesn't have any interaction with that Global variable at all only the load
00:19:58.919 path one we saw that when we gave a relative file name now if we look at
00:20:04.000 require let's have another example we can give require a full path so we'll do require twice in that second file X over
00:20:11.559 there will print out hello world and if we execute this program just as you'd expect hello world is only output once
00:20:18.240 we've all used require we all know about the semantics it'll only load that file once we can also give a relative path to
00:20:24.799 require so like this when we execute that again hello world is printed out
00:20:30.000 and you'll notice that I had to specify sltm to- so that it knew where to find
00:20:35.760 that file what else is kind of cool about require is requ require will return a Boolean to you about whether or
00:20:42.159 not that file was loaded so when we run it the first time it'll say true meaning yes I did load something I loaded some I
00:20:49.080 loaded some code the second time it'll say I didn't load any Code false is I didn't load any code so in order to do
00:20:55.960 that it has to search loaded features to figure out whether or not it already loaded that code so this is how our second Global variable is used so we can
00:21:03.240 see we can actually see that modification in action with this program right here so we dup the loaded features
00:21:08.600 before we require then print out the the difference between uh before and after
00:21:13.760 and if we look at that we'll see yes indeed it just it added that fully qualified path to the loaded features
00:21:21.159 array and you'll see like require is smart in that if we say require X and
00:21:27.520 require X . RB it'll canonicalize that file name and check the loaded features
00:21:33.559 thing so if we print that out it'll have exactly the same output as a previous slide now I keep mentioning
00:21:39.799 canonicalization and this is going to be important the load path is used for
00:21:45.080 canonicalization right so if you look at this if you look at this example on the left hand side we have
00:21:51.320 the non-canonical format and on the right hand side we have the canonical format the canonical format being the entire path of the file so Ruby knows
00:21:59.159 using using the load path how to figure out that whole file path and check the
00:22:04.799 loaded features as to whether or not it's been loaded so the the logic for this look looks a little bit something
00:22:09.840 like this is it is it canonical Ruby says is it canonical you say no it says okay we canonicalize it then we go back
00:22:17.320 to is it canonical yes we check is it loaded uh if it is isn't then we load it
00:22:23.520 add it to the loaded features and then we're done if it's already been loaded then we're done
00:22:29.039 so this canonicalization step right here is where the load path is used and this
00:22:34.720 is loaded part is where loaded features is used and then if we actually load the code loaded features is used again right
00:22:43.159 there got it it's just that simple those seven easy
00:22:50.400 steps we all got it yes okay all right so the next thing we're
00:22:57.559 going to look at at is autoload and autoload autoload usage looks like this we have we say Okay I want to autoload
00:23:03.960 some particular constant bar and when that constant is referenced for for the
00:23:09.320 first time I want you to load that constant from this particular file here so bar whenever anybody looks up bar
00:23:15.880 it'll look in file X for that thing and then when we reference the constant bar
00:23:22.240 it'll go load this program so as soon as bar is referenced it'll load x. RB that
00:23:28.080 print out high and then it'll go toine bar and we're done so when we run this
00:23:33.559 program you'll see the output is just high and then it's that constant Foo
00:23:41.279 bar so this the semantics of autoload are exactly the same as require in this
00:23:48.080 particular case so if we reference bar multiple times it's not going to load the file multiple times so if we execute
00:23:54.679 this you'll see high is printed out once and then it just prints out the con constant three times after that so the
00:23:59.919 autoload logic looks a little bit something like this did it you know when a constant is referenced it says did we
00:24:05.480 load it already uh if we didn't load it then let's go do the require logic and then we're done if we did load it then
00:24:12.840 we're done right so we do constant reference
00:24:19.400 evaluate this file and then execute the whole thing so
00:24:25.600 we know we puts out hello next now we get bar and then as soon as bar
00:24:33.039 is uh uh evalu I think I said this already ah I'm scared anyway so when bar
00:24:40.840 is referenced X isn't necessarily evaluated now the interesting thing is
00:24:47.480 we have to say like when we get autoload the autoload logic is a little bit more complicated when we say when we
00:24:53.440 reference a constant we have to say well ah let me be a little bit more clear
00:24:58.480 when we're when we're evaluating this file what actually happens is uh we're referencing that constant twice okay we
00:25:06.320 reference it once here in the Fu bar but then as soon as we're evaluating this file it comes in and it prints out high
00:25:13.200 and then it references the constant a second time here right there so what happens when
00:25:19.919 that bit of code is executed we know that we're referencing a constant a second time and we have to
00:25:25.840 say well we're currently loading this file we don't want to reload it if we reloaded it we'd be into an infinite
00:25:33.039 Loop right so bar when bar is referenced
00:25:38.559 X is not evaluated that second time so our autoload logic is a little bit more complicated we have to say okay did we
00:25:45.080 load it are we currently loading it is it in Flight if we're not currently loading it
00:25:51.799 then we do the requir logic if we are currently loading it then we have to say we're done so we need to we need some
00:25:59.559 some mechanism for making sure that we're currently loading that particular file so I'm going to get a little bit
00:26:05.120 handwavy here hand wavy but what's going on under the hood
00:26:11.080 is that we actually have a hidden Global variable that isn't exposed to Ruby there's a global variable inside of Ruby
00:26:17.399 that keeps track of the files that we're currently requiring the files that we're currently loading and that's called the
00:26:22.559 loading table and if you look inside if you look inside MRI Source you'll find this function called called get loading
00:26:28.760 table and this is the thing that keeps track of files that are currently being loaded so file load steps when we looked
00:26:36.440 at the file load steps like this right here at this load section
00:26:41.919 that's the part where we actually add to that add to that inflight list so our
00:26:47.799 load steps look a little bit something like this we take out a lock we add the file to the Loading table that is not
00:26:53.679 exposed to Ruby you don't see this normally we eval the file add that to the loaded features and then remove the
00:27:00.760 lock and remove it from unloading and we're done so I want to talk so far we've been
00:27:07.000 looking at uh functions that are just inside of Ruby we haven't talked about ruby gems at all and I want to talk a little bit about ruby gems and it's
00:27:13.760 relationship with rubies require this is important for figuring out how we're going to speed up loading
00:27:19.640 loading stuff in rails so we hit let's say we do require rack we know that we've installed the
00:27:26.480 rack Gem and when we do require rack how does it know to find rack so how do how
00:27:31.600 does it know that we can look that up or where do we look that up the way that it works is that ruby gems implements
00:27:37.360 require and if you look here you'll say like if to prove this we can get a reference to the method and say tell me
00:27:43.880 where the source location is for that method and you'll see there it's implemented somewhere inside of ruby
00:27:49.279 gems so on line 38 or whatever right there now if we run without ruby gems so
00:27:55.880 you can say disable gems and run run IRB you'll see uh the method Source location
00:28:01.000 is nil so right up there disabled gems means no ruby gems whatsoever and if we
00:28:06.399 look for the source location of require we'll see that it's nil and that means that it's implemented in C so if your
00:28:11.559 methods are implemented in Ruby you'll get a you'll get a source location for it if it's implemented in C you'll get
00:28:17.519 nil so how does ruby gems require work I'm going to boil this down very simply
00:28:23.760 it looks like this basically what it does is the alias is the alias' rubies
00:28:29.559 require off to the side then it tries to call the original require and if there is an exception then it'll go look for
00:28:36.200 any gems that have that particular file in it then it mutates the load path and
00:28:41.960 then tries the require again so I know that's a lot of code the way that it works is we say all
00:28:48.240 right try rubies require if that works great we're done we just return if an
00:28:54.000 exception happens then we say okay go find a g that contains that file then
00:29:00.399 mutate the load path to put that Gem's directory onto the load path then try
00:29:05.799 the require again and then we're done so you can see when we do require
00:29:10.960 on rack that very first that very first require is going to cause an exception
00:29:16.080 the second require will not have an exception because the gem is now put onto the load path so this very first
00:29:23.080 section here we say all right require rack lock we hit an exception and we go all all the way down through here and
00:29:28.480 we're done that second one the eag one just goes straight down to done because
00:29:34.240 we're already on the load path so there's actually a way to load
00:29:39.919 rack without causing any exceptions in your process if you do gem rack like this the gem rack actually
00:29:47.840 mutates the load path all that does is it looks up the gem mutates the load path and then both of these have no
00:29:53.559 exceptions so to tie this together we can see the exception in action if we run with- D if you run Ruby with the
00:29:59.799 debug flag on you can actually see all the exceptions that are occurring inside your app now you can see right there our
00:30:06.720 first we have one exception on rack lock and they're required a rack e tag it's fine doesn't matter anymore we can also
00:30:13.720 see this from uh inside IRB if we dup the load path and then we require rack
00:30:18.760 lock you'll see down there at the bottom that gem has been added to the load path you'll also see that the loaded features
00:30:24.960 are mutated at the same time so so far we've looked at require loading code
00:30:31.120 with require autoload and load uh We've looked at Global variables the global variables that are involved load path
00:30:37.440 loaded features and that hidden one that you don't see in Ruby land loading table and we've also looked at ruby gems as
00:30:43.039 require and how it mutates the load path so the next thing I want to look at
00:30:48.519 are Ruby Gem's usage and performance characteristics and performance improvements that we can do with ruby
00:30:54.159 gems so I wanted to know and note that I'm saying Ruby space gems usage I want
00:31:00.840 to know about people's development environments it's hard for me when I'm doing when i'm doing development against
00:31:06.440 rails and trying to improve the development environment of rails it's difficult for me because I don't have
00:31:12.639 access to all the applications that all of you are developing I have I have access to my application at work so I
00:31:19.840 use that for sure uh and then maybe some other other open- source ones but I don't know what the typical developer is
00:31:26.440 like what is the typical developer like I don't know that and that's the question that I want to answer is what
00:31:31.919 does a typical development environment look like so I created a survey thing
00:31:36.960 here this is this is the code you can go visit it you don't need to run it now because I'm going to show you the results that I have from that and
00:31:43.720 hopefully I'd like to get this thing running every year so we can see how development environments change the data
00:31:49.679 that came back looks a bit like this uh make sure to read all this I'm going to
00:32:02.559 it's kind of interesting basically all this gem does it's not even a gem it's just a script you run all it does is
00:32:08.000 collect some data about your environment and then posts it to a Google form and that goes into this this document here
00:32:15.240 uh so the data that I'm collecting are like how many gems do people use like how many gems are installed on your
00:32:21.320 system like systemwide then how many gems are in your project so I want to know like your rails project because the
00:32:28.320 gems that you use in your rails project are different than the ones that are installed globally on your system uh how many files are in each
00:32:35.519 Gem and what versions of ruby gems do you use and what versions of Ruby do you use so the reason I want to know this
00:32:42.240 data is because uh gem count impacts your performance because it modifies
00:32:47.360 that load path that load path impacts our performance and we'll see how that how that uh impacts our performance
00:32:53.360 later and the file count impacts our performance as well the way that the number of files impacts our performance
00:32:59.200 is how are we going to do caching what is our caching strategy going to be so the data specifically collected as gem
00:33:06.159 count the gem count per project and systemwide for that particular user uh your Ruby version your ruby gems version
00:33:12.799 host OS and the file counts for each of the gems that you have installed min max median
00:33:18.360 mean but nothing specific about each of the gems I also collected a unique user
00:33:23.639 ID and a unique project ID and I I think was an interesting thing that I did so I'm going to share the code with you the
00:33:30.440 user ID the unique user ID and project ID uh I put quotes around them because
00:33:35.600 they're not necessarily unique they could be duplicated basically I generated a hash for that particular
00:33:41.600 user and this is what the code looks like for generating that hash we just said okay give me your host name your IP
00:33:47.159 address your time zone and whatever your home directory is Mash that together as
00:33:52.320 a string and then shot 256 it and send it off so that's our ID so theoretically
00:33:58.320 two people who are running exactly the same setup like this could have sent duplicate results but probably that's
00:34:04.519 not true so each project I grab the per project I just grab your bundle gem file
00:34:10.280 bundler actually sets an environment variable that points at your gem file sh that and send it up so duplicates are
00:34:16.480 possible but unlikely and also this data is pretty Anonymous I don't know
00:34:22.200 anything particular about anyone who submits data so as far as responses are
00:34:27.599 concerned I got 466 unique projects 140 Unique Systems and a lot of the data I'm
00:34:33.599 going to present to you here today I used R the r programming language to do processing on it and after using R for a
00:34:47.000 uh it sucks I wasted many hours on this I would have been done way earlier if I
00:34:53.960 had just stuck with Ruby and we'll talk about that over for beerus tonight please come ask me ask me for a sticker
00:34:59.680 and tell me about and I'll tell you about how R is terrible anyway these are the versions that we looked at so this
00:35:05.720 is this is just a version breakdown we have I think I had one response using 187 so that's kind of cool uh you have
00:35:12.480 to notice that note that these uh these statistics are totally biased because the way that I advertise this is through
00:35:18.839 Twitter so they're biased towards people who follow me on Twitter uh they're also biased towards people who will actually
00:35:25.359 send me some data but I guess you know whatever those are the people who are going to get performance improvements so
00:35:30.920 good for them so our implementation systemwide we
00:35:37.079 had all I got were the only responses I got were MRI and J Ruby and that's what the breakdown looks like uh I think what
00:35:43.880 was interesting about this is that uh J Ruby users are I guess running more
00:35:48.960 projects so a person running J Ruby on their system has more projects uh than
00:35:54.760 usual um another thing I thought thought was interesting was looking at Ruby Jem's upgrades uh it turns out 44% of people
00:36:04.079 have upgraded once so 44% of the people who responded to me have upgraded their
00:36:09.440 ruby gems system and the way that I measured this is I looked at I went through every version of Ruby and looked
00:36:15.040 at the ruby gems that shipped with that version and then compared that to the ruby gems version that they told me they
00:36:20.319 were running so 44% have upgraded once and 23 23% are on the latest version so
00:36:26.440 I thought was interesting um looking at project distributions so I want to know how many
00:36:32.319 projects are on each machine this is what the project distribution look like most people are only running a couple
00:36:37.920 projects but there's a few that are running like almost 90 on one machine
00:36:43.400 right so our summary looked a little bit like this this is our Max our Max output we had 82 projects on one machine so
00:36:49.440 most people have like three at most our OS distribution looked
00:36:54.960 like this I had zero people with Windows respond to me uh everyone is using OS 10
00:37:00.520 or Linux and I'm trying to get I think that this reflects development environments we're trying to get
00:37:05.839 development environment information because that's what I care about optimizing is your development environment I don't really care about
00:37:11.440 your production environment so much I I shouldn't say don't quote me on that I do care about your prod
00:37:17.920 production environment but I'm trying to optimize your development your development environment so our project distributions
00:37:24.920 what was interesting about project distrib this is I want to look at gem distributions per project how many gems
00:37:31.040 does your project depend on and this isn't just the number of gems that are in your gem file this is the entire the
00:37:36.720 entire graph right this is what it looked like this is kind of interesting uh I'm not sure what type of
00:37:44.119 graph that is it is a graph it is a keynote
00:37:50.440 graph I was going to say oh it's linear blah blah blah I don't know it's keynote
00:37:55.480 anyway so this is this this here's a the statistics about this our Max we had somebody with 287 gems and most people
00:38:03.680 are running about 100 100 or so gems which actually works with the project we have at work our ours is a little bit on
00:38:09.839 the higher side I think we have about 200 200 Gems or so but average is about 100 gem dependencies file distribution
00:38:17.319 this is interesting this is the number of files that ruby gems thinks are
00:38:22.560 requir in a particular gem okay now look at
00:38:27.880 that that is the number of files in each gem that's not total across the project
00:38:35.599 that's each gem so you'll notice on the very right hand side there there are gems that have 14,000 files in them and
00:38:44.079 those are requir files you can actually require all of them so the average here is about 4,000 files
00:38:52.720 what I think is interesting about this is it means like there are 4,000 files that are potentially requir inside of
00:38:58.400 your project but probably not all 4,000 of them are being required system
00:39:04.440 distribution uh number of gems on each system this is interesting to me because the number of gems that are on your
00:39:10.440 system will impact uh Bin bin stubs ruby gems bin stubs so when you run bundle
00:39:17.800 exec or bundle whatever this number will impact that command so that's why I
00:39:22.960 wanted to know this so we want to optimize your projects and we also want to optimize your system summary looks
00:39:29.760 like this uh so this is the number of gems that are installed systemwide one person responded had 1200 over 12200
00:39:37.359 gems installed on their system which is crazy so a number of files number of
00:39:43.000 files per system what almost 990,000
00:39:50.400 files it's crazy there's some really interesting data out here so the average
00:39:55.440 project average project just to summarize the average project has about 100 gems about 4,000 files the average
00:40:01.400 system has about three projects on it 280 gems are typically installed on your system and maybe 13,000 files are requir
00:40:10.200 I think what this boils down to is that people typically they're just installing the gems on their system and then they
00:40:15.640 go into their projects and they're doing bundle there right so you're probably installing more gems on your system and
00:40:21.319 then using those inside of your bundles so performance characteristics
00:40:26.520 let's move on to the Future Let's talk about let's talk about the performance and how we're going to improve the performance I wanted to
00:40:33.520 know as the number of gems grows how does require change so we see we have a
00:40:40.240 range of projects here from very few gems up to many many gems uh how does
00:40:45.800 the performance of require change if we change the number of gems that are on the system so what I'm really saying here is as the load path
00:40:53.359 grows how does retire require time grow because that's what we're doing with
00:40:58.880 gems when we load the gems we put them on the load path right so what we're really talking about here is uh search
00:41:05.720 load path search time how long does it take to to search the load path and this is the test code that I use again please
00:41:12.400 read it it's you're going to be quizzed on it later I know this is a small Point font but it is Baskerville
00:41:21.359 so uh this is the test code a little zoomed in a little bit basically what I did is I said okay get uh get the clock
00:41:28.359 time the current clock time require the require the file and then get the clock
00:41:33.440 time afterwards and I if you can read this code great if not I'm going to be
00:41:38.800 posting the slides later but what I think is cool about this is we can get uh Ruby exposes a high resolution clock
00:41:44.440 to us that's also monotonic monotonic meaning uh if the system clock changes
00:41:50.880 that doesn't impact our impact our tests so what I did is I said okay we're going to incre increase the load path and
00:41:57.160 we're going to require one file and we're going to do a worst case scenario file and a best case scenario file and
00:42:03.920 we're going to graph that time and this is what the graph looks like so the red one is our our worst case scenario
00:42:09.720 that's the worst case File and the blue one is our best case the fastest one so
00:42:16.880 as you can see here uh down along the down along the x-axis there that's the number of gems we have activated so
00:42:22.960 that's roughly the size of the load path and the y axis is require time in milliseconds so how many milliseconds it
00:42:28.440 took to require that one file so you can see here we scale linearly as the size of the load path increases the amount of
00:42:34.839 time it takes to require also increases so we see like when I say worst case what does that mean well when we do like
00:42:42.000 let's say we have a load path here and we're looking for Fu the worst case means we go in here and we say oh it's
00:42:47.119 not there it's not there it's not there it's all the way at the end and we found
00:42:52.520 it now best case scenario means it's at the beginning we found it at the very
00:42:57.880 beginning it's there we're done so what I think is really interesting about this graph and it's a
00:43:04.760 question that I don't have an answer for today if it's at the beginning of that list it should be constant time it
00:43:11.040 should always be the same speed we know it's at the beginning we're done every single time yet you can see here it
00:43:17.040 actually increases linearly so I think this is a bug I don't know what the bug
00:43:22.119 is yet I don't know why it does this it's something I need to study a bit more and I can tell you when I was producing these graphs I was
00:43:29.520 crying because I was hoping I could come in here and say to you oh it's linear time everything's great but this is the
00:43:36.800 reality so at 300 gems you have it takes four to six milliseconds to require one
00:43:42.760 empty file this is an empty file and you think wow four to six milliseconds it's actually pretty fast but then when you
00:43:48.559 think oh wait my app has 3,000 files in it so 6 milliseconds times 3,000 files
00:43:55.559 adds up right so let's look at some performance improvements what I want to do is we
00:44:01.200 have this load path search that load path search is o n and I want to change it to
00:44:06.800 01 I want to do constant time constant time lookups I want to have constant time requires so searching load path is
00:44:13.520 o n and the reason searching load path is o n or we have to search load path because we keep mutating it now
00:44:20.880 searching that is you know searching that is O and I think well okay how can
00:44:26.160 we improve the performance here I think the way that we can improve performance is you know what if we just stopped
00:44:33.000 searching the load path let's just stop doing it just don't
00:44:38.200 do it anymore so how can we do that the way we do that is if you provide a full
00:44:44.839 path name to require if you provide a full path name that doesn't search the load path anymore so if you do something
00:44:52.040 like this we say Okay require Fubar baz that RB that doesn't search the load path and we can have a constant time
00:44:58.400 require in that case but the question is how can we accomplish this you don't want to write out/ fuar baz on your
00:45:04.480 system because you're shipping that code out to somebody and they might be on in a different place and also that's a pain
00:45:09.920 to write and we write Ruby for fun and writing out the entire thing like that is not fun and why are you making me
00:45:15.880 write out all this stuff this is really terrible so what we need to talk about is
00:45:21.520 canonicalization we talked about it a little bit earlier it happens in two places it happens when we search the
00:45:27.680 load path and it also happens when we search gem specs what's interesting is when you say require food like what ruby
00:45:35.040 does is it says okay I'm going to go look for food. RB I'm going to go look for f.o or food. o uh or just plain Fu
00:45:42.440 maybe there's a file named just Foo I'm going to look for that file in all those directories in the load path what's
00:45:49.079 interesting is the logic for ruby gems is required
00:45:54.359 and the logic for this is a little side thing here I found while I was researching this data is the logic for
00:46:00.359 Ruby jems and the logic for Ruby are different unfortunately so this is this
00:46:05.599 is uh using um just uh ruby gems so we say require
00:46:12.880 noir. bundle that works require n.so that works actually no I'm sorry this is
00:46:19.680 plain old Ruby now if we use that same code with ruby gems it just breaks
00:46:27.960 this is my life what I do every day for all of you so maybe I will have two beers
00:46:36.280 tonight anyway you're getting off track yes yes I am okay back to this you say require food and it calculates all these
00:46:42.359 it tries to find all these things we have a required parameter and it goes from the required parameter to the file
00:46:48.680 name right but what if we went backwards what if we went backwards from that we
00:46:54.960 know what the files are it's going to look for we can say like okay well given a particular full file path we can
00:47:02.119 predict what what the parameter to require will be we know it'll either be fu. RB or it'll be Fu or it'll be the
00:47:09.680 entire path we know this data in advance we don't need to do this at runtime so the idea is we could put together a
00:47:15.920 translation hash we could say all right let's put together a hash that says it has fu. RB and Fu in it and all those
00:47:22.920 point at lib Fu then we can change our ruby gems is requireed to instead of
00:47:28.280 looking like this where we have o n here o n here and o n here instead what we do
00:47:36.119 is we look up that parameter inside that hash we actually end up with constant
00:47:41.160 times on that two those two First Steps will be constant time all right so I put together a
00:47:48.440 little uh proof of concept for this uh ran the code exactly the same benchmarks
00:47:54.079 I showed you before except that uh this time we're looking up that file in a hash rather than scanning the
00:48:01.160 entire file system or scanning everything in the load path and this is what the graph looks like we say all
00:48:06.280 right down there along that the x-axis is the number of gems that I've activated so on the very right hand side
00:48:11.760 I've activated a th gems and on the Y AIS there is uh time in milliseconds to require one file and you can see it's a
00:48:19.000 linear time there and what I think is really really cool about this is that uh
00:48:24.119 it's less than 1 millisecond I actually had to change my test if you look at my test it says okay time this
00:48:29.960 and time it in milliseconds and it was always returning one so I actually had to measure in Nan which was fun uh but
00:48:37.559 anyway if we when can we do this when can we calculate this cash we know about
00:48:43.160 this cach on gem install so as soon as somebody installs a gem we can look at all those files and say okay here are
00:48:49.079 all the files that they installed let's calculate those short names for it put that in a hash and then when you run
00:48:55.200 your program program we can actually use that hash now astute
00:49:01.000 Watchers those of you who are still awake and not mad at me because you want
00:49:06.480 beer we'll note that there are challenges with this and I want to talk a little bit about the challenges with this that I'm trying to overcome first
00:49:12.880 off we have to deal with Dash ey people can run I showed this at the very beginning people can run with
00:49:17.960 Dashi and Dashi takes precedence over gems if you run with Dashi you want to be able to get that that file not the
00:49:25.040 one that are in gems the one that you specified on the command line we also have to deal with load path mutations
00:49:30.880 like if somebody does this I've seen this in Ruby code you might do unshift require
00:49:36.040 something now the other important thing extremely important thing is we have to have bundler support for this if we want
00:49:41.720 to have this particular strategy because the way that your applications work if you're using a bundled application like
00:49:47.280 we are at work when you say bundle exact rails whatever that rails whatever isn't
00:49:53.480 actually using ruby gems anymore Ruby jems is completely out of the picture in that case so we need to be able to
00:49:59.920 support that case too uh what happens in that case is bundler sets up the load path for you so you actually have a load
00:50:06.319 path of however big it is and then you scan against that so it would be nice as
00:50:11.760 if we could integrate this into bundler as well and then have constant time look up in that case too now I want to end
00:50:20.119 this I've been talking for a long time sorry I want to end this with a strange bug
00:50:26.559 super strange bug that I ran into while trying to figure this stuff out all right we have
00:50:32.400 two files here a. RB and b. RB and a
00:50:38.200 autoads b the same setup we had earlier but the setup before was like Temp and X
00:50:44.119 or something like that right have a here B there and if I run this program I get
00:50:51.000 an error but what's weird is it prints it out high so clear clearly I mean it's
00:50:56.240 getting into that second file but it it just gives me an error it's weird right
00:51:04.599 so I couldn't figure this out I'm looking at this what is this doing what is it doing why is this breaking does my
00:51:09.760 Cod does my code look wrong to any of you is there a bug in this code anyone see a
00:51:19.480 bug class inside class no class inside class is fine double col nope
00:51:27.599 nope is there a bug okay nobody sees a bug all right I get an
00:51:33.240 error now I get on IM with a friend of mine I'm like hey uh my code is breaking
00:51:40.799 can you help me out I'm trying to run this thing it just seems like autoload is completely broken what am I doing
00:51:47.000 wrong the conversation went went a little bit like this uh works for
00:51:53.680 me really you must have broken
00:52:00.640 something I said no no no what file names are you using what file names are you using I'm I'm shortening up this
00:52:07.359 conversation here and they they said well I'm using I'm using x. RB and y.
00:52:13.000 RV and I said try a and try a. RV and try b. RV
00:52:23.200 oh so there there was no bug in my code what what it turns out what actually breaks is if you have a file named b. RB
00:52:31.839 or rb. RB it won't
00:52:40.599 work just doesn't work so the solution is
00:52:47.240 uh don't name your fails your files like
00:52:54.240 that no no no no no no no that's that's not
00:53:00.640 that's not right that's not right you should be able to name your file b. RB or rb. RB it should work fine but what's
00:53:07.040 interesting is what I I researched this bug I dug into the internals a ruby I actually fix this bug it is a bug and
00:53:13.240 Ruby it's a bug and Ruby and I fixed it um but the problem is I
00:53:19.040 think well I was working on this bug I was looking at pairing with somebody and
00:53:24.400 pairing on fixing it and we're looking through pouring through the documentation CU I three people thought
00:53:31.880 I was doing something wrong okay I contacted three of my peers and they're like you must be doing it wrong you must
00:53:37.839 be doing it wrong autoload works for me and every one of them I had to know no
00:53:42.880 no use a. RV and b. RV so I'm pairing with somebody we're reading through reading through the documentation of
00:53:49.359 autoload and the example in the documentation of autoload uses a. RB and b.
00:54:03.119 RV anyway so I was thinking about this I was thinking about this situation for quite a while you know we fix this fix
00:54:09.760 this bug together I think as developers as developers 99% of the time we blame
00:54:15.160 ourselves like if you had run that code if you had had those two files they had. RB and b. RB and you're running that and
00:54:21.119 you're getting that error you're saying man what am I doing wrong I'm doing something wrong I'm doing something wrong and then you go along and you just
00:54:27.280 change the file name and now it works I think most of the time you just move on everyone's like well I I must have been
00:54:33.400 doing something wrong I don't know what I was doing before I don't know why I don't know what I was doing before but now it works I know you all have said
00:54:40.760 that I know every one of you have said that phrase I think we're all we're all
00:54:46.799 trained to 99% of the time blame ourselves and the thing is the reason the reason that we're trained to do that
00:54:52.920 is because 99% of the time it is our fault we did like we did we did screw something up
00:55:00.319 that's I mean that's really the truth of it I mean I know that I know that personally for myself 99% of the time I
00:55:05.920 do I do make mistakes but I think what's important is when you get errors like
00:55:11.440 that when you when you get an error like that it's really important to take the time to understand why why is it giving
00:55:17.720 me that error I I know it's a lot of work like I think it's a lot of work to
00:55:22.880 to look that up but I think if you if you do that if you're always asking why
00:55:28.240 if you're always asking why you'll become a better developer once you understand what is the source of this
00:55:34.559 because for example in this particular case it turned out to actually be a bug it was not my fault this is like the one
00:55:40.640 time the one time it was not my fault but the only way I found that out is because I persisted and looked looked
00:55:47.319 into this and kept digging and digging so what I want to encourage everybody to do is take the time to find out always
00:55:53.160 be asking why it's doing the thing that it's doing take the time to figure out why it's doing that and maybe you can
00:55:59.240 fix it and if you don't fix it if it turns out you are doing something wrong you've learned something new so with
00:56:05.280 that thank
00:56:16.200 you if we have time for questions I'll do that otherwise I'm not sure something it is
00:56:22.839 Friday right how did you fix the
00:56:30.520 oh the the answer so we have an answer over here that says regular expression that's almost that's almost true um
00:56:37.359 someone else asked me a question while I find the patch for you because it's really really it's really
00:56:44.119 amazing I have a joke about regular Expressions if you want to hear
00:56:49.559 it so a programmer had a problem and he solved it with regular expressions and now he has two problems
00:56:55.680 s that's not a joke that's
00:57:02.880 truth okay
00:57:09.760 so that that probably needs to be
00:57:17.240 bigger can everyone read that is it readable okay so here is the uh nope
00:57:24.359 that's wrong hold on let me do get
00:57:38.640 ah there we go files named
00:57:45.599 B all right there is the answer right there
00:57:52.440 that so I I'll explain I'll explain what the bug
00:57:58.680 is and it basically boils down to uh pointers in C so just as bad as regular Expressions
00:58:06.440 basically What's Happening Here is there's that uh that function there loaded feature path uh basically
00:58:11.920 iterates over everything inside of the hash so I talked earlier about the loaded features array is actually a hash
00:58:19.119 that's used as a cache this iterates through that hash calling this function looking at the file names and comparing
00:58:24.559 them to the canonicalized file name or is it no no not the canonicalized file
00:58:29.760 name the short file name now what it does is it says it's trying to take a shortcut here
00:58:35.880 everything in the loaded features path is a canonicalized file and the path that we passed in here is actually the
00:58:41.160 short name it's whatever you pass to require or whatever you pass to autoload it's that string so this particular
00:58:48.280 shortcut what it's doing is it's trying to say like okay it's trying to tell did you pass in the full path or most of the
00:58:54.720 full path and it says all right I'm going to take this key and I'm going to move the pointer all the way out to the
00:59:01.319 left hand side of the string and then I'm going to take yours move it all the way out and then I'm going to move over
00:59:06.640 one and check to see if that string is the same so since pretty much all the
00:59:11.839 files end in RB and my file name was B it would walk
00:59:18.520 back one character and compare those two and say yes I have a match
00:59:25.720 which is why rb. RB would also fail if you Tred to do autoload with RB it would
00:59:30.960 do that so basically what this did is it said okay only do this speed hack if the
00:59:36.960 file name has a dot in it so technically files named. rb. RB will now probably
00:59:49.000 that but other ones will work FS other questions you you mentioned
00:59:55.799 load and require and autoload how about require relative uh yeah so I didn't
01:00:02.359 mention I didn't mention require relative uh and that's basically because require relative all it does is figure
01:00:09.559 out the full file path and send that to require so it wasn't I mean I probably
01:00:15.440 should have put it in here for completeness but it wasn't interesting to me as far as performance improvements are
01:00:20.839 concerned also I don't particularly like require relative
01:00:27.640 should I explain why I'll ask myself questions sure all
01:00:33.359 right so I'm not I'm not a huge fan of require relative and the reason I'm not a huge fan of that is because it
01:00:38.760 calculates the full file path and basically does a require on that full file path so that is faster if you do it
01:00:44.760 if you do that that's faster because you're not doing the search of the entire load path so that's faster but
01:00:50.720 the downside of it the thing that you're giving up is that um if you change- I it
01:00:57.720 won't impact require relative so let's say for example uh I F I find this
01:01:03.400 technique to be very useful especially when dealing with Legacy code is let's say you have a file and uh you need to
01:01:10.680 test it but you don't want you you don't want to load that file you want to fake it out you have a class inside a file
01:01:16.160 that you want to fake right what you can do is you can you can provide a special path with
01:01:22.799 Dashi so let's say you have food RB in your main application but you want to replace food. RB with your
01:01:28.359 stubs you can say dasi and provide a food. RB that has your own stubs in it
01:01:34.200 and it'll load that instead of the one inside the application so it's very handy when dealing with Legacy code you can say I want to replace this one stub
01:01:41.400 out this one section of my code base and you can't do that if somebody's using require relative if they're using
01:01:46.960 require relative you'll always get that file so I'm not particularly a huge fan of
01:01:53.440 that more questions come on I'm not always in Singapore
01:01:59.119 please so the question is um what if the file system changes or uh
01:02:08.119 should we dig around in the load path if we can't look it up in the cash essentially sure uh
01:02:16.559 so I don't know uh I guess the idea the reason I
01:02:22.039 wanted to do it on install is because we know at that time we can calculate it at that particular moment uh we could do it
01:02:28.160 we could do it at runtime too I just don't know how expensive that is and probably the problem is like let's say
01:02:33.960 we have a gem that contains 4,000 files right then we'd have to calculate that cash for all 4,000 files even though
01:02:40.680 your app probably only requires a 100 of them something like that so maybe not do
01:02:46.400 it at runtime although I don't see why you couldn't I mean if we figure if we're able to calculate that cash at gem
01:02:52.680 install time we could have an option to do do it at runtime too okay if not I have a question for
01:02:58.359 you yes what day is it today Friday therefore Friday hug time
01:03:06.480 yes okay everyone are you happy that it's Friday I don't really believe that no no
01:03:13.559 come on are you happy that it's Friday are you happy that it's Friday come on we're getting beers soon
01:03:21.680 please everyone stand up I like to do it so I work at home I work remotely I
01:03:27.480 worked remotely for 5 years and I get very lonely when I work at home so what I do on Fridays I give the internet a
01:03:33.319 hug to say hello hold
01:03:48.200 on oh every okay everyone on the on the count of 3es say happy Friday one two three happy Frid
01:04:10.960 fr
Explore all talks recorded at Red Dot Ruby Conference 2015
+18