# Autoloading
## How it works and how we broke it
---
## Before We Go Too Deep: What Even Is Autoloading?
---
## An Example Without Autoloading
---
Say you had the following code:
```ruby
# located in the ./code/blarg_service.rb path
class BlargService
def self.do_something_useful
# ... imagine something useful here
end
end
```
---
and I had another file that needed to use that code:
```ruby
# located in the ./myscript.rb path
BlargService.do_something_useful
```
If I ran that as it currently is it wouldn't work!
---
That's because ruby has no idea what `BlargService` is. It hasn't actually been defined yet!
---
So to solve that we would use `require`, to tell ruby to load that code first. So our `myscript.rb` file becomes:
```ruby
# located in the ./myscript.rb path
require './code/blarg_service.rb'
BlargService.do_something_useful
```
Now it all works!
---
### Except this still has some issues
---
First of all I need to put `require` in a lot to ensure the code I need is loaded:
```ruby
require 'code/file/a.rb'
require 'code/file/b.rb'
require 'code/file/c.rb'
require 'code/file/d.rb'
require 'code/file/e.rb'
require 'code/file/f.rb'
# I haven't even reached my own code yet! D:
```
This can mean a lot of extra typing.
---
Second this makes refactoring harder.
If I decide to rename or move a class or module then I have to update every single `require` statement that references it!
---
Thirdly it can be very inefficient!
If I load all the code that I think I might need, there's a good chance that at least some of that code is never actually being used and I'm just waisting CPU and memory requireing. We all know that rails isn't super fast to startup, but imagine if it was even worse!
---
Lastly it makes it hard to know where a given piece of code is likely to be written.
There's nothing ensuring that I adhere to any kind of naming convention so I can put whatever class or module I want in whatever path I want e.g.
```ruby
# located in the ./code/basmatti_rice.rb path
module Cookies
# totes not rice
end
```
---
## The Alternative: Autoloading
---
Autoloading tries to solve all these issues. It works based off a very simple naming convention:
Given a class or module named: `BlargService`
I expect it to be in a file named `blarg_service.rb`
If I have a something inside a module named: `Services::BlargService`
I expect that to be in a path matching: `services/blarg_service.rb`.
Hopefully that makes clear how that works.
---
Using that convention rails autoloading then hooks into ruby's `const_missing` method, which gets called whenever any constant is referenced that ruby doesn't yet know about.
---
This means that in my original example:
```ruby
BlargService.do_something_useful
```
when I write that without doing the `require` myself, the rails autoloading gets told `BlargService` doesn't exist, so it tries to load it from its defined autoload paths, which in this case is just `./code`. It sees a file exists matching the naming convention for `BlargService` at `./code/blarg_service.rb` and requires it for me!
---
This is really cool as it means:
1. I don't have to write require myself.
2. I don't have to update requires whenever I rename or move a class, because I haven't written any requires.
3. The code I need is only loaded in when it's needed, making it faster to start up.
4. Because a convention is being enforced, I can pretty easily guess where the code for `BlargService` is written.
---
## So How Did This All Go Wrong?
---
This whole autoloading setup works great, and rails has some good defaults for autoloading paths so that directory inside the `app/` directory is automatically added as an autoload path, so a basic rails app has the following autoload paths:
```
app/controllers/
app/controllers/concerns/
app/mailers/
app/models/
app/models/concerns/
app/views/
app/workers/
```
---
So with those autoload paths defined, if I reference a constant like `BlargService`, it would look for a file with the expected name at each of these places:
```
app/controllers/blarg_service.rb
app/controllers/concerns/blarg_service.rb
app/mailers/blarg_service.rb
app/models/blarg_service.rb
app/models/concerns/blarg_service.rb
app/views/blarg_service.rb
app/workers/blarg_service.rb
```
The first place it finds that matches it will load.
---
That's all fine, however in our app we didn't have just the default autoload paths... we had a few more:
---
The End
---
{"metaMigratedAt":"2023-06-15T00:00:58.064Z","metaMigratedFrom":"YAML","title":"Autoloading: How it works and how we broke it","breaks":true,"contributors":"[{\"id\":\"dc6f92c8-9fa1-4d22-bbd3-6fe00f988ec8\",\"add\":7224,\"del\":2653}]"}