

Ruby's Bundler: As Simple as What You Did Before - wycats
http://yehudakatz.com/2010/09/30/bundler-as-simple-as-what-you-did-before/

======
tomstuart
It would've saved me a lot of time if I'd realised sooner that, as far as I
can tell, you can't use Bundler with the Rails 2.x gems if you need a Git
repository as the gem source (e.g. because you've forked them) because the
Rails 2.x repo contains multiple gems but has no gemspec explaining that.
[Although maybe adding a backported gemspec to the fork would work?]

Once I finally gave up trying to use Bundler to manage my forked Rails 2.x and
just left vendor/rails as a submodule, all the rest of the bundled gems worked
beautifully.

------
dasil003
I'm sure you've heard more than your share of complaints about every possible
flaw in Bundler, but are people really still complaining about it?

I had my issues with Bundler since trying out earliesh version of it last
year, and jumping on the early Rails 3 betas during the January bugmash and
intervening months. There were warts for sure, but the biggest one was the
pace of development and the outdatedness of the blog posts.

By now, however, it feels like all this complaining has put Bundler through a
kind of crucible that RubyGems never had. From my perspective Bundler 1.0.0 is
a pure joy to work with. The problems it solves were very real, and from where
I sit it solves them in a very thorough way. At the moment I'm contemplating
how to bring my 50k line 3-year-old Rails app up to Rails 3, and converting to
Bundler is the first step with immediate and significant benefits. I lump
Bundler in with efforts like RVM and Rubinius, as ambitious projects that are
pushing the state of Ruby forward and keeping it relevant in a world of
Clojures, Scalas and node.jses

~~~
FooBarWidget
I agree that Bundler is useful. However there are purists out there who see
the existence of Bundler as a flaw in Ruby or its community:
<http://news.ycombinator.com/item?id=1736726>

~~~
regularfry
Bundler is a worthwhile patch on rubygems itself, but from where I'm sitting
it's only needed because rubygems is flawed. It solves symptoms, not
underlying problems.

~~~
FooBarWidget
And what flaws are those? What are the underlying problems?

I find it interesting that most people who claim that RubyGems is flawed don't
state what the flaws are, or only give vague explanations and assume everybody
can read their minds.

About the only thing I can imagine is that the ability to simultaneously
activate multiple gems should be a feature in RubyGems itself rather than an
external feature.

~~~
regularfry
There are a few reasons given in the previous thread. In short, my complaints
are that language-specific package managers make life hellish for sysadmins
and end users, and that making it trivially easy to have more than one version
of a gem installed means that authors generally don't bother making it clear
when they introduce incompatibilities. This makes needing different versions
side-by-side inevitable, and again, that's tough on the sysadmin.

Bundler papers over this by putting each app in its own enclosure such that
it's at least possible to package a gem-using app atomically without requiring
too much effort on the author's part.

~~~
FooBarWidget
Let's address your main concern first. You see the ability to install multiple
versions of a gem as a flaw. Let's analyze this viewpoint in detail.

First a few axioms we must agree on:

1\. Libraries eventually have to break compatibility, otherwise progress is
impossible.

2\. There must be some way to deal with incompatibilities, either socially
(release and compatibility guarantee policies) or technically (package
managers).

Your point of view: social ways to deal with incompatibility are superior to
to technical ways to deal with incompatibility because the latter encourages
developers to be lazy about compatibility guarantees.

I have a few objections about that point of view.

1\. It assumes a perfect world.

Although it doesn't happen often, an app can break due to reliance on library
bugs or unformalized/undocumented behavior/internals. Sometimes a newer
version of a library has a regression that isn't found until it's released.

Yes we all know things like these ideally shouldn't happen, but they do. Is it
a good idea to ignore the reality that things like this happen from time to
time?

According to the logic that supports your point of view, we should abolish
protected memory as well. Protected memory allows programmers to write apps
that don't bring down the entire OS when they crash... it makes programmers
lazy!!

2\. It assumes that DPKG/RPM don't make life hellish for sysadmin and end
users.

For the most part, DPKG/RPM works fine. For Ruby stuff, not so much. Suppose
there's an app called frobnicator, and it works on foobar 1.0.x but not on
foobar 1.2.x. Thanks to the fact that DPKG/RPM only supports installation of
single versions, your distro can only package foobar 1.2.x but not 1.0.x. Now
the user cannot use frobnicator at all because you insist on DPKG/RPM. How
exactly is this better for the end user?

~~~
FooBarWidget
Oh and this.

3\. It inherently excludes some valid compatibility cases, unless the
developer is forced to hack around the package manager

Suppose 'foo' depends on 'bar'. bar consists of features A, B and C.
Furthermore bar has made the guarantee that it will never break the
compatibility of feature 'A', ever. It also has a compatibility policy that
states it will increment its major version number every time it breaks B and
C.

foo only uses feature A in bar, so we know that foo is compatible with every
version bar that will ever be released.

foo also depends on 'libcat'. libcat depends on bar, but uses all its
features. The current release of bar is 1.0.0, so we know libcat depends on
1.0.0 <= bar < 2.0.0.

Suppose that 'frobnicator' depends on bar. It uses feature B and it uses the
interface provided by bar 2.x.

This seems like a completely reasonable case. Developers aren't being lazy
about compatibility guarantees here. The only way to solve this problem is by
versioning bar on the filesystem level. That is, while bar 1.x requires
developer to type

    
    
      require 'bar/feature_a'
      require 'bar/feature_b'
    

bar 2.x requires the developer to type

    
    
      require 'bar-2/feature_a'
      require 'bar-2/feature_b'
    

_You have to rename the entire library directory._ In my opinion this is an
ugly hack around the fact that your package manager doesn't support multiple
versions. I think this is solved much more elegantly if the package manager
allows you to switch the version on-the-fly... in other words, what RubyGems
does.

~~~
regularfry
This is one case that rubygems handles well, but I think your specific example
is broken. If libcat requires 1.0.0 <= bar < 2.0.0, foo requires libcat, foo
requires 2.0.0 < bar, you've got conflicting requirements - foo requires both
bar < 2.0.0 and 2.0.0 < bar. Rubygems will barf at that.

> You have to rename the entire library directory. In my opinion this is an
> ugly hack around the fact that your package manager doesn't support multiple
> versions. I think this is solved much more elegantly if the package manager
> allows you to switch the version on-the-fly... in other words, what RubyGems
> does.

It may be an ugly hack, but it's fairly traditional at this point.

~~~
FooBarWidget
> Rubygems will barf at that.

Only if you activate gems linearly. Bundler solves exactly this: it looks at
all dependencies then figures out a combination that works. Bundler will only
activate bar 1.x because it sees that foo is compatible with all versions but
libcat is only compatible with 1.x.

> It may be an ugly hack, but it's fairly traditional at this point.

I argue against the notion that being traditional here equals being good.
There's no good reason why the developer should do this manually instead of
having some system do it for him.

RubyGems actually implicitly does this. By installing each gem to its own
directory it separates the versions on the filesystem level.

~~~
regularfry
> Only if you activate gems linearly. Bundler solves exactly this: it looks at
> all dependencies then figures out a combination that works. Bundler will
> only activate bar 1.x because it sees that foo is compatible with all
> versions but libcat is only compatible with 1.x.

You're absolutely right, I misread your example.

> I argue against the notion that being traditional here equals being good.
> There's no good reason why the developer should do this manually instead of
> having some system do it for him.

It's a trade-off. Either the developer has to do it manually (once, which will
then work with every sane distro), or the sysadmin has extra work to do (many
times, once for each language-specific package manager).

In an ideal world, the language communities would gang up on Debian and Red
Hat and improve dpkg and rpm to make this issue go away. I don't see this
happening.

