Whatever you do, don't autoload Rails `lib/`
island94.org
island94.org
The benefit of lib/ is clearer in my opinion. Files that live there are only explicitly loaded. Some might be loaded in development, some in production, some in test. The conversation about the structure becomes more important because you need to think about what is going to consume your class.
But I think we could take this a step further and instead replace lib/ with engines/. This way, you can create multiple Rails engines that will have their own paradigm and environments' handling.
Every Rails application I got to work on had a lib/ (or app/service) that could have been grouped in a few different engines/. The benefit of using those kind of engines is that conversation about architecture, pros/cons get more defined. At least that's been my experience.
service became the junk drawer of junk drawers even worse than lib because people at least 'believe' there is supposed to be a convention when there isn't. at least you know lib is kinda wild west.
rails has failed to channel applications into domain logic once it scales past start-up rapid development to a huge team of ICs
This sounds like such a recipe for confusion... why not just have a lib_dev for the very very rare case that something in lib/ isn't appropriate outside of a dev environment? Any RSpec already has spec/support for the test environment side. Saying that everything in lib/ has to be special and unique just because <10% of are dev-only makes zero sense to me. 90% of the lib code I've ever used/written is used in models, controllers, etc and it would make no sense to need to require it everywhere you use it when no other code in Rails works that way.
Having shat out such over-engineered malarkey myself on occasion, I will say, there but for the grace of gods go I.
Even better: Autoload discrete subdirectories in lib occasionally.
Occasionally? If something is a library, why do you want autoloading anyway? The likely answer is that you are actively working on it, and autoloading allows quick feedback loops, and is a huge productivity boost.
I would expect a "library" is a true, cross-cutting technical dependency, not behavior for the application domain (or else it ought to be in app). It is safe to autoload some number of things inside of lib some of the time, if you knowingly placed it there. One manner of achieving this:
- Be specific, and don't use a wildcard or globbing notation. Maintain a list of exclusive sub-directories in lib that are capable of optionally being auto-loaded (in development only).
- Set up an environment variable that controls when and which of these curated lib subdirectories are be autoloaded. Only enable one when actively working on it, keep disabled otherwise.
As with many things in Rails, there are (a) a dozen other ways to achieve a very similar result, (b) people with different aesthetic preferences for one or the other, and (c) other people who chafe at there not being a "blessed" way to do this, or even think that making one's own conventions ought not be done.
What? Bundler always "auto-loads" all of your gems automatically anyway—that's the whole point of the require: statement. If anything, thinking about lib/ code as library code makes it MORE obvious that it should be autoloaded—why should gem "papertrail" and lib/papertrail.rb ever behave any differently? Both should provide Papertrail constants to the rest of the application.
And I may be the one misreading here!
I take "autoloading" in the Rails context to mean "Rails.application.config.autoload_paths", which is separate from a Ruby "require", and which has always had all sorts of complexity, but is supposed to be recommended against as of Rails 6. You are, I believe, referring to "require" call to load a library once (which is what Bundler does).
The Rails autoloading (once homegrown, now via zeitwerk) is used to hotswap to a new version of a constant when a file has changed. It does so by searching for missing constants on the file system based on "root paths", in this case using "config.autoload_paths" plus a few defaults.
This hotswap nature of autoloading is why I reference autoloading a library specifically in the context where one is "actively working on it, and autoloading allows quick feedback loops". A simple "require" does not do that. It loads the library once, ala Bundler, and unless it lives in the tree of an autoload "root path", changes will not be available until one restarts the server/console/rake task, etc.
I agree that, of course, that one's libraries ought to be loaded via "require" to be used. Otherwise, they are dead code, and might as well not be part of the project source. My suggestion of an ENV var is that it should swap from a single require at application boot to live autoloading.
This blog post is about a problem that shouldn't exist, and doesn't exit in any other modern language ecosystem.
One thing I very much like about JS (among other languages) is the explicit import system. You can walk the dependency chain up and down to figure out exactly where and why certain code is called.
But if you don't like autoloading, you can turn it off with just `config.eager_load = true`.
Or is the solution to just put everything in a folder that always get autoloaded?
Wouldn’t that be the same as autoloading lib?
but by default every dir under `app/` autoloads, and `lib/` does not.
so using app/lib is really just a reasonable solution for not breaking the existing defaults and conventions.
No idea what about HN algorithm made this wind up on the front page! It's not an especially interesting post, I agree. Perhaps just a testament to the in fact continued interest in Rails?
Putting autoload on lib is equivalent to monkey patching.
Creating a directory app/lib is a great way to achieve confusion and make the fuzzy finder fail more often though. Give it another name if you can
The writer says “That’s when people jump to googling ‘how to autoload lib/‘. Don’t do it! lib/ should not be autoloaded.”
But from experience, that’s not what was commonly queried. The search terms or the question asked to senior engineers went something like “my Rails lib dependency is not loading in production” which always lead to the “require” solution and the advice against autoloading.
Thinking about it more, I don’t recall ever googling the word “autoload”.
Have all of those old StackOverflow posts been removed?
Are newer devs not using linters that check for this?
Is the audience for this article solo devs inexperienced with working with Rails?
Rails always baffled me in this regard, things coming from seemingly nowhere, sometimes (in a large and messy codebases) hard to trace back and comprehend.
I see the same thing all the time with Etherium/Ethereum as well for example.
I had the same problem when NGINX first came out. It wasn't until maybe a year later after starting to use it that I actually talked with another person AFK about NGINX, and they said "engine-x" which I had never heard of.
I pronounce it rougly /mæstədan/ and I imagine many other people do as well. That sounds is closer to "a" than "o".
0: I assume they don't pronounce it as mas-TO-don, since that would be a rather bizzare stress pattern, so the "o" generally gets weakened to a schwa as is typical for unstressed vowels.
See, I think this is definitely why I'm confused, because I can't for the life of me think of anything that fits this pattern. Are you talking about japanese onamonapias, like kabedon? that's the only word I can think of with an ending that might possibly be analyzed like that. a quick search of wiktionary for words ending in "adon" doesn't turn up anything obvious that might fit that pattern either. Could you give some examples?
Second, language is fluid... if you think it shouldn't then good luck policing that.
Third, I feel your pain. I groan everytime I hear "which begs the question".
So is "helicopter", but you don't typically break it apart as "helico" and "pter" in order to pronounce or spell it.