Kill your dependencies vs. shoulda-matchers

I was just asked to evaluate the Gemfile of a project I’m working on using criteria laid out in this blog post:

I was asked specifically about should-matchers. Is the shoulda-matchers gem worth it? I think it scores pretty well by the criteria laid out in the post: it has only 1 dependency (activesupport, which is part of rails anyway). On the other hand, cloc says shoulda-matchers’ lib directory has 7391 lines of code, which seems insane. (For a comparison, cloc reports about 3800 lines for devise’s app and lib dirs combined, and devise does a lot more.)

Do I need to worry about counting lines of code when I consider including gems? Does the shoulda-matchers gem offer enough value to justify its size?

@jferris, can you explain why the gem is so big/why I shouldn’t be concerned about adding complexity by including this gem (only for tests, of course)?

I was just asked to evaluate the Gemfile of a project I’m working on

I think it’s good to think before adding a dependency, but I think it’s better to re-evaluate the features that caused a dependency to be introduced in the first place. If you want to kill complexity, it’s much better to simplify the problem in front of you than to try and reproduce the behavior provided by an external library.

External dependencies give developers the ability to solve a single problem very well in one place. When one developer finds a bug in something, many other developers can get the fix by updating their dependencies. If you cargo-cult or re-implement, you’ll inherit code and bugs you need to worry about on your own.

Is the shoulda-matchers gem worth it?

Using shoulda-matchers as an example: do you need to write unit tests for a Rails application? If so, you can use shoulda-matchers and take advantage of a battle-tested, widely-used approach for testing your associations, or you can roll your own assertions and relearn the lessons the many contributors to shoulda-matchers have learned through over the years. If you pull back too hard from dependencies, you’ll have to continually re-implement the same functionality in every library and application.

To use another example, Rails itself is almost certainly your largest dependency. Countless bugs and security vulnerabilities have been discovered in Rails (and its many dependencies!) over the years, and I’m sure you’re only using a fraction of its functionality. On the other hand, do you want to write your own database connection pooling? How about routing? How about protection from SQL injection attacks?

On the other hand, cloc says shoulda-matchers’ lib directory has 7391 lines of code, which seems insane. Do I need to worry about counting lines of code when I consider including gems?

I wouldn’t place much value in counting lines of code. I wrote about why in a blog post.

Can you explain why the gem is so big/why I shouldn’t be concerned about adding complexity by including this gem (only for tests, of course)?

Are you adding complexity by including this gem, or are you just using complexity that somebody else wrote instead of rewriting the complexity yourself? If you like the way shoulda-matchers solves your problem, I’d use it. If you don’t, I’d use something else or write something you think is better. If you do write something better, I’d publish it so that other developers can take advantage of it by declaring it as a dependency.

I would back up from original task of evaluating the Gemfile and figure out what your goals are. Are your Rails processes too large? Are your tests too slow? Are you finding a lot of bugs? Are you finding weird monkey patched methods that gunk up the works? There are tools to help you find solutions to each of these problems. For each problem you run into, I’d use those tools to figure out if one of your dependencies is causing it. If you don’t have any of these problems, I wouldn’t worry about your Gemfile.

Thanks @jferris for your detailed response! This was very helpful, as was the blog post you linked to.