💾 Archived View for erock.io › 2021 › 11 › 01 › on-autoloading captured on 2022-07-16 at 13:38:25. Gemini links have been rewritten to link to archived content

View Raw

More Information

-=-=-=-=-=-=-

on autoloading

Stardate 2021-11-01

Autoloading is a paradigm in some programming languages or frameworks that

allows code to be automatically imported into any developer's source code file.

This has a few benefits, like removing the need to have the header of a file

contain a series of import statements.

Autoloading appears to be the most popular in scripting languages like Ruby

(via Rails) and PHP.

https://guides.rubyonrails.org/autoloading_and_reloading_constants.html

https://www.php.net/manual/en/language.oop5.autoload.php

At Aptible, a significant portion of our infrastructure

is a set of services written using Rails. After spending the better part of a

couple years working with rails, I would argue that autoloading **negatively**

impacts the developer experience as well as the productivity of our engineers.

https://aptible.com

Autoloading is the worst feature in rails and getting rid of it entirely would

make the framework much more enjoyable. Even the creator of ruby wrote a post

about how he strongly discourages the use of autoloading.

Granted their reasons are unrelated to what I'm interested in discussing and

later in the post they rescinded their stance.

https://bugs.ruby-lang.org/issues/5653

For this post, I'd like to focus on how autoloading impacts the developer

experience of a novice.

As someone who was first getting introduced to ruby _and_ rails, I found it

extremely difficult to figure out where classes or functions were defined in the

codebase. Since there are no import statements at the top of the file, it was a

guessing game to figure out where source code was located. Is `SomeClass` a

class we created in one of our repos? Is it a third-party class? I have no clue

just by looking at how the class is being used. This makes onboarding to a

codebase frustrating and confusing. There are

conventions

that help you correctly guess, but I found the best way to find the source code

was to grep for it.

https://guides.rubyonrails.org/v5.2/autoloading_and_reloading_constants.html#autoload-paths-and-eager-load-paths

Here was my basic search algorithm for finding the source to `SomeClass`:

It was not uncommon for me to give up entirely. Autoloading made it more

difficult to figure out how something worked and left me feeling defeated.

Even after searching for the right way to do this and asking colleagues, it

still feels like there's no great solution to this problem that virtually every

other modern programming language avoids by having import statements.

There are IDEs like RubyMine or an LSP that make finding the source code one

click away but `solargraph` -- the LSP I use with `neovim` -- still comes up

empty sometimes. And at least for `solargraph` it doesn't even bother searching

the source from my installed gems. There's also the `source_location` method

which we can use at runtime to find the source, but it's also not full-proof and

a little awkward. My immediate reaction is: Do I really need to run `rails c` in

order to figure out where the source code is for a piece of functionality?

https://railsguides.net/find-method-source-location/

Coming from python and typescript, the entire experience feels foreign,

backwards, and confusing.

I think when people say that rails feels "magical," autoloading is a significant

part of the magic.

`fxn` -- the creator of the current autoloading implementation in rails called

`Zeitwerk` --

commented about the reasons why he likes autoloading.

https://bugs.ruby-lang.org/issues/5653#note-40

I'll focus on the arguments they claim result in a better developer experience:

1. Being able to reload code is handy in web applications development. That is
replacing the objects stored in the autoloaded constants, not reopening
classes by reevaluating the files.

Every other development web server I've used solves this by watching files and

reloading the server. It is rarely, if ever, an issue. This argument doesn't

convince me in the slightest.

2. In any non-trivial project, getting the require calls right is difficult,
you always forget some and gives load order bugs.

The error shows up immediately, you fix it, and then move on with your life.

Again, this is not a very convincing argument as I would much rather fix an

easily traceable error once than perform my crude search algorithm every single

time I want to inspect a definition.

3. If you structure your project in a conventional manner in which file paths
match constant paths, the requires don't feel DRY. You are repeating
something all the time that could be automated.

I have another rant about DRY that deserves its own post. I'll keep it brief

here: the obsession with DRY in the rails community is a virus that has infected

the minds of engineers. I know DRY wasn't invented with rails but it certainly

popularized it. All aspects of structuring code need to be evaluated based on

their merits and DRY is not always the correct decision. I would also argue in

some cases it produces far **less** readable and maintainable code.

4. Being able to work as if all your classes and modules are just available
everywhere (as in Rails) is a great user experience.

Fair enough, I do see this as a positive and I'm not blind to the benefits of

having all modules, classes, and functions automatically loaded. Once you've

memorized them you can really cut down on the preamble of writing code. I have

also spent a significant amount of time refactoring JS code to fix imports

because I wanted to move some code to another location.

I remember when I first started to learn python and stumbled across this

stackoverflow post about auto importing modules in python. I think it

provides some interesting arguments **for** having import statements:

https://stackoverflow.com/a/1494402

1. They serve as a sort of declaration of **intent**.
2. Imports serve as a proxy for the **complexity** of a module.

So much information and complexity is hidden by removing the import statements.

If we want rails to feel less magical, we should start by looking at removing

autoloading.

--

Want to chat? email me at gemlog@erock.io

home