This Time Self-Hosted
dark mode light mode Search

Lies, damn lies and dependencies (Yet Another Ruby Rant)

In the previous installment I have complained at how compass required a long list of OSX-specific dependencies, as well as Chrome and a (now dead) gem for reloading pages for its tests.

Well, let’s be honest: it doesn’t require them. It simply tells you it does.

The tests seem to run fine without Chrome, without livereload and most importantly without any of the Darwin-specific dependencies. So why are they still required? The answer lies in Bundler, the “nice” idea Ruby developers had to deal with dependencies.

While from one side Bundler is nice (disallows gems that you don’t enable from being loaded) it has caused all distributions quite a few headaches: not only older versions insisted in copying the content of the gem (even when coming from the system) into the project’s directory, but to work correctly, it expects all gems to provide correct gemspecs with their dependencies. You’d expect that to make them better, but that’s not always the case.

More than a few times the dependencies are set too strict (since Bundler is designed to allow relying on old and obsolete gems without clashing with newer gems requiring newer dependencies — which sounds good at first, until you understand that it might as well be a security issue), but much more commonly you have what I can only call “depend creep”.

Let’s take a step back and go back at the design of Bundler: given it seems to live in symbiosis with Rails 3, it makes sense for it to be able to specify dependencies only needed during development (webservers, logging and debug), or only during production (performance improvements) or testing (testing frameworks, mockers, and so on)… which is why it allows you to define “groups”, which you can disable when calling bundle

If it wasn’t the case that they still require you to install the dependencies! While excluding a particular group allows you to avoid loading the gems, Bundler still insists to make sure that there are no clashing dependency restriction between the various groups… which in turn means that you need to have the development and testing gems available in production as well. The documentation makes a point that the whole :platforms setting is also just an automated group handling, which means that Bundler will try to create the full dependency tree on Linux counting the Darwin and Windows gems as well, which definitely is not what we’re looking forward to.

Oh and it goes one step further: since Gems do not really have a way to explicit dependencies that are valid only for one Ruby implementation, and even if Gemfile has a way to do that, you still end up requiring gems in Ruby 1.9 (for instance) where they make no sense at all. And this brought us a number of “placeholder” gems, that when executed in Ruby 1.9 have no purpose at all.

This without counting the way the ruby-debug gem, that was already tricky due to the incompatibility between the original code and JRuby’s implementation, has now a sibling in ruby-debug19, a different gem that only works in 1.9 (why not maintain them together and simply build one or the other extension is still something I’m wondering).

In the case of compass the Gemfile was listing a number of dependencies that are used by the author during development and make no sense for us during package-testing; which means I don’t have to waste time with all of them, but just with part. Actually, almost all the dependencies are already in portage; I guess the one that is missing would be timecop — I have an ebuild for it, since I wrote it for some other gem before, but its tests fail consistently, and the last release being made over an year ago, with a lot of noise on the GitHub issues’ page, does not let me hope for the best. Honestly, though, even timecop seems to be unneeded, as I see it required but I don’t see its functions ever used.

I sure hope that most of the same is true for paperclip — I was finally able to package cocaine, since bourne was updated to mocha 0.10 (and yet it requires forcefully version 0.10.4 … which is not working under Ruby 1.9, for a regression which will be fixed in 0.10.5 — the ebuild hacks the version in the specification to make sure it does not complain as long as any 0.10 version is installed, for now), but now I’m looking forward the very long list of development dependencies, and wondering if I’ll ever be able to get it to work for me.

Now there is a good question: why am I not giving up? Because once it works, Radiant is a cool CMS; just like Typo is a cool blog engine in my opinion. I’m looking forward for Jim’s reduced dependencies (which he noted on the comments to my other post), but even as it is, it’s still the best web application for the task I could find. Would I be able to find something else? Maybe, but I’m not sure it would be the same. And even if Jim makes the clipped extension optional, I have no doubt I’ll be using it (and thus fighting with paperclip anyway): Radiant 1.0.0 is even better than the previous ones because it solves the problem with extensions’ compatibility…

Comments 4
  1. So you’re saying if you use `bundle install –without test development` it still installs the gems, it just doesn’t load them? For me, I am using capybara-webkit which requires qt to be installed, so I definitely don’t want full qt-dev in production. So in production, I use bundle install –without development test and it doesn’t even attempt to install it. Am I misunderstanding the issue?

  2. From Bundler’s website:Install all dependencies except those in groups that are explicitly excluded.$ bundle install –without development testThat being said, dependencies aren’t an easy animal to tame. Bundler definitely needs improvement, but has proven solid enough for my uses so far.

  3. That’s good if you use pure gems in which case it simply _downloads_ them. But when you’re using hybrid Gentoo-based packaging, you can’t rely on that, because you can’t tell it not to install anything (so that you can just get the list of missing dependencies and ask Portage to download them). End result is that you need to have the gems themselves installed.

  4. Bundler DOES NOT install dependencies from excluded groups. That’s simply not true. It DOES consider gems in all groups for the purposes of resolving dependencies consistently, but it does not install all of them. What would you propose Bundler do instead of this? Do you really want an entirely different dependency graph in development and production? I don’t think so.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.