To gem, or not to gem

Elle Meredith

…that is the question.
Whether ‘tis nobler in the mind to suffer
the slings and arrows of outrageous Gemfiles,
or to take arms against a sea of dependencies
and by opposing, end them.

Last year while mentoring an apprentice here at thoughtbot I was asked how I decide when to add a gem or not. That conversation was in particular about the decision to use Warden for authentication rather than Devise. Sometimes a similar question comes up in a pull request.

There is a school of programming that follows the principle that if software functionality can be provided by an external library, it should be. In Ruby’s case, those libraries are Ruby Gems. I view writing software as an active, thoughtful practice. Choosing libraries requires as much consideration as I devote to writing my own code.

On one of my first development jobs, I was asked by a more experienced developer why I added a gem for some simple functionality. From that developer, I learnt to examine gems more closely, to look at the code base and assess its quality; to look at its tests, how they are written and their coverage; and to critically assess how much functionality the new library adds and if that addition is worthwhile.

Let us expand on these ideas.

When deciding whether to add a new gem to an application I consider:

  • The scope of functionality that is to be added and how much effort will be needed. If it is a case of adding one simple module, then I will opt for writing it myself. If on the other hand, the requirements are more complex, including edge cases I might not consider, than I will probably opt for a gem.
  • The quality of the gem’s code. If the code base is full of code smells and complicated code that is not easily readable and understandable, then I will either try to find a better gem, or opt for writing the functionality myself. The same goes for test suite quality and coverage.
  • Adding another gem is adding liability for code I did not write, and which I do not maintain.
  • The more gems there are in Gemfile, the more libraries must to be loaded into memory and the slower the test suite will run.
  • I review the gem on places like the Ruby Toolbox, RubyGems, and Github to check for its up-to-date stats. I check if the gem is still maintained, when was the last time it was updated, how many open issues it has, are the maintainers responsive, and its support for different Ruby or Rails versions.
  • While on the topic of maintainers, I check the library’s licence, whether the maintainers are receptive to contributions, and look for a code of conduct as an indicator of whether they take contributions seriously.
  • I also ask myself if I like the gem’s DSL. For example, I have used quite a few different state machine gems over the years, and they all provide a very similar functionality. When asked which to choose, my answer is: the one with the DSL that works for you.

On the other hand, there are advantages to using gems, for example:

  • Existing knowledge. New developers on the project do not have to familiarize themselves with my code if they already know the gem.
  • Coverage of edge cases.
  • Quicker integration.

Devise is a good example of a fully featured authentication library. It gives you so much functionality out of the box, and in most cases I encountered, much of it was not needed. I often found I needed to customize some of its workflows, because it did not match the project’s requirements. This commonly happened in the views but I, more often than not, needed to overwrite Devise’s controllers in order to get the behavior the feature needs. In the last few years I opted to use plain Warden for authentication, or even Monban.

If we review smaller libraries, Paranoia for example is such a simple library I see no reason to add a gem. Instead I use a simple concern that I test with shared_examples. Another example of a simple gem is email_validation. Again a very simple gem, but one argument for possibly using it is that the regex it uses might cover more edge cases than the regex I wrote for my validator module.

There are gems I absolutely cannot be productive without. Each one I reach for, I review according to the guidelines above and consciously consider whether I need it. I ask you try the same.

Thanks to George Brocklehurst for the Shakespearean quote at the start of this post.