The original reason I thought using Bundler.require was better was just a variety of bad habits leftover from Rails. Over the years Rails has changed a lot in how it handles dependencies. Gems used to be manually required, then were automatically required via Bundler. Code in the app folder has always been automatically required, and up until relatively recently so was code in the lib folder. The general message was and still is pretty clear; Rails implicitly—if not explicitly—discourages manual requiring. Over time this led me to the erroneous conclusion that manually requiring dependencies was repetitious and unnecessary. Why do something manually that can be done automatically?

But as I’ve gotten better my opinion has shifted the other way. There are some huge benefits to using Bundler.setup to set up load paths for gems, adding application directories to the load paths, and then manually requiring dependencies wherever they are used in an application.

It provides amazing design feedback and documentation

Manually requiring dependencies at the top of every file very explicitly tells you and anyone else exactly what dependencies that file has. This makes code easier to read, understand, test, and refactor. It also makes it painfully obvious when a class is too complicated. If a class needs more than five require statements to work there’s probably too much going on in that class.

It forces you to think about your dependencies and the cost associated with using them

Dependencies aren’t free. Every dependency you have adds complexity and increases coupling. Automatically loading all dependencies makes them seem like they’re free and can be used whenever and wherever in your application. Having to manually require a dependency to use it forces you to justify its use and keeps your dependency list lean.

It makes removing dependencies easier

If you automatically load all your dependencies when you load your environment, you have no way of knowing what parts of your application are using any given dependency. You’d have to manually search for class names, method names, and other ways of identifying a dependency in order to update it or remove it, which is tedious and error-prone. If you manually require dependencies, you can just search for the require statement and remove or replace the dependency.

The big question at the heart of this all is what is your application? Is it one monolithic, tightly-coupled mess? Or is it a structured collection of small, loosely-coupled objects? Using Bundler.require will lead you towards the former, but using Bundler.setup will help ensure you make the latter.