Managing Ruby gems dependencies
This is a question that I sometimes get: Why don’t you use Bundler?
There are a lot of factors that went into that decision, but most importantly: Bundler is a very big dependency that solves a lot of problems that I don’t have, so I’ve always been tempted to explore other options and see if maybe there’s a smaller, simpler tool for the job.
Luckily, there’s a fantastic tool that does just that: dep.
The README of the project explains how that gem came to be, how it works, the workflow it defines and even compares it with Bundler a bit too. I strongly recommend you check it out and see if it adapts well to your own needs.
I figured this tool is worth sharing, not only because it’s such a useful addition to our stack, but also because it’s a clear example of a fundamental workflow that is usually taken for granted and we tend to jump to the most popular tool, even if our own use case is far from it’s scope.
Granted, dep
won’t solve all the problems that Bundler tackles, but then again
we’re not expecting it to do so. What we do expect it to solve, it solves
elegantly and efficiently.
Here’s how our usual workflow goes:
Let’s say that we want to add the ohm
gem to our project.
This will use a .gems
file in our repo to store dependencies, and if we look
at it now, we’ll see the following:
This is a simple list of gems with a specific version assigned to them, and
dep
provides simple commands for adding and removing gems to this file.
What about gem groups? simply use different files to list the dependencies of
each group. For example, let’s say we want a different group for testing gems,
then we can use dep
’s -f
option to specify the file we want, like so:
And that’s about it. Check it out and let us know what you think! You may find that the difference in your workflow doesn’t change significantly, but the weight of your dependencies does!
dep
is only 58 lines of code in total, while Bundler has more than 58 files,
each having more than 58 lines of code in average.
Why is that? The biggest difference is that Bundler not only lists dependencies, but also ensures that the gems you use are locked into the right version. For us, that’s a separate problem which we solve by always using gemsets in our projects, so we have no conflicting gem versions across projects. We’ll be writing a separate article about gemsets, but if you’re curious about what tool we use for that, check out gs which is a great place to start.
For some people this approach won’t be enough and they’ll benefit from some of bundler’s more obscure edge cases, but we believe that for most of us, that’s all it takes.
The conclusion that I want to leave you with, is to be mindful about the code that you bring into your projects. Are the libraries you’re adding relevant to your problem? Are they doing too much or too little? Are you comfortable with their code quality? Are they well tested and maintained?
These are basic questions that we ask ourselves all the time when evaluating gems, but then for the most important, fundamental workflows and needs, sometimes we ignore all of that.
Let’s eradicate this blindspot and critically think about every dependency that we add to our projects. Starting with our dependency manager, of course :-)