 Good afternoon. We are going to see a talk about the Rails boot process, and I would like to explain before the goals of this talk. So in this talk, we are going to see a few things related to this topic. For instance, if you open the config directory, there are a number of files that we normally never touch that are generated, like this config.boot.rb, config.environment.rb, and so we are going to see what they do, okay? Then Rails components in general can work independently of Rails. So Active Support, for instance, is a library that you know you can use in a Ruby script that is not running inside the Rails application. Also for instance, you can use Active Record outside Rails, okay? You can have like a regular Ruby script using Active Record connecting to everything, you know? You have everything. But somehow, magically, you know, you launch a Rails application and all these independent components are, you know, somehow organized for you, and seamlessly you use them, you know? And there's nothing that the programmer has to do to get these things working together. And we are going to see how that works. And you know, the final goal is to understand more or less what happens when, okay? I say more or less because there's a lot happening, but we are going to have a good sense of what happens when. And for this talk, we are going to have to take into account a few things. First, the approach of the talk is thought for Rails parameters, right? So for instance, it's not going to be like a, you know, a walkthrough of, you know, of code and code and code and see the rune path of these things. So we are going to see code, but it's not a walkthrough. So with this talk, I have tried to explain what I would like to know as a Rails programmer about the root process, the boot process, okay? And it is something that I would like an innate guide to cover, you know, that kind of information. In the boot process, we have rail ties and we have engines, but this is not a talk about rail ties and engines. We are going to see what they are, but that's a topic for the whole talk, okay? So we are going to see only what is needed for this talk about rail ties and engines. Therefore, we are going to see some code snippets, but they are going to be like heavily, heavily edited. So I have not even tried it so that the slides makes clear this has been edited, you know, with ellipses or something like that. We put like a big warning and in general, the code we are going to see, if you open the real file, is going to have more stuff, okay? But there is a lot going on and I tried to select and, you know, and put everything out that was not relevant to the topic we are talking about. And finally, we are going to ignore spring, you know, so the boot process assuming that no, no, no, no, no, this is the boot process, you know, the vanilla thing, okay, without additions, all right. So normally when you think about booting rails, you have a server in mind, okay? You launch the application, you launch the server, you can, you are able to serve requests and everything, but there are more things that boot rails. So for instance, if you run the console, you know that somehow you have everything in the application available in the console, right? Also runner, if you run, you know, if you pass runner a string or a file name, it gets executed in the context of the application. So somehow the application has been booted for, you know, in order to run these commands. Runner indeed is a command that I love. I believe I run this command every day. So it allows you to run something quickly instead of launching the console and then control D and that kind of thing, you just, you know, runner something. And indeed to understand the rails, the rails initialization, runner one, which is execute the program that has a literal one, you know, it's something that I do often, you know. So that's the minimum thing, the minimum thing rails runner one, the minimum thing that, you know, loads what it has to load, does what it has to do and then there's no more side effects, except evolution one, which is not allowed. And also in some rate tasks, you know, that you have also the environment load. Booting the application means being ready to serve all these kind of things. All right. So let's open bin rails, okay? This is a file that is generated in any, at least, modern rails application. And we have here config boot, we load config boot and then it doesn't require something, okay? If you open bin rake, you will see that it loads config boot and then does a stuff related to rake, okay? So these both, these both files start loading config boot. That's the first thing. And if you open config boot, you will see that is basically doing bundler setup, okay? Bundler setup configures the load paths so the application is able to require the gems that are in the gem file with, you know, with all the constraints and everything and is not able to load gems that are outside that thing, okay? So bundler setup tricks load path and, I don't know, all is needed so that that is going to work. Then if you open config rule, which is what you execute when you launch a server, you will see that it requires config environment, okay? And then does something. Config environment is another important, important file. It loads application and this is config application rb, which is the first file we normally, you know, working as a programmer. That's the kind of the first thing, you know? Config application rb is where stuff starts, where you can config, I don't know, time zone, that kind of stuff, okay? So that's the file that is being referenced here. And then very important, it runs Rails application initialize. And this is the magic. So initialize, this method is the one that runs all the initializations. Up to now, we are like setting things up, you know, to be able to do this. And this is config application rb, which loads Rails all and then executes boundary require with the groups that are relevant to that execution, okay? So Rails all, we are going to see Rails all later, okay? Forget about it for a moment. But the point here is that we are doing boundary require. At this point is when the gem dependencies are loaded, okay? Unless you opt out, okay? At this point, and after that, we evaluate the class that defines the application itself, which is, you know, this thing that is named after, you know, what you pass to the new command, that kind of thing. Okay, so the presentation is organized in a few blocks. And we are going, it's going to be a bit like a roller coaster, okay? So we are going to dive a little bit in something, and then I'll leave it up, doing some summaries, okay? So this is the summary of what we have seen up to this point. So define load paths. We have gems, dependencies ready. Then load Rails all, which is something that is going to be seen later. Then we actually load the dependencies. Define the application class, run, initialize. That's like the script, no, that's the order in which things run at this point. And it's initialize that does the proper Rails boot process, okay? Rails-RailType, so Rails-RailType is a class that provides a number of things so that extensions and, you know, are able to hook into this process. For instance, it provides hooks to run code when you launch a console, when you launch the runner command, you know? So you can say, as a gem, you can say, hey, if I am loaded in a Rails application and the console is launched, please call this code, okay? And we may have a series of blocks like this that are scheduled to run at that point. Then you have the ability to define custom configuration points, okay? So when you see, for instance, config.something, config.activerecord.something, you know? A RailType, we are going to see later that ActiveRecord is a RailType, allows you to define configuration points so that applications are able to, you know, to express the configuration they want. And also, very important, they have the ability to declare code to be executed during boot, during boot. So these are called initializers, okay? So hooks, configuration points, and the ability to declare. So, Rails can declare that I want to run something when the initialization happens, which is something I don't know, okay? Rails are defined by suppressing this class, this very class. And Rails knows which Rails are defined because there's an inherited hook, you know, that when Rails, RailType is subclassed, there's an inherited hook that say, hey, I have been subclassed and that by definition is a RailType, okay? Well, there's a technical thing about some special subclasses that I know, but that's the idea. So let's see an example, okay? So this is, for instance, a RailType of FactoryGal. And this initializer thing with a block is, FactoryGal is declaring when the application is initialized and I don't know when that is, you know? But when it happens, you've got to run this code. So for instance, FactoryGal at this point knows that Rails root is already defined, okay? That's a contract. You know you can assume that, okay? And in this case, FactoryGal is setting up some factory paths or something like that, okay? So the way FactoryGal, so FactoryGal needs to define some paths that depend on the Rails application, and the way to do that in an integrated way with Rails is to define a RailType and say, okay, when you are booting, call me and I will, I will configure myself, all right? So Rails components are integrated into the framework using RailTypes. For instance, this is the RailType of ActiveRecord. ActiveRecord defines a RailType to integrate into the framework. In this case, for instance, this is an example. This is one of, this is the hook that tells Rails to run this code if the console is launched, okay? So if the console is launched, if it's launched in sandbox mode, which is a mode that starts a transaction and rollbacks a transaction when the console, when the session is over, okay? Load some code, I have not copied here, okay? Load whatever you need to support this thing. And for instance, then you have, you know that, that recently in the console, you get, you get the SQL logins in, you know, there. So there's code that says, okay, unlock to standard error, all right? So that's the way ActiveRecord integrates into Rails by defining a RailType that does this and, and does a lot of other things, all right? Okay, for instance, this is from ActionDispatch. And we are seeing here an example of configuration. We saw before an example of hooking into the console. Now we see an example with configuration. So for instance, this is the way ActionDispatch defines a configuration point called tld underscore length. And it gives this configuration point a default, which is one, okay? This is from ActiveSupport, and this is another Initializer. We saw an Initializer for FactoryGal. We are now seeing an Initializer for ActiveSupport. And we do not need to understand this code, but it's basically taking the time zone that the application has configured and setting, you know, whatever ActiveSupport needs to set up to to take into account that configuration point. Okay, so that's what Rails all does. Rails all is just, you know, it just loads all the, the rail types of the different components in Rails. So, application.rb loads this file. This file is just, it's just looping and loads everything, all right? And as a side effect of loading these things, we have first that Rails knows that RailTie has been supplaced. So we are able to list the rail, the rail types that have been loaded. And also, as a side effect of loading these, we have the configuration points, the declarations of the Initializer. So it's like a setup, okay? And that's the way the components work seamlessly in a Rails application. So, the application, in reality, well, as a rule of thumb, let's say, maybe it's not 100% in all cases. But as a rule of thumb, this is, I don't know, I like very much this design. So Rails doesn't, it's not coupled to the components. Rails is kind of agnostic to most of them, all right? So Rails does not have in the Initialization process anything that hardcodes stuff to integrate the components. No, no, no, it goes the other way around. So the rail types are loaded and the configuration points are the interface between Rails and these components, okay? So ActiveRecord just loads and say, hey, call me the console, please run this Initializer, blah, blah, blah, blah, blah, okay? And the same for the rest of Rails components. And the rail types, so are the components that know that they are living in a pattern application, okay? That's the way they integrate. So Rails does not hardcode in general anything about ActiveRecord, that kind of thing. Rails just exposes a number of configuration points, ActiveRecord loads, takes the configuration points that it needs to set up itself and you know, you are set, okay? That's the idea. So a vanilla Rails application has 15 rail types, which are these ones, okay? So you see, everyone that needs to integrate with all these processes has to define a rail. All right. Next block, lazy loading. So in general, so example of heavily edited code, this is ActiveRecord RV, which has a lot of things, okay? All right, so in general, if you open like the root file of the Rails components, you will see a lot of auto loads like this one, okay? This is the auto load of Ruby. Well, yeah, so Rails redefines because auto loading Ruby needs the constant and then it needs a path, all right? But when you follow naming conventions for the files and you write this thing three times, so the reaction is to write something that automates this using the convention. So model is that, this is the Ruby auto load, not the Rails auto load of constants, okay? So in general, when you boot, Rails tries to be as lazy as possible loading things, so you have the minimal things to do when you boot. One of them is setting auto loads for, this is the ActiveRecord is the name space, so ActiveRecord base, ActiveRecord, whatever, is going to be auto load. So it's not going to be ActiveRecord base, it's not going to be required on boot. It's going to be required when it's needed, you know? And that's thanks to auto load. So since things are going to be loaded only when needed, and there's code that needs to know, hey, have you load already ActiveRecord? For instance, to include something in ActiveRecord base or whatever, there's this utility which is ActiveSupport on load. So for instance, in the ActiveRecord rail tie, we have to set up the logger of ActiveRecord. And the initializer does not go and straight away assign the logger. Because the way to do this orderly is, you declare that when ActiveRecord is load, then please set the logger with the block that I am passing here. Okay, so that's the way to defer as much as possible things in order to have a boot process as lightweight as possible. And at the end of ActiveRecord base, at the end of ActiveRecord base, which is what ActiveRecord considers to be loading ActiveRecord, by definition is evaluating this file, it says room load hooks for ActiveRecord, okay? So when this file is evaluated, all the class is defined. And at the bottom of the file, you have this line and then everything that was scheduled to be run when ActiveRecord loads is going to be run at this point. Okay, next block is Rails engine. Rails engine is a subclass of rail ties, of Rails rail tie. They are defined as well, so rail ties were defined by subclassing Rails rail tie and engines are defined by subclassing Rails engine. So it's the same kind of thing, okay? And what is an engine? So this would be like one, two, three talks, but just to get the idea of what it is, first it heritage everything from Rails rail tie. So all we saw before about console, runner, hooks, initializers, config points, that's all available here, but it's like a super set. You can do more things with an engine. So for instance, you can define controllers, models, that kind of thing. You have initializers as well, assets, you know, a bunch of things. So it's closer to like, you know, unless you are able to define like a subset of an application, that's the idea for an engine, okay? So engines have predefined some configuration points and also some initializers, all right? So just by subclassing engine, you got some configuration and some initializers for starters. So this is the one that are inherited. So when you define an engine subclassing Rails engine, you get this kind of thing. So you're going to set the load path of the engine, okay? So adding your own lead directory or whatever, you know, to APP models, whatever, to the load path that is already set. Auto load path, routine paths, locale, a number of things, okay? So it is not important to follow every single step of this, you know, it's maybe too detailed, but just, you know, to give an idea of the kind of things that you inherit from an engine. View paths, load environment config is, these are initializers. This is the initializer that runs whatever you have and config environments, develop config environments, production review, whatever. And then some other paths. Then you load config initializers, all right? Disorder, and then there's a technical hook engines black point that says you've, at this point you have already run a number of things and if you are interested in hooking into this, you can, all right? So initializers, by default, go like in chain, but you can say this has to run before this initializer or this has to run after that one, and there are a number of technical points in order to be able to do that. And a vanilla range application, which is like range new, you know, what do we get with range new? There are four engines, these four, okay? Okay, action cable is an engine, it has an engine, so the rest of range components have rail ties because with a rail tie is enough, what they have to do on boot, and action cable has some assets and that's the reason it is an engine. All right, and we are arriving to range application, which is a subclass of engines, so look at this hierarchy. So the base thing is a rail tie, then we have an engine, and an application is a subclass of engines. So, you know, the application is like a particular case of all this design, okay? Beautiful, I think it's beautiful. All right, so they are defined by subclassing and that's what you do in config application RV. If you remember, you have your application, subclassing range application, that's exactly what that file is doing. So the application indeed is a singleton, you know, there's just one instance of that class and you can access that instance using Rails.application, which is a method. And when the singleton is instantiated, you get a hook, call it, before configuration. That's also just something that is fired and if you're in a rail tie, for instance, you say config.beforeconfiguration execute something is going to be execute at this point, which is just when the application is just, you know, it got instantiated, you get this code called. Okay, so application execute for groups of initializers, for groups, it's organized this way. First, you have the ones inherited from Rails engine, okay, Rails engine have some pre-configured ones, so those ones you inherit, therefore, they are going to be executed. Then, there's a bootstrap group that does like super basic things, like setting up paths and that kind of thing. Then we have the initializers of all the rail ties and engines that the application has load, okay? And the way this is load is because we have a bundle require in config application. So if you have an extension, a gem or something, implementing a rail tie or an engine, so what happens is that when bundle require loads that gem, that gem, you know, at that point defines the rail tie or the engine so that the application knows about the existence of this thing. And then there's a finishes group that does some training stuff. So the bootstrap group, for instance, the first one is a technical hook as well. Then, for instance, we load active support. So active support, that's not something optional. The whole Rails uses active support, okay? So straight away, this one is hard code, this one is loaded. Okay, yeah, so this loads active support all, which brings you everything in active support unless there's a configuration point which is config active support bare, which says instead of loading everything, just load whatever the application, I mean, whatever Rails needs to run. And this light means that we are finishing. No? All right, I saw a change. Okay, okay, fine. Yeah, so you are able to load as the minimum of active support, okay? That said, I have never seen this one used, so, but we have it there. Then eager load, you initialize the logger, this is the bootstrap log, the bootstrap group, okay? So you initialize the logger, the cache, the way constant auto-loading loads things, which can be load or require depending on, depending on the environment or configuration. And then there's a before initialize hook, the details, too much details, okay? There are a number of things that are going on, just having a look. And then Rails and Engines in a vanilla Rails application have 94 initializers declared, okay? It's too much. So then we have the finisher group, okay? These things, more or less, you can think that they run more or less in order, except that the before and after things that are, you know, when you declare an initializer, you can say before this and after this, you know? Unless you have defined something, you can more or less think that they go in order, okay? So, yeah, a number of things. The finisher group does a number of things. It configures lip template in case generators need to load things from here. Yeah, this second one is technical. Then this one is defining, you know, you know that if you go in development mode to Rails info, you get some pages there and if you go to the home, you get this new shiny thing, you know, in Rails 5. So, the way that works, if you go to config.root.rb, that's not in config.root.rb, so how is that served? All right, so the roots are defined here. Those ones are defined here. You build the middleware stack at this point, so we are kind of already late, you know? Okay, you have to think we are already, most of the things are done at this point. Well, you define main app, which is something for engines, doesn't matter. To prepare blocks, important, these are blocks that are on certain points of the runtime. And eager load, this is important. By default, in production, you eager load the application and then there's another technical hook, which is the finisher hook that fires another event, which is after initializing case, you have to do something after this has run. All right, and a number of things that are too detailed, maybe, well, the second one loads the roots, this one is important, okay? But there are a number of things in this finisher group going on. Okay, so once everything has been declared and we have everything load, you know, there's a topological sort going on here. So an idealizer have an after, before, topological sort, if someone does not know. Basically, if you have things that have a relative order declared, like, I have to run at some point but make sure it's before that thing, or I have to run at some point but make sure it's after that other thing, okay? So a topological sort is getting this linear in a way that respects these relative constraints, okay? So if you said, you need to run before that thing, you are guaranteed that you are going to run before that thing, okay? Maybe not immediately before, it doesn't matter. So the constraint is relative, okay? So maybe not just before, maybe two before, I don't know, depends on the other things that have said that need to be run before that hook, okay? So that's the idea, in any case, we ordered initializers to be run the way they have declared to be run. So at this SHA-1, we have 124 initializers, there's a lot going on, okay? Because everything, you know, this is designed so that everything that needs to happen at boot is going to be generally happening in an initializer. So there's a lot of things, 124, and I have listed all of them, so if you get then a PDF or we see the video, we have them at least as a reference. This is not like public interface, this is not something Rails is telling you these are going to exist, you can assume that all of these 124 are going to exist in other releases or things like that. But anyway, just for the sake of the presentation, these are the ones, I am just going to pass the slides because there's no point in going one by one, but you see we have setting load paths here, then out to load paths, and there are like, all right? So yeah, so what I want to say here is just that you are aware that all of these initializers are defined and all of these things are running, okay? Okay, so we've seen like a number of things, and there's too much to get like which is the whole picture. So from all this, I've selected what I think I would like to have clear as a Rails programmer, okay? So you've seen there's a lot of things going on. So this is the summary of the summaries, like the essential things that we need to know. All right, summary of the summary. We go to the beginning of the presentation, okay? With boot, Airbnb and the kind of thing. So first, we define the load paths which is bundle setup. So we have the gems, you know, the ones that we want to be available and not the ones we do not want to have available. Then we load the rail ties, and this side effect defines all these configuration points of this initializer, active record, and all the rails components. After that, we load the gem dependencies with bundle require. Then the application class itself is evaluated, okay? The definition of the application class itself is evaluated. And then there's a bunch of paths, like auto load paths, you know, load paths, stuff, all right? After that, and this is important, at this point, we load config environments, development Airbnb, production Airbnb, whatever, okay? And this is why the configuration in these files takes precedence over the one in config application Airbnb, simply because it runs after it, okay? So if you say foo equals one in application Airbnb, and since after that, you run config environments, development Airbnb, for instance, and you say foo equals two, so it takes precedent just because it's evaluated later, and that's the one that remains. After that, the initializers in the application engines or whatever are run, okay? So first application, then development Airbnb, production Airbnb, whatever, after that config initializers. These ones are executed in lexicographic order, and after that, if needed, the application is eager loaded, that happens in production mode, by default. Well, another thing, so yeah, parentheses. So we've seen that rails integrate into rails via configuration points, all right? And in general, something curious as well is that in rails, in general, in general, maybe if you do a rep, maybe you find a counter example, but in general, the rails code base is not full of, if development question mark, if production question mark, no, no, no, the interface is, we have parametrized rails using configuration points, okay? And when you generate an new application, development Airbnb, production Airbnb, whatever, sets sensible defaults for that environment, and then rails just checks this configuration, all right? So it's not that in production, you do something, is that in production, the default generated in production has a value that makes that happen, okay? Right, so we run these ones, eager load, we load the routes, and if we were running a command, then the hooks of the command are good, okay? So this is like the most important sequence of things that we have to remember, all right? And that's it, all right, thank you. Thank you.