

Use Bundler.setup Instead of Bundler.require - anti-pattern
http://anti-pattern.com/use-bundler-setup-instead-of-bundler-require

======
stormbrew
In a language with a more rigid module system I'd agree with this, but Ruby's
is really problematic for this sort of thing. Your requires will eventually
cease to be documentation as they go stale, and you'll almost certainly
accidentally use a dependency you don't require. All of this results in Weird
Dependency Failures At A Distance.

If there's one thing I wish Ruby would adopt from python it's the import
namespace system. Then this kind of proposal would become more practical.

~~~
anti-pattern
Interesting. Why would the requires go stale? And how would you use a
dependency you don't require? It wouldn't be possible to use it unless you
required it. This of course assumes you're testing your classes in isolation.

~~~
stormbrew
I think that isolation testing _files_ is considerably harder than isolation
testing _classes_. You can't force isolation of one by using isolation of the
other.

For requires going stale, I mean when a file originally depends on something
but no longer does. The require is likely to linger, especially if the
dependency is removed without knowing that it was the entirety or the last of
the dependency. This file now has stale dependencies.

Then something requiring that file will have that dependency in place and
possibly use it without requiring it because of that. This file now has
incorrect dependencies.

Expand the above across a more complex project and it becomes virtually
impossible to verify the correctness of your requires, so you probably just
stop trying and require things as needed, which makes it worse.

When you finally discover it your changes (in your version control) become
less isolated as random requires start popping in and out.

This is not a new or unique problem to Ruby, obviously. C/C++ headers have a
very similar problem.

~~~
anti-pattern
Ah, well, nothing is foolproof. Yes, if you don't update your dependency list
when dependencies are removed, they might get stale. But I keep up on that
stuff and haven't ran into that problem yet. Even if I did, I'd rather have
that problem than an app where all the dependencies are global.

~~~
stormbrew
Sure. I guess what I'm trying to get at here is that, while I'm not fond of
the Everything Is Magic approach rails often takes, I actually think this is
one case where it was an entirely pragmatic effort to work around a poorly
developed area of the ruby language when a program gets large (in terms of
files, lines, or both). And Bundler.require is an evolution of that practice.

------
suckaplease
Wow, I'm always excited to see Rubyists promoting things being explicit in
code. That's my primary gripe with Ruby projects, too much magic fairy dust
and freebies that generates complexity. I'll keep this tip in mind when I play
around w/ Rail/Grape next time.

~~~
anti-pattern
I think a lot of this unfortunately comes from Rails. Rails hides a lot of
complexity which creates "magic". And since most Rubyists come to Ruby from
Rails, a lot of Rubyists have the bad habit of hiding complexity wherever
possible. I was guilty of that myself. But I've noticed it slowly starting to
change.

------
mnarayan01
I'm not sure that there's really any way to give a firm recommendation either
way here. You can, after all, simply add

    
    
      :require => false
    

to any gems which you don't want to require with Bundler.require.

> Manually requiring dependencies at the top of every file very explicitly
> tells you and anyone else exactly what dependencies that file has.

While I don't disagree with this statement, I don't really know of any way to
enforce it (certainly using Bundler.setup won't do so). You're always going to
have everything that has been required elsewhere "pre-required" for you. I'll
often start out explicitly requiring everything that a file needs when I start
a project, and then end stopping when I look back at some file and notice that
it lacks require statements for half the stuff it needs.

~~~
anti-pattern
Yes, but, if you test your classes in isolation, then you'll be forced to
manually require each dependency at the top of the file.

~~~
mnarayan01
Stormbrew said pretty much everything I would
(<https://news.ycombinator.com/item?id=5370718>), but the one thing I would
add is that _most_ people are not going to keep their requires up-to-date for
all but the most stable projects. Once your requires start to get
stale/incomplete, they can easily become more of a liability than a benefit.

Again, I tend to agree with you more than I disagree. I think were I disagree
is in making it a recommendation -- if someone is on point enough to
effectively use Bundler.setup, I don't know that they need to have it
recommended to them; they just need to know the difference between
Bundler.setup and Bundler.require. On the other hand, if someone does need a
recommendation and not a description, I'm not sure that either is the
appropriate response.

I guess at the end of the day, I'm just not looking forward to the change-sets
this might generate ;)

------
Perceptes
Another thing to consider is thread safety. "require" is not thread safe, so
if your app is multi-threaded, it's actually a good idea to load everything up
front. Granted, you can still do this with manual requires, but
Bundler.require does that job for you pretty nicely.

~~~
anti-pattern
Ah, that isn't something I considered. I don't write my apps multi-threaded,
so it shouldn't be an issue, but definitely good to be aware of.

------
avand
If you subscribe to the philosophy that every line of code is a liability,
which I do, this really hits home.

~~~
anti-pattern
The best code is no code.

