---
title: To gem, or not to gem
teaser: |
  Writing software is an active, thoughtful practice.
  Choosing gems requires as much consideration as writing code.
tags: rails,web
author: Elle Meredith
published_on: 2016-02-19
---

> ...that is the question.<br />
  Whether 'tis nobler in the mind to suffer<br />
  the slings and arrows of outrageous Gemfiles,<br />
  or to take arms against a sea of dependencies<br />
  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.

[apprentice]: http://www.apprentice.io/
[Warden]: https://github.com/hassox/warden
[Devise]: https://github.com/plataformatec/devise

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.

[Ruby Toolbox]: https://www.ruby-toolbox.com/
[RubyGems]: https://rubygems.org/
[Github]: https://github.com/

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].

[Monban]: https://github.com/halogenandtoast/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_example`s.
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.

[Paranoia]: https://github.com/rubysherpas/paranoia
[email_validation]: https://github.com/RISCfuture/email_validation

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.

[George Brocklehurst]: https://twitter.com/georgebrock
